{ "cells": [ { "cell_type": "markdown", "id": "f8d24115", "metadata": {}, "source": [ "# Defining Simulation Inputs" ] }, { "cell_type": "markdown", "id": "4842fde1", "metadata": {}, "source": [ "In this tutorial, we'll cover how to setup your simulation by defining the basic simulation and physical parameters. " ] }, { "cell_type": "code", "execution_count": 26, "id": "073e7dd3", "metadata": {}, "outputs": [], "source": [ "import py21cmfast as p21c\n", "from tempfile import mkdtemp\n", "from pathlib import Path" ] }, { "cell_type": "code", "execution_count": 3, "id": "e3834fd0", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Using 21cmFAST version 4.0.0b1.dev312+gb6f5204f.d20250728\n" ] } ], "source": [ "print(f' Using 21cmFAST version {p21c.__version__}')" ] }, { "cell_type": "markdown", "id": "72f690bc", "metadata": {}, "source": [ "## The `InputParameters` Class and Parameter Subgroups" ] }, { "cell_type": "markdown", "id": "0d3000b9", "metadata": {}, "source": [ "All the parameters that `21cmFAST` uses are stored in the `InputParameters` class. This class handles the validation of the set of parameters you specify (in case there are conflicts between parameters), and also gives you a few ways to setup the parameters.\n", "\n", "The easiest way is to use all defaults:" ] }, { "cell_type": "code", "execution_count": 4, "id": "097661b4", "metadata": {}, "outputs": [], "source": [ "inputs = p21c.InputParameters(random_seed=1234)" ] }, { "cell_type": "markdown", "id": "cc225fc7", "metadata": {}, "source": [ "
\n", "\n", "Note\n", "\n", "Why do we require you to specify the random seed explicitly? Because doing so minimizes\n", "surprises. `21cmFAST` attempts to cache results, and can therefore\n", "return the same simulation when the same parameters are given. This is sometimes \n", "surprising, if you were trying to generate multiple realizations of simulations with the \n", "same parameters. Always explicitly specifying the seed requires *you* to take control\n", "of this behavior.\n", "\n", "
" ] }, { "cell_type": "markdown", "id": "e74bf741", "metadata": {}, "source": [ "You will see that within the `InputParameters` object, the actual parameters are divvied up into multiple sub-categories:" ] }, { "cell_type": "code", "execution_count": 5, "id": "f35b07c7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "cosmo_params: CosmoParams(SIGMA_8=0.8102, hlittle=0.6766, OMm=0.30964144154550644, OMb=0.04897468161869667, POWER_INDEX=0.9665, OMn=0.0, OMk=0.0, OMr=8.6e-05, OMtot=1.0, Y_He=0.24, wl=-1.0)\n", "simulation_options: SimulationOptions(HII_DIM=256, _BOX_LEN=None, _DIM=None, _HIRES_TO_LOWRES_FACTOR=None, _LOWRES_CELL_SIZE_MPC=None, NON_CUBIC_FACTOR=1.0, N_THREADS=1, SAMPLER_MIN_MASS=100000000.0, SAMPLER_BUFFER_FACTOR=2.0, N_COND_INTERP=200, N_PROB_INTERP=400, MIN_LOGPROB=-12.0, HALOMASS_CORRECTION=0.89, PARKINSON_G0=1.0, PARKINSON_y1=0.0, PARKINSON_y2=0.0, Z_HEAT_MAX=35.0, ZPRIME_STEP_FACTOR=1.02, INITIAL_REDSHIFT=300.0, DELTA_R_FACTOR=1.1, DENSITY_SMOOTH_RADIUS=0.2, DEXM_OPTIMIZE_MINMASS=100000000000.0, DEXM_R_OVERLAP=2.0, CORR_STAR=0.5, CORR_SFR=0.2, CORR_LX=0.2)\n", "matter_options: MatterOptions(HMF='ST', USE_RELATIVE_VELOCITIES=False, POWER_SPECTRUM='EH', PERTURB_ON_HIGH_RES=False, USE_INTERPOLATION_TABLES='hmf-interpolation', MINIMIZE_MEMORY=False, KEEP_3D_VELOCITIES=False, SAMPLE_METHOD='MASS-LIMITED', FILTER='spherical-tophat', HALO_FILTER='spherical-tophat', SMOOTH_EVOLVED_DENSITY_FIELD=False, DEXM_OPTIMIZE=False, PERTURB_ALGORITHM='2LPT', USE_FFTW_WISDOM=False, USE_HALO_FIELD=True, FIXED_HALO_GRIDS=False, HALO_STOCHASTICITY=True)\n", "astro_params: AstroParams(HII_EFF_FACTOR=30.0, F_STAR10=-1.3, ALPHA_STAR=0.5, F_STAR7_MINI=-2.8, ALPHA_STAR_MINI=0.5, F_ESC10=-1.0, ALPHA_ESC=-0.5, F_ESC7_MINI=-2.0, M_TURN=8.7, R_BUBBLE_MAX=15.0, R_BUBBLE_MIN=0.620350491, ION_Tvir_MIN=4.69897, L_X=40.5, L_X_MINI=40.5, NU_X_THRESH=500.0, X_RAY_SPEC_INDEX=1.0, X_RAY_Tvir_MIN=4.69897, F_H2_SHIELD=0.0, t_STAR=0.5, A_LW=2.0, BETA_LW=0.6, A_VCB=1.0, BETA_VCB=1.8, UPPER_STELLAR_TURNOVER_MASS=11.447, UPPER_STELLAR_TURNOVER_INDEX=-0.6, SIGMA_STAR=0.25, SIGMA_LX=0.5, SIGMA_SFR_LIM=0.19, SIGMA_SFR_INDEX=-0.12, T_RE=20000.0, FIXED_VAVG=25.86, POP2_ION=5000.0, POP3_ION=44021.0, PHOTONCONS_CALIBRATION_END=3.5, CLUMPING_FACTOR=2.0, ALPHA_UVB=5.0, R_MAX_TS=500.0, N_STEP_TS=40, MAX_DVDR=0.2, DELTA_R_HII_FACTOR=1.1, NU_X_BAND_MAX=2000.0, NU_X_MAX=10000.0)\n", "astro_options: AstroOptions(USE_MINI_HALOS=False, USE_CMB_HEATING=True, USE_LYA_HEATING=True, USE_MASS_DEPENDENT_ZETA=True, INHOMO_RECO=False, USE_TS_FLUCT=False, FIX_VCB_AVG=False, USE_EXP_FILTER=True, CELL_RECOMB=True, PHOTON_CONS_TYPE='no-photoncons', USE_UPPER_STELLAR_TURNOVER=True, M_MIN_in_Mass=True, HALO_SCALING_RELATIONS_MEDIAN=False, HII_FILTER='spherical-tophat', HEAT_FILTER='spherical-tophat', IONISE_ENTIRE_SPHERE=False, AVG_BELOW_SAMPLER=True, INTEGRATION_METHOD_ATOMIC='GAUSS-LEGENDRE', INTEGRATION_METHOD_MINI='GAUSS-LEGENDRE')\n", "\n" ] } ], "source": [ "print(inputs)" ] }, { "cell_type": "markdown", "id": "a9ac4070", "metadata": {}, "source": [ "These five categories (`CosmoParams`, `SimulationOptions`, `MatterOptions`, `AstroParams` and `AstroOptions`) come in two types: *options* and *params*. Here *options* refers to choices that affect how the simulation is run, for exapmle the size of the grid, or whether to run with certain physical models. These are generally integers or booleans (though they can be floats as well sometimes). On the other hand, *params* specify physical parameters of the simulation, for instance cosmological parameters like $\\sigma_8$, or astrophysical parameters like $f_{\\rm esc}$. " ] }, { "cell_type": "markdown", "id": "b6bf0582", "metadata": {}, "source": [ "The reason we break them into these groups---besides the conceptual benefit---is that it is then easier to identify parameters that might be constrained by data (via MCMC for example)." ] }, { "cell_type": "markdown", "id": "22bcaa1d", "metadata": {}, "source": [ "Within a type, the different parameter groups (e.g. `SimulationOptions`, `MatterOptions` and `AstroOptions`) affect different stages of the simulation, and are broken up to enable better caching." ] }, { "cell_type": "markdown", "id": "0c7510ee", "metadata": {}, "source": [ "## Manually Specifying Parameters" ] }, { "cell_type": "markdown", "id": "5c88b071", "metadata": {}, "source": [ "One way to specify an `InputParameters` class is to build it from individual subgroups. For example:" ] }, { "cell_type": "code", "execution_count": 6, "id": "48b413b5", "metadata": {}, "outputs": [], "source": [ "inputs = p21c.InputParameters(\n", " cosmo_params = p21c.CosmoParams(SIGMA_8=0.6),\n", " astro_options = p21c.AstroOptions(USE_TS_FLUCT=True),\n", " random_seed=1234\n", ")" ] }, { "cell_type": "markdown", "id": "dfbf867f", "metadata": {}, "source": [ "In this case, any subgroup that is not specified will be filled with all default parameters (see [the API reference](../reference/_autosummary/py21cmfast.wrapper.inputs.html) to check what these are).\n", "\n", "Furthermore, any parameter within any subgroup that is not specified will receive its default. " ] }, { "cell_type": "markdown", "id": "b27b9fff", "metadata": {}, "source": [ "
\n", "\n", "Warning\n", "\n", "Specifying some parameters as non-default values without explicitly changing other parameters can result in validation errors. `21cmFAST` doesn't generally provide dynamic defaults because there are too many situations to cover and too many surprises for you. Instead, it will raise exceptions and inform you how to fix your inputs. This can be made easier by using templates. Read on!\n", "\n", "
" ] }, { "cell_type": "markdown", "id": "27593ec5", "metadata": {}, "source": [ "## Evolving Existing Parameters" ] }, { "cell_type": "markdown", "id": "1d96e5e8", "metadata": {}, "source": [ "In some cases, you have an existing set of parameters (for instance, you may have read\n", "the input parameters from an existing simulation file) and you want to create a new\n", "set of parameters based on these parameters. In this case you **cannot** update the \n", "existing parameters in-place:" ] }, { "cell_type": "code", "execution_count": 7, "id": "580e2dfc", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "try:\n", " inputs.simulation_options.SIGMA_8 = 0.9\n", "except Exception as e:\n", " print(type(e))" ] }, { "cell_type": "markdown", "id": "c7b234f5", "metadata": {}, "source": [ "This highlights a key point of the `InputParameters` class: it is immutable. Once you\n", "have your parameters, you can be confident that they're not going to be secretly \n", "modified under the hood. \n", "\n", "Instead, you can use one set of parameters to define a new set, like so:" ] }, { "cell_type": "code", "execution_count": 8, "id": "add057c5", "metadata": {}, "outputs": [], "source": [ "new_inputs = inputs.evolve_input_structs(SIGMA_8=0.9)" ] }, { "cell_type": "code", "execution_count": 9, "id": "7ccad178", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "New Sigma_8: 0.9\n", "Original Sigma_8: 0.6\n" ] } ], "source": [ "print(\"New Sigma_8: \", new_inputs.cosmo_params.SIGMA_8)\n", "print(\"Original Sigma_8: \", inputs.cosmo_params.SIGMA_8)" ] }, { "cell_type": "markdown", "id": "900cc8e9", "metadata": {}, "source": [ "Note that the `evolve_input_structs` method directly accepts parameters from any of the\n", "subgroups, without having to specify which subgroup it comes from. If you would instead\n", "prefer to update an entire subgroup at a time, use the `.clone()` method:" ] }, { "cell_type": "code", "execution_count": 10, "id": "7b6093c7", "metadata": {}, "outputs": [], "source": [ "new = inputs.clone(cosmo_params=p21c.CosmoParams(hlittle=0.9))" ] }, { "cell_type": "markdown", "id": "6db8d585", "metadata": {}, "source": [ "## Using Templates" ] }, { "cell_type": "markdown", "id": "3e8b5f86", "metadata": {}, "source": [ "The recommended way to specify your parameters is by starting from a built-in *template*.\n", "The reason for this is that there are many \"modes\" in which to run 21cmFAST (and the\n", "number grows over time), and each mode may require several parameters to be specified.\n", "Instead of having to know and remember the full set of interlocking parameters, we \n", "provide templates that give you the basics, upon which you can build.\n", "\n", "To build from a template, simply use the `.from_template` constructor method:" ] }, { "cell_type": "code", "execution_count": 11, "id": "a6b709d5", "metadata": {}, "outputs": [], "source": [ "inputs = p21c.InputParameters.from_template(\"Park19\", random_seed=1)" ] }, { "cell_type": "code", "execution_count": 12, "id": "6005856e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "AstroOptions:AVG_BELOW_SAMPLER : True\n", " CELL_RECOMB : False\n", " FIX_VCB_AVG : False\n", " HALO_SCALING_RELATIONS_MEDIAN: False\n", " HEAT_FILTER : spherical-tophat\n", " HII_FILTER : sharp-k\n", " INHOMO_RECO : True\n", " INTEGRATION_METHOD_ATOMIC : GAUSS-LEGENDRE\n", " INTEGRATION_METHOD_MINI : GAUSS-LEGENDRE\n", " IONISE_ENTIRE_SPHERE : False\n", " M_MIN_in_Mass : True\n", " PHOTON_CONS_TYPE : no-photoncons\n", " USE_CMB_HEATING : False\n", " USE_EXP_FILTER : False\n", " USE_LYA_HEATING : False\n", " USE_MASS_DEPENDENT_ZETA : True\n", " USE_MINI_HALOS : False\n", " USE_TS_FLUCT : True\n", " USE_UPPER_STELLAR_TURNOVER : False \n" ] } ], "source": [ "print(inputs.astro_options)" ] }, { "cell_type": "markdown", "id": "20e56a9b", "metadata": {}, "source": [ "You can overwrite specific parameters by passing them to the constructor:" ] }, { "cell_type": "code", "execution_count": null, "id": "ac0fbbab", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/data4/smurray/miniforge3/envs/21cmfast/lib/python3.11/site-packages/attr/_make.py:3040: UserWarning: USE_MINI_HALOS needs USE_RELATIVE_VELOCITIES to get the right evolution!\n", " v(inst, attr, value)\n", "/data4/smurray/miniforge3/envs/21cmfast/lib/python3.11/site-packages/attr/_make.py:3040: UserWarning: You are setting M_TURN > 8 when USE_MINI_HALOS=True. This is non-standard (but allowed), and usually occurs upon manual update of M_TURN\n", " v(inst, attr, value)\n" ] } ], "source": [ "inputs = p21c.InputParameters.from_template(\n", " \"Park19\", USE_MINI_HALOS=True, random_seed=1\n", ")" ] }, { "cell_type": "markdown", "id": "72a647a9", "metadata": {}, "source": [ "As you can see, overwriting this particular option -- `USE_MINI_HALOS` -- on its own\n", "has generated some warnings, because in fact a model using mini-halos requires other\n", "options to be set in order to be accurate. This is an example of why building from a\n", "template is easier. We could have used the `EOS21` template, which instantiates the\n", "basic model presented in https://arxiv.org/abs/2110.13919, which includes molecularly-cooled\n", "galaxies that form in mini-halos:" ] }, { "cell_type": "code", "execution_count": 14, "id": "c23e60e6", "metadata": {}, "outputs": [], "source": [ "inputs = p21c.InputParameters.from_template(\"EOS21\", random_seed=1)" ] }, { "cell_type": "code", "execution_count": 15, "id": "3f09309f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "EOS21 uses minihalos? True\n" ] } ], "source": [ "print(\"EOS21 uses minihalos?\", inputs.astro_options.USE_MINI_HALOS)" ] }, { "cell_type": "markdown", "id": "8de736d7", "metadata": {}, "source": [ "### Stacking Multiple Templates" ] }, { "cell_type": "markdown", "id": "acc519f3", "metadata": {}, "source": [ "Most built-in templates instantiate a \"mode\" of running 21cmFAST -- some set of options\n", "that define the physical models that are used in the simulation -- often representing\n", "a specific publication or publicly available simulation.\n", "\n", "However, another use-case of templates is to quickly set a \"size\" of your simulation. \n", "Often you want to switch between something very small for testing, and something larger\n", "when want to produce scientific results. To make this easier, `21cmFAST` allows you to \n", "stack templates, and provides several built-in templates that only modify simulation \n", "size. \n", "\n", "For example:" ] }, { "cell_type": "code", "execution_count": 16, "id": "fb78190c", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/data4/smurray/miniforge3/envs/21cmfast/lib/python3.11/site-packages/attr/_make.py:3040: UserWarning: You are setting R_BUBBLE_MAX != 50 when INHOMO_RECO=True. This is non-standard (but allowed), and usually occurs upon manual update of INHOMO_RECO\n", " v(inst, attr, value)\n" ] } ], "source": [ "inputs_small = p21c.InputParameters.from_template(['EOS21', 'small'], random_seed=1)\n", "inputs_large = p21c.InputParameters.from_template(['EOS21', 'gpc'], random_seed=1)" ] }, { "cell_type": "markdown", "id": "f6d88fcc", "metadata": {}, "source": [ "Here, the \"small\" template combined with EOS21 emits a warning, because the box is too\n", "small to set `R_BUBBLE_MAX` to 50. That is ostensibly OK because this box would only be\n", "used for testing anyway." ] }, { "cell_type": "markdown", "id": "39b69367", "metadata": {}, "source": [ "### Listing Available Templates" ] }, { "cell_type": "markdown", "id": "3e14fb4d", "metadata": {}, "source": [ "So, what templates are available to you as builtins? You can print a list of available \n", "templates most easily from the CLI interface:" ] }, { "cell_type": "code", "execution_count": 17, "id": "d13f6403", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[1;35mdefaults\u001b[0m \u001b[35m | default\u001b[0m\n", " All the default parameters of 21cmFAST.\n", "\u001b[1;35msimple\u001b[0m \n", " A simple 21cmFAST run with no minihalos, discrete halos, recombinations \n", "or spin temperature fluctuations\n", "\u001b[1;35mconst-zeta\u001b[0m \n", " A 21cmFAST run with constant ionising efficiency for halos of all mass\n", "\u001b[1;35mlatest\u001b[0m \n", " Our latest fiducial run without discrete halos, includes recominations \n", "and spin temperature fluctuations\n", "\u001b[1;35mminihalos\u001b[0m \u001b[35m | mini\u001b[0m\n", " A run including minihalos\n", "\u001b[1;35mlatest-discrete\u001b[0m \u001b[35m | latest-dhalos\u001b[0m\n", " Our latest fiducial run with discrete halos, recominations and spin \n", "temperature fluctuations\n", "\u001b[1;35mminihalos-discrete\u001b[0m \u001b[35m | mini-dhalos\u001b[0m\n", " Run with discrete halos, including the molecularly cooled galaxy \n", "component\n", "\u001b[1;35mPark19\u001b[0m \n", " Exact fiducial parameters from Park et al \u001b[1;36m2019\u001b[0m. Disables modules \n", "implemented afterwards\n", "\u001b[1;35mQin20\u001b[0m \n", " Exact fiducial parameters from Qin et al \u001b[1;36m2020\u001b[0m. Disables modules \n", "implemented afterwards\n", "\u001b[1;35mMunoz21\u001b[0m \u001b[35m | EOS21\u001b[0m\n", " Exact fiducial parameters from Munoz et al \u001b[1;36m2021\u001b[0m. Disables modules \n", "implemented afterwards\n", "\u001b[1;35mfixed-halos\u001b[0m \n", " integrals of the CHMF on the Eulerian \u001b[1m(\u001b[0mevolved\u001b[1m)\u001b[0m density grid, FFRT-P in \n", "Davies+\u001b[1;36m22\u001b[0m or ESF-E in Trac+\u001b[1;36m22\u001b[0m\n", "\u001b[1;35msize-tiny\u001b[0m \u001b[35m | tiny\u001b[0m\n", " Set the simulation to have a very small size \u001b[1m(\u001b[0m\u001b[1;36m48\u001b[0m Mpc\u001b[1m)\u001b[0m, useful for quick \n", "tests. Intended to be used on top of another template\n", "\u001b[1;35msize-small\u001b[0m \u001b[35m | small\u001b[0m\n", " Set the simulation to have a small size \u001b[1m(\u001b[0m\u001b[1;36m92\u001b[0m Mpc\u001b[1m)\u001b[0m, useful for quick \n", "exploration. Intended to be used on top of another template\n", "\u001b[1;35msize-medium\u001b[0m \u001b[35m | medium\u001b[0m\n", " Set the simulation to have a medium size \u001b[1m(\u001b[0m\u001b[1;36m384\u001b[0m Mpc\u001b[1m)\u001b[0m, useful for MCMC. \n", "Intended to be used on top of another template.\n", "\u001b[1;35msize-gpc\u001b[0m \u001b[35m | gpc | large\u001b[0m\n", " Set the simulation to have a large size \u001b[1m(\u001b[0m~\u001b[1;36m1\u001b[0m Gpc\u001b[1m)\u001b[0m. Intended to be used on\n", "top of another template.\n" ] } ], "source": [ "! 21cmfast template avail" ] }, { "cell_type": "markdown", "id": "535df086", "metadata": {}, "source": [ "This output lists the name (and aliases, which will work just as well as the name when\n", "specifying the template) as well as a short description of each built-in template. \n", "Templates whose names begin with `size-` only contain options that modify the size of \n", "the simulation (which may include the number of node redshifts)." ] }, { "cell_type": "markdown", "id": "a9d6eda1", "metadata": {}, "source": [ "### Generating Required Citations/Acknowledgments" ] }, { "cell_type": "markdown", "id": "7f385f36", "metadata": {}, "source": [ "You may wonder what papers to cite for a given model that you are using. This is made\n", "easier by using the `show_references` function:" ] }, { "cell_type": "code", "execution_count": 22, "id": "ead56306", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The main reference for 21cmFAST v3+:\n", "====================================\n", "Murray et al., (2020). 21cmFAST v3: A Python-integrated C code for generating 3D\n", "realizations of the cosmic 21cm signal. Journal of Open Source Software, 5(54),\n", "2582, https://doi.org/10.21105/joss.02582\n", "\n", "Based on the original 21cmFAST model:\n", "=====================================\n", "Andrei Mesinger, Steven Furlanetto and Renyue Cen, \"21CMFAST: a fast, seminumerical\n", "simulation of the high-redshift 21-cm signal\", Monthly Notices of the Royal\n", "Astronomical Society, Volume 411, Issue 2, pp. 955-972 (2011),\n", "https://ui.adsabs.harvard.edu/link_gateway/2011MNRAS.411..955M/doi:10.1111/j.1365-2966.2010.17731.x\n", "\n", "The mass-dependent ionising efficiency model:\n", "=============================================\n", "Park, J., Mesinger, A., Greig, B., and Gillet, N.,\n", "“Inferring the astrophysics of reionization and cosmic dawn from galaxy luminosity\n", "functions and the 21-cm signal”, Monthly Notices of the Royal Astronomical Society,\n", "vol. 484, no. 1, pp. 933–949, 2019. https://doi.org/10.1093/mnras/stz032.\n", "\n", "\n" ] } ], "source": [ "p21c.utils.show_references(p21c.InputParameters.from_template('simple', random_seed=0));" ] }, { "cell_type": "markdown", "id": "7fbf775b", "metadata": {}, "source": [ "This will print only the references applicable to the set of models switched on according\n", "to your `InputParameters` instance." ] }, { "cell_type": "markdown", "id": "691afad0", "metadata": {}, "source": [ "### Create Your Own Template" ] }, { "cell_type": "markdown", "id": "d2725593", "metadata": {}, "source": [ "The built-in templates are simply defined as TOML files. You can create your own\n", "Parameter TOML as well:" ] }, { "cell_type": "code", "execution_count": 27, "id": "c079bec0", "metadata": {}, "outputs": [], "source": [ "inputs = p21c.InputParameters.from_template(['simple', 'large'], random_seed=1)\n", "\n", "# For the sake of the tutorial, write the custom toml into a temporary directory\n", "tomlfile = Path(mkdtemp()) / 'custom_parameters.toml'\n", "p21c.write_template(inputs, tomlfile)" ] }, { "cell_type": "markdown", "id": "fad7d2e5", "metadata": {}, "source": [ "You can then use this TOML file in the `.from_template` function:" ] }, { "cell_type": "code", "execution_count": 30, "id": "0635b285", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Original == New? True\n" ] } ], "source": [ "inputs_read = p21c.InputParameters.from_template(tomlfile, random_seed=1)\n", "\n", "print(\"Original == New? \", inputs==inputs_read)" ] }, { "cell_type": "markdown", "id": "16d10ed7", "metadata": {}, "source": [ "
\n", "\n", "Note\n", "\n", "It is not possible to register new 'built-in' templates that are accessible by name, only\n", "to define new TOML files that can be explicitly pointed to. However, if you have a set\n", "of parameters that correspond to a publicly-available simulation or publication of interest,\n", "feel free to [make a PR](https://github.com/21cmfast/21cmFAST/compare) that adds it as\n", "a built-in!\n", "\n", "
" ] }, { "cell_type": "markdown", "id": "f7371a20", "metadata": {}, "source": [ "By default, the `write_template` function creates a **full** TOML file with all \n", "of the possible parameters specified in it. In fact, you can create a TOML file listing\n", "all of the default parameters very easily:" ] }, { "cell_type": "code", "execution_count": 32, "id": "dba550e0", "metadata": {}, "outputs": [], "source": [ "inputs = p21c.InputParameters.from_template(['defaults'], random_seed=1)\n", "\n", "# For the sake of the tutorial, write the custom toml into a temporary directory\n", "tomlfile = Path(mkdtemp()) / 'default_parameters.toml'\n", "p21c.write_template(inputs, tomlfile)" ] }, { "cell_type": "markdown", "id": "8804a16e", "metadata": {}, "source": [ "Sometimes, it's useful to instead only list the parameters that are non-default, in order\n", "to bring attention to what you intend to modify. To do this, set the `mode` parameter:" ] }, { "cell_type": "code", "execution_count": 33, "id": "1aca7b77", "metadata": {}, "outputs": [], "source": [ "inputs = p21c.InputParameters.from_template(['defaults'], SIGMA_8=0.9, random_seed=1)\n", "\n", "# For the sake of the tutorial, write the custom toml into a temporary directory\n", "tomlfile = Path(mkdtemp()) / 'minimal_parameters.toml'\n", "p21c.write_template(inputs, tomlfile, mode='minimal')" ] }, { "cell_type": "markdown", "id": "1fbc6f28", "metadata": {}, "source": [ "This file should only list the `SIGMA_8` parameter:" ] }, { "cell_type": "code", "execution_count": 34, "id": "8d5c5bbe", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# This file was generated by py21cmfast.run_templates.write_template\n", "# Created on: 2025-07-29T02:21:52.467573\n", "\n", "[CosmoParams]\n", "SIGMA_8 = 0.9\n", "\n" ] } ], "source": [ "with tomlfile.open('r') as fl:\n", " print(fl.read())" ] }, { "cell_type": "markdown", "id": "a70bf0ec", "metadata": {}, "source": [ "## Specifying Node Redshifts" ] }, { "cell_type": "markdown", "id": "3e7aefac", "metadata": {}, "source": [ "There is another input that is not captured by the parameter groups listed above, which\n", "is the set of redshifts at which the \"evolution\" of the model is evaluated. \n", "\n", "These redshifts are known as the `node_redshifts`. " ] }, { "cell_type": "markdown", "id": "4b5052c4", "metadata": {}, "source": [ "
\n", "\n", "Warning\n", "\n", "The `node_redshifts` are a separate concept from the redshifts at which you might \n", "want to generate your simulation boxes. The \"output\" redshifts are different depending\n", "on whether you are interesting in `coeval` boxes or `lightcones`. In either case, the\n", "`node_redshifts` can in general be different from the output redshifts (within some\n", "limitations). The `node_redshifts` can be thought of as defining the intrinsic *evolution*\n", "of the simulation, while the output redshifts are merely for viewing. \n", "
" ] }, { "cell_type": "markdown", "id": "7edc7d0b", "metadata": {}, "source": [ "Not all physical models in `21cmFAST` require evolution: the simplest models can be\n", "directly evaluated at any redshift. In these cases, while `node_redshifts` *may* be \n", "specified, it is not required (and by default will not be specified). To check if your\n", "model requires `node_redshifts`, use the `evolution_required` attribute:" ] }, { "cell_type": "code", "execution_count": 37, "id": "452ea78d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Evolution Required for Simple? False\n", "Evolution Required for EOS21? True\n" ] } ], "source": [ "simple = p21c.InputParameters.from_template('simple', random_seed=1)\n", "print(\"Evolution Required for Simple? \", simple.evolution_required)\n", "\n", "eos21 = p21c.InputParameters.from_template('EOS21', random_seed=1)\n", "print(\"Evolution Required for EOS21? \", eos21.evolution_required)\n" ] }, { "cell_type": "markdown", "id": "837733b2", "metadata": {}, "source": [ "In `21cmFAST`, the `node_redshifts` are completely flexible -- you can specify any \n", "set of `node_redshifts` that you like, so long as they are monotonically decreasing,\n", "and start above `AstroOptions.Z_HEAT_MAX`. \n", "\n", "However, the default -- when the model requires it -- is to use a regular log-spaced\n", "(in $1 + z$) sequence of redshifts, spanning from $z=5.5$ to $z \\ge $ `Z_HEAT_MAX` with\n", "a geometric spacing of `AstroOptions.ZPRIME_STEP_FACTOR`." ] }, { "cell_type": "markdown", "id": "11da73bd", "metadata": {}, "source": [ "To control the set of node redshifts, you can pass them explicitly:" ] }, { "cell_type": "code", "execution_count": 38, "id": "38e13eb4", "metadata": {}, "outputs": [], "source": [ "inputs = p21c.InputParameters.from_template(\n", " \"EOS21\", \n", " node_redshifts=[7.0, 8.0, 10.0, 15.0, 25.0, 40.0], \n", " random_seed=1\n", ")" ] }, { "cell_type": "markdown", "id": "a8bad892", "metadata": {}, "source": [ "However, it is generally better to use log-spaced redshifts. If you do not require\n", "control of the *minimum* redshift, then this can be specified explicitly via normal\n", "parameters:" ] }, { "cell_type": "code", "execution_count": 42, "id": "0b5b47e2", "metadata": {}, "outputs": [], "source": [ "inputs_coarse = p21c.InputParameters.from_template(\n", " \"EOS21\",\n", " ZPRIME_STEP_FACTOR=1.2, # default is 1.02\n", " Z_HEAT_MAX=20.0, # default is 35\n", " random_seed=1\n", ")" ] }, { "cell_type": "code", "execution_count": 43, "id": "f71d2fa6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(22.290675199999992, 18.408895999999995, 15.174079999999996, 12.478399999999999, 10.232, 8.36, 6.8, 5.5)\n" ] } ], "source": [ "print(inputs_coarse.node_redshifts)" ] }, { "cell_type": "markdown", "id": "a35160f5", "metadata": {}, "source": [ "If you also require control of the minimum redshift, use the `.with_logspaced_redshifts`\n", "constructor method:" ] }, { "cell_type": "code", "execution_count": 47, "id": "303ddee4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "20.499, 16.916, 13.930, 11.442, 9.368, 7.640, 6.200, 5.000\n" ] } ], "source": [ "inputs_coarse_low_zmin = inputs_coarse.with_logspaced_redshifts(zmin=5.0)\n", "print(\", \".join(f'{z:.3f}' for z in inputs_coarse_low_zmin.node_redshifts))" ] }, { "cell_type": "markdown", "id": "dda71caf", "metadata": {}, "source": [ "The `.with_logspaced_redshifts` method by default uses the `Z_HEAT_MAX` and \n", "`ZPRIME_STEP_FACTOR` parameters to set the range and resolution of the grid, but these\n", "can be specified manually as well:" ] }, { "cell_type": "code", "execution_count": 48, "id": "9f111908", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "21.278, 16.137, 12.182, 9.140, 6.800, 5.000\n" ] } ], "source": [ "inputs_coarse_low_zmin = inputs_coarse.with_logspaced_redshifts(zmin=5.0, zmax=21.0, zstep_factor=1.3)\n", "print(\", \".join(f'{z:.3f}' for z in inputs_coarse_low_zmin.node_redshifts))" ] }, { "cell_type": "markdown", "id": "876ab16c", "metadata": {}, "source": [ "## Tips on Specifying Simulation Size" ] }, { "cell_type": "markdown", "id": "4f9aa298", "metadata": {}, "source": [ "The \"size\" of a simulation depends on a number of options, but the main ones are:\n", "\n", "* `DIM`: The dimensionality of the high-resolution periodic boxes produced by the initial\n", " conditions simulation step. \n", "* `HII_DIM`: The dimensionality of the low-resolution periodic boxes produced by all \n", " subsequent steps after the initial conditions. While these are lower resolution, there\n", " are many more fields that are produced at this dimensionality. Typically this will be\n", " about 1/3 or 1/4 of `DIM`. Roughly speaking, simulation time, memory and storage\n", " scales as `HII_DIM^3`.\n", "* `node_redshifts`: For models that require evolution, the total time and storage\n", " requirements scale linearly with the number of node redshifts (see above). Given\n", " that these are by default set via `ZPRIME_STEP_FACTOR` and `Z_HEAT_MAX`, these parameters\n", " can be considered as options that affect the size of the simulation.\n", "* `N_STEPS_TS`: for models with `USE_TS_FLUCT=True`, this parameter controls how many\n", " radial shells are computed. The higher the number, the more accurate the results, but\n", " the total simulation time and peak memory will scale linearly with `N_STEPS_TS` (not\n", " counting overheads)." ] }, { "cell_type": "markdown", "id": "c22bffb8", "metadata": {}, "source": [ "The easiest way to switch between different simulation sizes is by using the built-in\n", "size-templates. These set multiple size-related parameters at once, with options of \n", "`tiny`, `small`, `medium` and `large`. " ] }, { "cell_type": "markdown", "id": "125bf205", "metadata": {}, "source": [ "From v4, it is recommended to use *resolution* parameters instead of explicit dimensionalities\n", "when setting up boxes. Thus, instead of specifying `DIM`, specify `HIRES_TO_LOWRES_FACTOR`\n", "along with `HII_DIM`. And instead of specifying `BOX_LEN`, specify `LOWRES_CELL_SIZE_MPC`. \n", "Specifying these ratios means that updating `HII_DIM` will automatically yield a new\n", "simulation size with the same resolution (auto-updating `DIM` and `BOX_LEN`).\n", "\n", "All the built-in size-templates are implemented using ratios, so doing:" ] }, { "cell_type": "code", "execution_count": 50, "id": "e882cd7a", "metadata": {}, "outputs": [], "source": [ "inputs = p21c.InputParameters.from_template(\n", " ['EOS21', 'medium'], random_seed=1\n", ").evolve_input_structs(\n", " HII_DIM=1000\n", ")" ] }, { "cell_type": "markdown", "id": "c90b4785", "metadata": {}, "source": [ "will still yield a reasonable box size and high-resolution dimensionality:" ] }, { "cell_type": "code", "execution_count": 51, "id": "2146db66", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "New BOX_LEN: 1500\n", "New DIM: 3000\n" ] } ], "source": [ "print(\"New BOX_LEN: \", inputs.simulation_options.BOX_LEN)\n", "print(\"New DIM: \", inputs.simulation_options.DIM)" ] }, { "cell_type": "markdown", "id": "887d9f47", "metadata": {}, "source": [ "You can also update the ratios consistently:" ] }, { "cell_type": "code", "execution_count": 52, "id": "cc70ea90", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4000\n" ] } ], "source": [ "inputs = inputs.evolve_input_structs(HIRES_TO_LOWRES_FACTOR=4)\n", "print(inputs.simulation_options.DIM)" ] }, { "cell_type": "markdown", "id": "2db11274", "metadata": {}, "source": [ "However, you cannot go from \"ratio\" mode to \"explicit\" mode:" ] }, { "cell_type": "code", "execution_count": 53, "id": "105b55df", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Cannot set both DIM and HIRES_TO_LOWRES_FACTOR! If this error arose when lading from template/file or evolving an existing object, then explicitly set either DIM or HIRES_TO_LOWRES_FACTOR to None while setting the other to the desired value.\n" ] } ], "source": [ "try:\n", " inputs.evolve_input_structs(DIM=2345)\n", "except Exception as e:\n", " print(type(e), e)" ] }, { "cell_type": "markdown", "id": "58e5053e", "metadata": {}, "source": [ "If you must do this, explicitly set the ratio to None:" ] }, { "cell_type": "code", "execution_count": 54, "id": "852a74ac", "metadata": {}, "outputs": [], "source": [ "new = inputs.evolve_input_structs(DIM=2345, HIRES_TO_LOWRES_FACTOR=None)" ] } ], "metadata": { "kernelspec": { "display_name": "21cmFAST", "language": "python", "name": "21cmfast" }, "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.11.0" } }, "nbformat": 4, "nbformat_minor": 5 }