From b79400cdc6580316817ed7c1f4a75e5bed9d4f3d Mon Sep 17 00:00:00 2001 From: loikki <loic.hausammann@protonmail.ch> Date: Tue, 4 Jun 2019 10:30:27 +0200 Subject: [PATCH] Improve documentation --- docs/RST/examples.rst | 1 + docs/RST/examples/cooling.rst | 8 +- docs/RST/examples/stellar.rst | 25 ++++++ docs/RST/libstellar.rst | 11 +++ docs/RST/pyswiftsim.rst | 3 - docs/index.rst | 1 + examples/lifetime/plot_lifetime.py | 8 +- pyswiftsim/__init__.py | 129 ++++++++++++++++++++++++++++- src/libstellar.c | 50 +++++++++-- tests/test_lifetime.py | 6 ++ 10 files changed, 227 insertions(+), 15 deletions(-) create mode 100644 docs/RST/examples/stellar.rst create mode 100644 docs/RST/libstellar.rst diff --git a/docs/RST/examples.rst b/docs/RST/examples.rst index 0912efd..ef5fc94 100644 --- a/docs/RST/examples.rst +++ b/docs/RST/examples.rst @@ -8,3 +8,4 @@ If you wish to generate them, you will need to first install PySWIFTsim and then :maxdepth: 2 examples/cooling.rst + examples/stellar.rst diff --git a/docs/RST/examples/cooling.rst b/docs/RST/examples/cooling.rst index 3f06576..f72b3f8 100644 --- a/docs/RST/examples/cooling.rst +++ b/docs/RST/examples/cooling.rst @@ -6,12 +6,12 @@ Cooling Rate ~~~~~~~~~~~~ This example is generated in ``examples/cooling_rate`` with the Grackle cooling. -The plot are the same than in [Smith2016]_. +The plot are the same than in [Smith2016]_ and uses a solar metallicity. The code has two different modes 1D or 2D. In the first mode, the code generates particles at different temperatures but same density and computes the cooling rate associated to theses conditions. -.. image:: https://obswww.unige.ch/~lhausamm/PySWIFTsim/examples/cooling_rate.png +.. image:: https://obswww.unige.ch/lastro/projects/Clastro/PySWIFTsim/examples/cooling_rate.png In the second mode, the code generates a grid of particles at different density and temperatures and then computes the cooling. I suppose that in [Smith2016]_, they use the non equilibrium mode of Grackle to generate this graph. @@ -19,12 +19,12 @@ It requires a careful initialization of the element fractions which is not easy For simplicity, only Grackle with the equilibrium mode is shown in this documentation. -.. image:: https://obswww.unige.ch/~lhausamm/PySWIFTsim/examples/cooling_rate_2d.png +.. image:: https://obswww.unige.ch/lastro/projects/Clastro/PySWIFTsim/examples/cooling_rate_2d.png Cooling Box ~~~~~~~~~~~ -.. image:: https://obswww.unige.ch/~lhausamm/PySWIFTsim/examples/cooling_box.png +.. image:: https://obswww.unige.ch/lastro/projects/Clastro/PySWIFTsim/examples/cooling_box.png diff --git a/docs/RST/examples/stellar.rst b/docs/RST/examples/stellar.rst new file mode 100644 index 0000000..94e1ac8 --- /dev/null +++ b/docs/RST/examples/stellar.rst @@ -0,0 +1,25 @@ +Stellar Examples +================ + + +Initial Mass Function +~~~~~~~~~~~~~~~~~~~~~ + +This example is generated in ``examples/initial_mass_function`` with GEAR's stellar model. +The initial mass function used in GEAR follows [Kroupa2001]_. + +.. image:: https://obswww.unige.ch/lastro/projects/Clastro/PySWIFTsim/examples/initial_mass_function.png + + +Lifetime +~~~~~~~~ + +This example is generated in ``examples/lifetime`` with GEAR's stellar model. +The lifetime in GEAR is a quadratic in metallicity and mass (see equation 3.32 in [Poirier2004]_) + + +.. image:: https://obswww.unige.ch/lastro/projects/Clastro/PySWIFTsim/examples/lifetime.png + + +.. [Kroupa2001] `On the variation of the Initial Mass Function <https://arxiv.org/abs/astro-ph/0009005>`_ +.. [Poirier2004] `Étude de l'évolution chimique et dynamique d'objets proto-galactiques: Application à l'évolution des galaxies spirales <https://obswww.unige.ch/~revaz/PyChem/_downloads/ff03ba21204a3f36fa4ec885abd545ae/ThesePoirier.pdf>`_ diff --git a/docs/RST/libstellar.rst b/docs/RST/libstellar.rst new file mode 100644 index 0000000..1a49508 --- /dev/null +++ b/docs/RST/libstellar.rst @@ -0,0 +1,11 @@ +Libstellar +========== + +.. automodule:: pyswiftsim.libstellar + :members: + :undoc-members: + :private-members: + :special-members: + :show-inheritance: + :inherited-members: + diff --git a/docs/RST/pyswiftsim.rst b/docs/RST/pyswiftsim.rst index 0e77bb5..d4b10ad 100644 --- a/docs/RST/pyswiftsim.rst +++ b/docs/RST/pyswiftsim.rst @@ -5,7 +5,4 @@ PySWIFTsim :members: :undoc-members: :private-members: - :special-members: - :show-inheritance: - :inherited-members: diff --git a/docs/index.rst b/docs/index.rst index d11523e..a799ccc 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -14,6 +14,7 @@ The aim is to provide a python tool that benefits from HPC code and allows to di RST/pyswiftsim.rst RST/libcooling.rst + RST/libstellar.rst RST/examples.rst diff --git a/examples/lifetime/plot_lifetime.py b/examples/lifetime/plot_lifetime.py index a1e1e9f..7696311 100644 --- a/examples/lifetime/plot_lifetime.py +++ b/examples/lifetime/plot_lifetime.py @@ -47,11 +47,17 @@ if __name__ == "__main__": print("Computing lifetime...") lifetime = libstellar.lifetimeFromMass(filename, mass, Z) + mass_from_lifetime = libstellar.massFromLifetime(filename, lifetime, Z) + lifetime /= 1e6 - plt.loglog(mass, lifetime) + plt.loglog(mass, lifetime, label="Lifetime from mass") + plt.loglog(mass_from_lifetime, lifetime, "--", + label="Mass from lifetime") plt.xlabel("Mass [Msun]") plt.ylabel("Lifetime [Myr]") + plt.legend() + plt.show() diff --git a/pyswiftsim/__init__.py b/pyswiftsim/__init__.py index 0025114..7852bc7 100644 --- a/pyswiftsim/__init__.py +++ b/pyswiftsim/__init__.py @@ -23,6 +23,10 @@ import yaml def downloadCoolingTable(): + """ + Download the cooling table if it does not already exist in the current + repository. + """ url = "http://virgodb.cosma.dur.ac.uk/" url += "swift-webstorage/CoolingTables/CloudyData_UVB=HM2012.h5" filename = "CloudyData_UVB=HM2012.h5" @@ -32,17 +36,81 @@ def downloadCoolingTable(): urllib.request.urlretrieve(url, filename) -def downloadChemistryTable(): - print("Not available") +def downloadYieldsTable(): + """ + Download the yields table if it does not already exist in the current + repository. + """ + url = "https://obswww.unige.ch/" + url += "lastro/projects/Clastro/PySWIFTsim/" + filename = "chemistry-AGB+OMgSFeZnSrYBaEu-16072013.h5" + + if not os.path.isfile(filename): + # Download the file from `url` and save it locally under `file_name`: + urllib.request.urlretrieve(url, filename) def parseYamlFile(filename): + """ + Parse a yaml file and return it as a dictionaryw. + + Parameters + ========== + + filename: str + The filename of the yaml file + + Returns + ======= + + yaml: dict + The parameters + + Examples + ======== + + >>> yaml = parseYamlFile("swift.yml") + >>> us = yaml["InternalUnitSystem"] + + Everything in the dictionary is a string, therefore you will need to + convert them manually. + + >>> unit_mass = float(us["UnitMass_in_cgs"]) + """ with open(filename, "r") as stream: stream = yaml.load(stream) return stream class ParameterFile: + """ + This structure generates a temporary parameter file that is automatically + removed. If the code crashes before the destruction of the parameter file, + the parameter file will not be removed, but it should be taken care + of by the operating system. + + Parameters + ========== + + overwrite: dict + Allow to overwrite some default parameters or to add new parameters. + + existing: str + Filename of an existing parameter file. + + Examples + ======== + + >>> overwrite = {"InternalUnitSystem": {"UnitMass_in_cgs": 1.}} + >>> with ParameterFile(overwrite=overwrite) as filename: + >>> params = parseYamlFile(filename) + >>> unit_mass = params["InternalUnitSystem"]["UnitMass_in_cgs"] + >>> print(unit_mass) + 1. + + + When leaving the ``with`` environment, the file is deleted. + """ default_parameters = { "InternalUnitSystem": { "UnitMass_in_cgs": 1.989e43, # 1e10 Msun @@ -105,12 +173,44 @@ class ParameterFile: "constant": [-261.365, 17.073, 9.8661], } } + """ + Dictionnary containing all the default parameters to write in the + parameter file. + """ def _write(self, f, txt): + """ + Encode and then write the string into a stream. + + Parameters + ========== + + f: stream (e.g. an opened file) + The stream where to write the information + + txt: str + The text to write in the steam + + """ txt = txt.encode() f.write(txt) def _writeParameters(self, f, d, overwrite): + """ + Writes the parameters file. + + Parameters + ========== + + f: stream (e.g. opened file) + The stream where to write the parameter file. + + d: dict + The dictionary containing the default parameters to write. + + overwrite: dict + The dictionary containing the parameters to overwrite. + """ _format = " {}: {}\n" for sec in d.keys(): p = d[sec] @@ -167,6 +267,19 @@ class ParameterFile: print() def __init__(self, overwrite=None, existing=None): + """ + This function Initializes the structure, but does not create the file. + + Parameters + ========== + + overwrite: dict + Allow to overwrite some default parameters or to add new parameters. + + existing: str + Filename of an existing parameter file. + + """ if overwrite is not None and existing is not None: raise Exception("Cannot overwrite default parameters and" " use existing parameter file") @@ -175,6 +288,15 @@ class ParameterFile: self.existing = existing def __enter__(self): + """ + Create the parameter file. + + Returns + ======= + + filename: str + The filename of the parameter file. + """ if self.existing is not None: return self.existing @@ -187,5 +309,8 @@ class ParameterFile: return self.filename def __exit__(self, *args): + """ + Remove the temporary file. + """ if self.existing is None: os.remove(self.filename) diff --git a/src/libstellar.c b/src/libstellar.c index 579ec51..fcd1cb3 100644 --- a/src/libstellar.c +++ b/src/libstellar.c @@ -33,27 +33,67 @@ static PyMethodDef libstellar_methods[] = { "filename: str\n" "\t Parameter file\n" "mass: array\n" - "\t Mass of the stars in internal units\n" + "\t Mass of the stars in internal units.\n" "\n" "Returns\n" "-------\n" "imf: array\n" - "\t The initial mass function\n" + "\t The initial mass function.\n" "\n" "Examples\n" "--------\n" ">>> mass = np.array([1, 10])\n" ">>> filename = 'params.yml'\n" - ">>> imf = initialMassFunction(filename, mass)\n" + ">>> imf = libstellar.initialMassFunction(filename, mass)\n" }, {"lifetimeFromMass", pylifetime_from_mass, METH_VARARGS, - "TODO\n" + "Compute the lifetime of a star from its mass and metallicity.\n\n" + "Parameters\n" + "----------\n\n" + "filename: str\n" + "\t Parameter file\n" + "mass: array\n" + "\t Mass of the stars in internal units.\n" + "metallicity: array\n" + "\t Metallicity of the stars.\n" + "\n" + "Returns\n" + "-------\n" + "tau: array\n" + "\t The lifetime of the stars.\n" + "\n" + "Examples\n" + "--------\n" + ">>> mass = np.array([1, 10])\n" + ">>> Z = np.array([0.02, 0.01])\n" + ">>> filename = 'params.yml'\n" + ">>> tau = libstellar.lifetimeFromMass(filename, mass, Z)\n" }, {"massFromLifetime", pymass_from_lifetime, METH_VARARGS, - "TODO\n" + "Compute the mass of a star from its lifetime and metallicity.\n\n" + "Parameters\n" + "----------\n\n" + "filename: str\n" + "\t Parameter file\n" + "lifetime: array\n" + "\t Lifetime of the stars in internal units.\n" + "metallicity: array\n" + "\t Metallicity of the stars.\n" + "\n" + "Returns\n" + "-------\n" + "mass: array\n" + "\t The mass of the stars.\n" + "\n" + "Examples\n" + "--------\n" + ">>> lifetime = np.array([1e7, 1e9])\n" + ">>> Z = np.array([0.02, 0.01])\n" + ">>> filename = 'params.yml'\n" + ">>> mass = libstellar.massFromLifetime(filename, lifetime, Z)\n" }, diff --git a/tests/test_lifetime.py b/tests/test_lifetime.py index 6fb9f09..9a1816e 100644 --- a/tests/test_lifetime.py +++ b/tests/test_lifetime.py @@ -47,5 +47,11 @@ if __name__ == "__main__": print("Computing lifetime...") lifetime = libstellar.lifetimeFromMass(filename, mass, Z) + mass_from_lifetime = libstellar.massFromLifetime(filename, lifetime, Z) + + print("Mass used: {}".format(mass)) print("Lifetime obtained: {}".format(lifetime)) + + print("Relative error on the mass from the lifetime: {}".format( + (mass_from_lifetime - mass) / mass)) -- GitLab