{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Plugins and Extensions" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "import typing\n", "\n", "import matplotlib.pyplot as plt\n", "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you've already read the [Broad Overview](../broad_overview.html), you'll know that `hmf` is extremely flexible, and is defined by a number of `Component` parts, that come together in `Framework` objects.\n", "\n", "In this notebook, we'll look at these a bit more closely and show how to define your own." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Built-in Models" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In `hmf`, we call each kind of calculation a `Component`. For example, the hmf `FittingFunction` is a `Component`, and so is the `Cosmology`. In fact, most of the functionality is defined in one of these components. Each particular implementation of a `Component` is a `Model` -- so, eg. the `SMT` fitting function is a model, and so is the `PS`. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Components are based on a simple plugin architecture, so that each base component knows about all its models. Let's see this in a few examples:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "from hmf import MassFunction\n", "from hmf.halos import MassDefinition\n", "from hmf.mass_function import PS, FittingFunction" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To determine all the implemented models for a particular component, use `get_models()`:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'PS': hmf.mass_function.fitting_functions.PS,\n", " 'SMT': hmf.mass_function.fitting_functions.SMT,\n", " 'ST': hmf.mass_function.fitting_functions.ST,\n", " 'Jenkins': hmf.mass_function.fitting_functions.Jenkins,\n", " 'Warren': hmf.mass_function.fitting_functions.Warren,\n", " 'Reed03': hmf.mass_function.fitting_functions.Reed03,\n", " 'Reed07': hmf.mass_function.fitting_functions.Reed07,\n", " 'Peacock': hmf.mass_function.fitting_functions.Peacock,\n", " 'Angulo': hmf.mass_function.fitting_functions.Angulo,\n", " 'AnguloBound': hmf.mass_function.fitting_functions.AnguloBound,\n", " 'Watson_FoF': hmf.mass_function.fitting_functions.Watson_FoF,\n", " 'Watson': hmf.mass_function.fitting_functions.Watson,\n", " 'Crocce': hmf.mass_function.fitting_functions.Crocce,\n", " 'Courtin': hmf.mass_function.fitting_functions.Courtin,\n", " 'Bhattacharya': hmf.mass_function.fitting_functions.Bhattacharya,\n", " 'Tinker08': hmf.mass_function.fitting_functions.Tinker08,\n", " 'Tinker10': hmf.mass_function.fitting_functions.Tinker10,\n", " 'Behroozi': hmf.mass_function.fitting_functions.Behroozi,\n", " 'Pillepich': hmf.mass_function.fitting_functions.Pillepich,\n", " 'Manera': hmf.mass_function.fitting_functions.Manera,\n", " 'Ishiyama': hmf.mass_function.fitting_functions.Ishiyama}" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "FittingFunction.get_models()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'SphericalOverdensity': hmf.halos.mass_definitions.SphericalOverdensity,\n", " 'SOGeneric': hmf.halos.mass_definitions.SOGeneric,\n", " 'SOMean': hmf.halos.mass_definitions.SOMean,\n", " 'SOCritical': hmf.halos.mass_definitions.SOCritical,\n", " 'SOVirial': hmf.halos.mass_definitions.SOVirial,\n", " 'FOF': hmf.halos.mass_definitions.FOF}" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "MassDefinition.get_models()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Any of the listed models can be used (as a string, or a class) when constructing a `Framework`, and it will be automatically converted to an actual class:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "mf = MassFunction(hmf_model=\"Behroozi\")" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "hmf.mass_function.fitting_functions.Behroozi" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mf.hmf_model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Also, you can get at those models from any model:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'PS': hmf.mass_function.fitting_functions.PS,\n", " 'SMT': hmf.mass_function.fitting_functions.SMT,\n", " 'ST': hmf.mass_function.fitting_functions.ST,\n", " 'Jenkins': hmf.mass_function.fitting_functions.Jenkins,\n", " 'Warren': hmf.mass_function.fitting_functions.Warren,\n", " 'Reed03': hmf.mass_function.fitting_functions.Reed03,\n", " 'Reed07': hmf.mass_function.fitting_functions.Reed07,\n", " 'Peacock': hmf.mass_function.fitting_functions.Peacock,\n", " 'Angulo': hmf.mass_function.fitting_functions.Angulo,\n", " 'AnguloBound': hmf.mass_function.fitting_functions.AnguloBound,\n", " 'Watson_FoF': hmf.mass_function.fitting_functions.Watson_FoF,\n", " 'Watson': hmf.mass_function.fitting_functions.Watson,\n", " 'Crocce': hmf.mass_function.fitting_functions.Crocce,\n", " 'Courtin': hmf.mass_function.fitting_functions.Courtin,\n", " 'Bhattacharya': hmf.mass_function.fitting_functions.Bhattacharya,\n", " 'Tinker08': hmf.mass_function.fitting_functions.Tinker08,\n", " 'Tinker10': hmf.mass_function.fitting_functions.Tinker10,\n", " 'Behroozi': hmf.mass_function.fitting_functions.Behroozi,\n", " 'Pillepich': hmf.mass_function.fitting_functions.Pillepich,\n", " 'Manera': hmf.mass_function.fitting_functions.Manera,\n", " 'Ishiyama': hmf.mass_function.fitting_functions.Ishiyama,\n", " 'MyNewFit': __main__.MyNewFit}" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "PS.get_models()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Also note, we haven't actually \"constructed\" the SMT fitting function here, we're just using it as a bare class." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Defining your own Models" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As long as you follow the prescribed interface, you can define your own model for any `Component`. The interface for each component is different, by necessity, and you can find information about what the interface is by looking at the documentation for the base component. In the case of fitting functions, that's `FittingFunction`. In this case, we can just define one method to create our own fit. \n", "\n", "Let's create a mass function very similar to the Press-Schechter form, but with an exponent that is not $\\nu^2/2$, but instead $0.4 \\nu^2$:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "class MyNewFit(FittingFunction):\n", " @property\n", " def fsigma(self):\n", " return np.sqrt(2.0 / np.pi) * self.nu * np.exp(-0.4 * self.nu2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can immediately use this new model in a `Framework`:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Text(0, 0.5, 'dndm')" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "mf = MassFunction(hmf_model=MyNewFit, transfer_model=\"EH\")\n", "plt.plot(mf.m, mf.dndm)\n", "\n", "mf.hmf_model = PS\n", "plt.plot(mf.m, mf.dndm)\n", "plt.xscale(\"log\")\n", "plt.yscale(\"log\")\n", "plt.xlabel(\"Mass\")\n", "plt.ylabel(\"dndm\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It's clear that our new function doesn't drop off at high masses quite so fast." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Parameterizing Custom Models" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Imagine that we doubt that the cutoff should be proportional to $0.5 \\nu^2$, and want to parameterize it as $a \\nu^2$, and fit that free parameter $a$ to our simulated data. Any `Component` may be parameterized by writing a `_defaults` dictionary:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class MyNewFitParameterized(FittingFunction):\n", " _defaults: typing.ClassVar = {\"a\": 0.5}\n", "\n", " @property\n", " def fsigma(self):\n", " return np.sqrt(2.0 / np.pi) * self.nu * np.exp(-self.params[\"a\"] * self.nu2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that to access the actual user-supplied value of $a$, we use the `self.params` dictionary. The `_defaults` dictionary only specifies the default values." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Constructing a model, we can use the `hmf_params` to set $a$:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "mf = MassFunction(hmf_model=MyNewFitParameterized, hmf_params={\"a\": 0.55}, transfer_model=\"EH\")" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Text(0, 0.5, 'dndm')" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "for a in np.arange(0.4, 0.6, 0.02):\n", " mf.hmf_params = {\"a\": a}\n", "\n", " plt.plot(mf.m, mf.dndm)\n", "\n", "plt.xscale(\"log\")\n", "plt.yscale(\"log\")\n", "plt.xlabel(\"Mass\")\n", "plt.ylabel(\"dndm\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Your Custom Model is a Plugin" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Due to the generic way that the plugin architecture is implemented, your custom models also appear as plugins:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'PS': hmf.mass_function.fitting_functions.PS,\n", " 'SMT': hmf.mass_function.fitting_functions.SMT,\n", " 'ST': hmf.mass_function.fitting_functions.ST,\n", " 'Jenkins': hmf.mass_function.fitting_functions.Jenkins,\n", " 'Warren': hmf.mass_function.fitting_functions.Warren,\n", " 'Reed03': hmf.mass_function.fitting_functions.Reed03,\n", " 'Reed07': hmf.mass_function.fitting_functions.Reed07,\n", " 'Peacock': hmf.mass_function.fitting_functions.Peacock,\n", " 'Angulo': hmf.mass_function.fitting_functions.Angulo,\n", " 'AnguloBound': hmf.mass_function.fitting_functions.AnguloBound,\n", " 'Watson_FoF': hmf.mass_function.fitting_functions.Watson_FoF,\n", " 'Watson': hmf.mass_function.fitting_functions.Watson,\n", " 'Crocce': hmf.mass_function.fitting_functions.Crocce,\n", " 'Courtin': hmf.mass_function.fitting_functions.Courtin,\n", " 'Bhattacharya': hmf.mass_function.fitting_functions.Bhattacharya,\n", " 'Tinker08': hmf.mass_function.fitting_functions.Tinker08,\n", " 'Tinker10': hmf.mass_function.fitting_functions.Tinker10,\n", " 'Behroozi': hmf.mass_function.fitting_functions.Behroozi,\n", " 'Pillepich': hmf.mass_function.fitting_functions.Pillepich,\n", " 'Manera': hmf.mass_function.fitting_functions.Manera,\n", " 'Ishiyama': hmf.mass_function.fitting_functions.Ishiyama,\n", " 'MyNewFit': __main__.MyNewFit,\n", " 'MyNewFitParameterized': __main__.MyNewFitParameterized}" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "FittingFunction.get_models()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This means we can construct the `Framework` using string names of the models:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "mf = MassFunction(hmf_model=\"MyNewFit\")" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "__main__.MyNewFit" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mf.hmf_model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is particularly useful for dynamically creating frameworks from a library of custom classes, or specifying models in YAML/TOML configuration files." ] } ], "metadata": { "kernelspec": { "display_name": "Python [conda env:hmf]", "language": "python", "name": "conda-env-hmf-py" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.0" } }, "nbformat": 4, "nbformat_minor": 4 }