From 71b231a40f8fc6ac9e6ba1a707c7f4631fa691eb Mon Sep 17 00:00:00 2001 From: Tom Wagg Date: Tue, 12 Nov 2024 16:20:56 -0800 Subject: [PATCH 1/7] start adding attribute docstrings --- cogsworth/pop.py | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/cogsworth/pop.py b/cogsworth/pop.py index b1e7779..e1c940c 100644 --- a/cogsworth/pop.py +++ b/cogsworth/pop.py @@ -386,6 +386,17 @@ def get_citations(self, filename=None): @property def bin_nums(self): + """An array of the unique identifiers for each binary in a population. + + This is a helper function which pulls from the bin_nums available in :attr:`final_bpp`, + or :attr:`initC`, or :attr:`initial_binaries` if available. If none of these are available, an + error is raised. + + Raises + ------ + ValueError + If no binaries have been sampled or evolved yet. + """ if self._bin_nums is None: if self._final_bpp is not None: self._bin_nums = self._final_bpp["bin_num"].unique() @@ -451,6 +462,18 @@ def initial_binaries(self): @property def bpp(self): + """A table of the evolutionary history of each binary. + + Each row of this table corresponds to an important timestep in the evolution of a binary. Events that + log a timestep include: stellar type of a star changing, mass transfer, a supernova, a common envelope + event, a binary merger, or a disruption. The columns of the table are described in detail `in the + COSMIC documentation `__. + + Raises + ------ + ValueError + If no stellar evolution has been performed yet. + """ if self._bpp is None and self._file is not None: self._bpp = pd.read_hdf(self._file, key="bpp") elif self._bpp is None: @@ -459,6 +482,21 @@ def bpp(self): @property def bcm(self): + """A table of the evolutionary history of each binary at dynamically chosen timesteps. + + Each row of this table corresponds to a timestep in the evolution of a binary. Timesteps are set + based on user-defined ``bcm_timestep_conditions``. The columns of the table are described in + detail + `in the COSMIC documentation `__. + + Raises + ------ + Warning + If no timestep conditions (``bcm_timestep_condition``) have been set for the BCM table. + + ValueError + If no stellar evolution has been performed yet. + """ if self._bcm is None and self._file is not None: has_bcm = None with h5.File(self._file, "r") as f: @@ -476,6 +514,16 @@ def bcm(self): @property def initC(self): + """A table of initial conditions for each binary. + + This table contains the initial conditions for each binary that was sampled. Each row corresponds to + a binary and the columns are described in detail in the COSMIC documentation. + + Raises + ------ + ValueError + If no stellar evolution has been performed yet. + """ if self._initC is None and self._file is not None: self._initC = pd.read_hdf(self._file, key="initC") elif self._initC is None: @@ -484,6 +532,17 @@ def initC(self): @property def kick_info(self): + """A table of the kicks that occur for each binary. + + Each row of this table corresponds to a potential supernova kick, such that there are two rows for + each binary in the population. The columns of the table are described in detail + `in the COSMIC documentation `__. + + Raises + ------ + ValueError + If no stellar evolution has been performed yet. + """ if self._kick_info is None and self._file is not None: self._kick_info = pd.read_hdf(self._file, key="kick_info") if self._kick_info is None: From 1d5b49bedd0968beceea6e3c05169acaaddc69f0 Mon Sep 17 00:00:00 2001 From: Tom Wagg Date: Tue, 12 Nov 2024 16:30:44 -0800 Subject: [PATCH 2/7] more docstrings, don't need initial attributes list --- cogsworth/pop.py | 175 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 134 insertions(+), 41 deletions(-) diff --git a/cogsworth/pop.py b/cogsworth/pop.py index e1c940c..ea8e72d 100644 --- a/cogsworth/pop.py +++ b/cogsworth/pop.py @@ -79,47 +79,6 @@ class Population(): Whether to store the entire orbit for each binary, by default True. If not then only the final PhaseSpacePosition will be stored. This cuts down on both memory usage and disk space used if you save the Population (as well as how long it takes to reload the data). - - Attributes - ---------- - mass_singles : `float` - Total mass in single stars needed to generate population - mass_binaries : `float` - Total mass in binaries needed to generate population - n_singles_req : `int` - Number of single stars needed to generate population - n_bin_req : `int` - Number of binaries needed to generate population - bpp : :class:`~pandas.DataFrame` - Evolutionary history of each binary - bcm : :class:`~pandas.DataFrame` - Final state of each binary - initC : :class:`~pandas.DataFrame` - Initial conditions for each binary - kick_info : :class:`~pandas.DataFrame` - Information about the kicks that occur for each binary - orbits : `list` of :class:`~gala.dynamics.Orbit` - The orbits of each system within the galaxy from its birth until :attr:`max_ev_time` with timesteps of - :attr:`timestep_size`. This list will have length = `len(self) + self.disrupted.sum()`, where the - first section are for bound binaries and disrupted primaries and the last section are for disrupted - secondaries - classes : `list` - The classes associated with each produced binary (see :meth:`~cogsworth.classify.list_classes` for a - list of available classes and their meanings) - final_pos, final_vel : :class:`~astropy.quantity.Quantity` - Final positions and velocities of each system in the galactocentric frame. - The first `len(self)` entries of each are for bound binaries or primaries, then the final - `self.disrupted.sum()` entries are for disrupted secondaries. Any missing orbits (where orbit=None - will be set to `np.inf` for ease of masking. - final_bpp : :class:`~pandas.DataFrame` - The final state of each binary (taken from the final entry in :attr:`bpp`) - disrupted : :class:`~numpy.ndarray` of `bool` - A mask on the binaries of whether they were disrupted - observables : :class:`~pandas.DataFrame` - Observables associated with the final binaries. See `get_photometry` for more details on the columns - bin_nums : :class:`~numpy.ndarray` - An array containing the unique COSMIC `bin_nums` of each binary in the population - these can be - used an indices for the population """ def __init__(self, n_binaries, processes=8, m1_cutoff=0, final_kstar1=list(range(16)), final_kstar2=list(range(16)), sfh_model=sfh.Wagg2022, sfh_params={}, @@ -392,6 +351,11 @@ def bin_nums(self): or :attr:`initC`, or :attr:`initial_binaries` if available. If none of these are available, an error is raised. + Returns + ------- + bin_nums : :class:`~numpy.ndarray` + An array of the unique identifiers for each binary in the population. + Raises ------ ValueError @@ -410,6 +374,21 @@ def bin_nums(self): @property def initial_galaxy(self): + """The initial sampled galactic star formation history. + + This contains the initial conditions for the galaxy that was sampled to generate the population. This + includes the birth times, positions, velocities, and metallicities of the stars in the galaxy. + + Returns + ------- + initial_galaxy : :class:`~cogsworth.sfh.StarFormationHistory` + The initial galaxy that was sampled to generate the population. + + Raises + ------ + ValueError + If no galaxy has been sampled yet. + """ if self._initial_galaxy is None and self._file is not None: self._initial_galaxy = sfh.load(self._file, key="initial_galaxy") self.sfh_model = self._initial_galaxy.__class__ @@ -419,30 +398,94 @@ def initial_galaxy(self): @property def mass_singles(self): + """The total mass in single stars needed to generate the population. + + Returns + ------- + mass_singles : `float` + The total mass in single stars needed to generate the population (in solar masses). + + Raises + ------ + ValueError + If no population sampled yet. + """ if self._mass_singles is None: raise ValueError("No population sampled yet, run `sample_initial_binaries` to do so.") return self._mass_singles @property def mass_binaries(self): + """The total mass in binaries needed to generate the population. + + Returns + ------- + mass_binaries : `float` + The total mass in binaries + + Raises + ------ + ValueError + If no population sampled yet. + """ if self._mass_binaries is None: raise ValueError("No population sampled yet, run `sample_initial_binaries` to do so.") return self._mass_binaries @property def n_singles_req(self): + """The number of single stars needed to generate the population. + + Returns + ------- + n_singles_req : `int` + The number of single stars needed to generate the population. + + Raises + ------ + ValueError + If no population sampled yet. + """ if self._n_singles_req is None: raise ValueError("No population sampled yet, run `sample_initial_binaries` to do so.") return self._n_singles_req @property def n_bin_req(self): + """The number of binary stars needed to generate the population. + + Returns + ------- + n_bin_req : `int` + The number of binary stars needed to generate the population. + + Raises + ------ + ValueError + If no population sampled yet. + """ if self._n_bin_req is None: raise ValueError("No population sampled yet, run `sample_initial_binaries` to do so.") return self._n_bin_req @property def initial_binaries(self): + """The initial binaries that were sampled to generate the population. + + This is only used when evolution has not been performed yet. If evolution has been performed, the + initial binaries are stored in the :attr:`initC` table instead (since this also includes information + on the assumed binary physics). + + Returns + ------- + initial_binaries : :class:`~pandas.DataFrame` + The initial binaries that were sampled to generate the population. + + Raises + ------ + ValueError + If no binaries have been sampled yet. + """ # use initC if available if self._initial_binaries is None and self._initC is not None: return self._initC @@ -469,6 +512,11 @@ def bpp(self): event, a binary merger, or a disruption. The columns of the table are described in detail `in the COSMIC documentation `__. + Returns + ------- + bpp : :class:`~pandas.DataFrame` + The evolutionary history of each binary. + Raises ------ ValueError @@ -489,6 +537,12 @@ def bcm(self): detail `in the COSMIC documentation `__. + Returns + ------- + bcm : :class:`~pandas.DataFrame` + The evolutionary history of each binary at dynamically chosen timesteps. Note this will be + ``None`` if no timestep conditions have been set (in ``bcm_timestep_conditions``). + Raises ------ Warning @@ -519,6 +573,11 @@ def initC(self): This table contains the initial conditions for each binary that was sampled. Each row corresponds to a binary and the columns are described in detail in the COSMIC documentation. + Returns + ------- + initC : :class:`~pandas.DataFrame` + The initial conditions for each binary. + Raises ------ ValueError @@ -538,6 +597,11 @@ def kick_info(self): each binary in the population. The columns of the table are described in detail `in the COSMIC documentation `__. + Returns + ------- + kick_info : :class:`~pandas.DataFrame` + Information about the kicks that occur for each binary. + Raises ------ ValueError @@ -551,6 +615,21 @@ def kick_info(self): @property def orbits(self): + """The orbits of each system within the galaxy from its birth until :attr:`max_ev_time`. + + This list will have length = `len(self) + self.disrupted.sum()`, where the first section are for + bound binaries and disrupted primaries and the last section are for disrupted secondaries. + + Returns + ------- + orbits : `list` of :class:`~gala.dynamics.Orbit`, shape (len(self) + self.disrupted.sum(),) + The orbits of each system within the galaxy from its birth until :attr:`max_ev_time`. + + Raises + ------ + ValueError + If no orbits have been calculated yet. + """ # if orbits are uncalculated and no file is provided then throw an error if self._orbits is None and self._file is None: raise ValueError("No orbits calculated yet, run `perform_galactic_evolution` to do so") @@ -578,10 +657,24 @@ def orbits(self): @property def primary_orbits(self): + """The orbits of primary stars + + Returns + ------- + primary_orbits : :class:`~gala.dynamics.Orbit`, shape (len(self),) + The orbits of the primary stars in the population + """ return self.orbits[:len(self)] @property def secondary_orbits(self): + """The orbits of secondary stars + + Returns + ------- + secondary_orbits : :class:`~gala.dynamics.Orbit`, shape (len(self),) + The orbits of the secondary stars in the population + """ order = np.argsort(np.concatenate((self.bin_nums[~self.disrupted], self.bin_nums[self.disrupted]))) return np.concatenate((self.primary_orbits[~self.disrupted], self.orbits[len(self):]))[order] From 6b081ed34088b7cef32487cf404993627e911d12 Mon Sep 17 00:00:00 2001 From: Tom Wagg Date: Tue, 12 Nov 2024 16:34:53 -0800 Subject: [PATCH 3/7] almost all docstrings for attributes in Pop added --- cogsworth/pop.py | 59 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/cogsworth/pop.py b/cogsworth/pop.py index ea8e72d..5895ed7 100644 --- a/cogsworth/pop.py +++ b/cogsworth/pop.py @@ -422,7 +422,7 @@ def mass_binaries(self): ------- mass_binaries : `float` The total mass in binaries - + Raises ------ ValueError @@ -440,7 +440,7 @@ def n_singles_req(self): ------- n_singles_req : `int` The number of single stars needed to generate the population. - + Raises ------ ValueError @@ -458,7 +458,7 @@ def n_bin_req(self): ------- n_bin_req : `int` The number of binary stars needed to generate the population. - + Raises ------ ValueError @@ -686,18 +686,41 @@ def classes(self): @property def final_pos(self): + """The final position of each binary (or star from a disrupted binary) in the galaxy. + + Returns + ------- + final_pos : :class:`~numpy.ndarray`, shape (len(self) + self.disrupted.sum(), 3) + The final position of each binary (or star from a disrupted binary) in the galaxy. + """ if self._final_pos is None: self._final_pos, self._final_vel = self._get_final_coords() return self._final_pos @property def final_vel(self): + """The final velocity of each binary (or star from a disrupted binary) in the galaxy. + + Returns + ------- + final_vel : :class:`~numpy.ndarray`, shape (len(self) + self.disrupted.sum(), 3) + The final velocity of each binary (or star from a disrupted binary) in the galaxy. + """ if self._final_vel is None: self._final_pos, self._final_vel = self._get_final_coords() return self._final_vel @property def final_bpp(self): + """The final state of each binary in the population. + + This is simply the final row from the :attr:`bpp` table for each binary. + + Returns + ------- + final_bpp : :class:`~pandas.DataFrame` + The final state of each binary in the population. + """ if self._final_bpp is None: self._final_bpp = self.bpp.drop_duplicates(subset="bin_num", keep="last") self._final_bpp.insert(len(self._final_bpp.columns), "metallicity", @@ -706,6 +729,13 @@ def final_bpp(self): @property def disrupted(self): + """A mask of whether a binary was disrupted during its evolution. + + Returns + ------- + disrupted : :class:`~numpy.ndarray`, shape (len(self),) + A mask of whether a binary was disrupted during its evolution. + """ if self._disrupted is None: # check for disruptions in THREE different ways because COSMIC isn't always consistent (: self._disrupted = (self.final_bpp["bin_num"].isin(self.kick_info[self.kick_info["disrupted"] == 1.0]["bin_num"].unique()) @@ -715,6 +745,16 @@ def disrupted(self): @property def escaped(self): + """A mask of whether a binary escaped the galaxy during its evolution. + + This is calculated by comparing the final velocity of the binary to the escape velocity at its + final position. + + Returns + ------- + escaped : :class:`~numpy.ndarray`, shape (len(self),) + A mask of whether a binary escaped the galaxy during its evolution. + """ if self._escaped is None: self._escaped = np.repeat(False, len(self)) @@ -728,6 +768,19 @@ def escaped(self): @property def observables(self): + """A table of the observable properties of each binary. + + Returns + ------- + observables : :class:`~pandas.DataFrame` + The observable properties of each binary. Columns are defined in + :func:`~cogsworth.observables.get_observables`. + + Raises + ------ + ValueError + If no observables have been calculated yet. + """ if self._observables is None: raise ValueError("Observables not yet calculated, run `get_observables` to do so") else: From efd603ab18c7c316e21f8188f8b6a7998ffa4248 Mon Sep 17 00:00:00 2001 From: Tom Wagg Date: Tue, 12 Nov 2024 16:40:25 -0800 Subject: [PATCH 4/7] document classes better --- cogsworth/classify.py | 3 ++- cogsworth/pop.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cogsworth/classify.py b/cogsworth/classify.py index a04b735..cb68efe 100644 --- a/cogsworth/classify.py +++ b/cogsworth/classify.py @@ -33,7 +33,8 @@ def determine_final_classes(population=None, bpp=None, kick_info=None, orbits=No Returns ------- classes : :class:`~pandas.DataFrame` - A DataFrame with a boolean column for each class (see :meth:`list_classes`) and a row for each binary + A DataFrame with a boolean column for each class and a row for each binary. + Run :func:`~cogsworth.classify.list_classes` to see the available classes and their criteria. Raises ------ diff --git a/cogsworth/pop.py b/cogsworth/pop.py index 5895ed7..f096a90 100644 --- a/cogsworth/pop.py +++ b/cogsworth/pop.py @@ -680,7 +680,20 @@ def secondary_orbits(self): @property def classes(self): + """A table of classes that apply to each binary. + + Each row corresponds to a binary and the columns are a boolean of whether they meet the criteria for + a class. For a full description of classes and their criteria, + run :func:`~cogsworth.classify.list_classes`. + + Returns + ------- + classes : :class:`~pandas.DataFrame` + The classes that apply to each binary. + """ if self._classes is None: + BOLD, RESET = "\033[1m", "\033[0m" + logging.getLogger("cogswoth").info(f"{BOLD}cogsworth info:{RESET} No classes calculated yet, running now") self._classes = determine_final_classes(population=self) return self._classes From 7d1181b06d5a803f63c7af35949c95f108d42f9a Mon Sep 17 00:00:00 2001 From: Tom Wagg Date: Tue, 12 Nov 2024 17:06:37 -0800 Subject: [PATCH 5/7] missed some functions from __all__ (classic) --- cogsworth/sfh.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cogsworth/sfh.py b/cogsworth/sfh.py index 5ce4773..b785574 100644 --- a/cogsworth/sfh.py +++ b/cogsworth/sfh.py @@ -21,7 +21,8 @@ from cogsworth.citations import CITATIONS -__all__ = ["StarFormationHistory", "Wagg2022", "QuasiIsothermalDisk", "load", "concat"] +__all__ = ["StarFormationHistory", "Wagg2022", "BurstUniformDisc", "ConstantUniformDisc", + "QuasiIsothermalDisk", "SpheroidalDwarf", "load", "concat"] class StarFormationHistory(): From b25512bf8292d11c9bbc0d17aa33092ed21ac137 Mon Sep 17 00:00:00 2001 From: Tom Wagg Date: Tue, 12 Nov 2024 17:06:48 -0800 Subject: [PATCH 6/7] add some human-readable tables --- cogsworth/utils.py | 2 + docs/modules/utils.rst | 124 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) diff --git a/cogsworth/utils.py b/cogsworth/utils.py index 65beade..85965df 100644 --- a/cogsworth/utils.py +++ b/cogsworth/utils.py @@ -68,6 +68,8 @@ def translate_COSMIC_tables(tab, kstars=True, evol_type=True, label_type="short", replace_columns=True): """Translate COSMIC BSE tables to human-readable labels + For a full description of the translations, see the tables in the :mod:`~cogsworth.utils` module page. + Parameters ---------- tab : :class:`~pandas.DataFrame` diff --git a/docs/modules/utils.rst b/docs/modules/utils.rst index ece27d5..73b023a 100644 --- a/docs/modules/utils.rst +++ b/docs/modules/utils.rst @@ -1,3 +1,5 @@ +.. _utils: + **************************** Helper functions (``utils``) **************************** @@ -7,3 +9,125 @@ most useful functionalities is translating COSMIC tables and plotting them as a .. automodapi:: cogsworth.utils :no-heading: + + +.. grid:: 1 1 2 2 + + .. grid-item:: + + .. list-table:: Translation of stellar types + :header-rows: 1 + + * - Stellar type ID + - Short name + - Long name + * - 0 + - MS < 0.7 + - Main Sequence (Low mass) + * - 1 + - MS + - Main Sequence + * - 2 + - HG + - Hertzsprung Gap + * - 3 + - FGB + - First Giant Branch + * - 4 + - CHeB + - Core Helium Burning + * - 5 + - EAGB + - Early Asymptotic Giant Branch + * - 6 + - TPAGB + - Thermally Pulsing Asymptotic Giant Branch + * - 7 + - HeMS + - Helium Main Sequence + * - 8 + - HeHG + - Helium Hertsprung Gap + * - 9 + - HeGB + - Helium Giant Branch + * - 10 + - HeWD + - Helium White Dwarf + * - 11 + - COWD + - Carbon/Oxygen White Dwarf + * - 12 + - ONeWD + - Oxygen/Neon White Dwarf + * - 13 + - NS + - Neutron Star + * - 14 + - BH + - Black Hole + * - 15 + - MR + - Massless Remnant + * - 16 + - CHE + - Chemically Homogeneous + + + + .. grid-item:: + + .. list-table:: Translation of evolutionary stages + :header-rows: 1 + + * - Evolutionary stage ID + - Short name + - Long name + * - 1 + - Init + - Initial state + * - 2 + - Kstar change + - Stellar type changed + * - 3 + - RLOF start + - Roche lobe overflow started + * - 4 + - RLOF end + - Roche lobe overflow ended + * - 5 + - Contact + - Binary entered contact phase + * - 6 + - Coalescence + - Binary coalesced + * - 7 + - CE start + - Common-envelope started + * - 8 + - CE end + - Common-envelope ended + * - 9 + - No remnant + - No remnant + * - 10 + - Max evol time + - Maximum evolution time reached + * - 11 + - Disruption + - Binary disrupted + * - 12 + - Begin symbiotic phase + - Begin symbiotic phase + * - 13 + - End symbiotic phase + - End symbiotic phase + * - 14 + - Blue straggler + - Blue straggler + * - 15 + - SN1 + - Supernova of primary + * - 16 + - SN2 + - Supernova of secondary From 1c287635ca5a5e8dfd9e48d7ded47a3d736aedd2 Mon Sep 17 00:00:00 2001 From: Tom Wagg Date: Tue, 12 Nov 2024 17:13:57 -0800 Subject: [PATCH 7/7] add sfh attribute docstrings --- cogsworth/sfh.py | 96 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 82 insertions(+), 14 deletions(-) diff --git a/cogsworth/sfh.py b/cogsworth/sfh.py index b785574..4a10051 100644 --- a/cogsworth/sfh.py +++ b/cogsworth/sfh.py @@ -47,20 +47,6 @@ class StarFormationHistory(): immediately_sample : `bool`, optional Whether to immediately sample the points, by default True - - Attributes - ---------- - tau : :class:`~astropy.units.Quantity` [time] - Lookback time - Z : :class:`~astropy.units.Quantity` [dimensionless] - Metallicity - x : :class:`~astropy.units.Quantity` [length] - Galactocentric x position - y : :class:`~astropy.units.Quantity` [length] - Galactocentric y position - z : :class:`~astropy.units.Quantity` [length] - Galactocentric z position - """ def __init__(self, size, components=None, component_masses=None, immediately_sample=True, **kwargs): @@ -132,6 +118,7 @@ def __getitem__(self, ind): @property def size(self): + """The number of points in the star formation history model""" return self._size @size.setter @@ -144,56 +131,137 @@ def size(self, value): @property def components(self): + """A list of the components in the star formation history model + + Returns + ------- + components : ``list`` of ``str`` + The list of the components in the star formation history model + """ return self._components @property def component_masses(self): + """The masses of the components in the star formation history model + + Returns + ------- + component_masses : ``list`` of ``float``, [Msun] + The masses of the components in the star formation history model + """ return self._component_masses @property def tau(self): + """The lookback times of the sampled points + + Returns + ------- + tau : :class:`~astropy.units.Quantity` [time] + The lookback times of the sampled points + """ if self._tau is None: self.sample() return self._tau @property def Z(self): + """The metallicities of the sampled points + + Returns + ------- + Z : :class:`~astropy.units.Quantity` [dimensionless] + The metallicities of the sampled points (absolute metallicity **not** solar metallicity) + """ if self._Z is None: self.sample() return self._Z @property def x(self): + """The galactocentric x positions of the sampled points + + Returns + ------- + x : :class:`~astropy.units.Quantity` [length] + The galactocentric x positions of the sampled points + """ if self._x is None: self.sample() return self._x @property def y(self): + """The galactocentric y positions of the sampled points + + Returns + ------- + y : :class:`~astropy.units.Quantity` [length] + The galactocentric y positions of the sampled points + """ if self._y is None: self.sample() return self._y @property def z(self): + """The galactocentric z positions of the sampled points + + Returns + ------- + z : :class:`~astropy.units.Quantity` [length] + The galactocentric z positions of the sampled points + """ if self._z is None: self.sample() return self._z @property def rho(self): + """The galactocentric cylindrical radius of the sampled points + + A shortcut for the radius in the x-y plane, :math:`\\sqrt{x^2 + y^2}` + + Returns + ------- + rho : :class:`~astropy.units.Quantity` [length] + The galactocentric cylindrical radius of the sampled points + """ return (self.x**2 + self.y**2)**(0.5) @property def phi(self): + """The galactocentric azimuthal angle of the sampled points + + A shortcut for :math:`\\arctan(y / x)` + + Returns + ------- + phi : :class:`~astropy.units.Quantity` [angle] + The galactocentric azimuthal angle of the sampled points + """ return np.arctan2(self.y, self.x) @property def positions(self): + """The galactocentric positions of the sampled points + + Returns + ------- + positions : :class:`~astropy.units.Quantity` [length], shape=(3, :attr:`~size`) + The galactocentric positions of the sampled points + """ return [self.x.to(u.kpc).value, self.y.to(u.kpc).value, self.z.to(u.kpc).value] * u.kpc @property def which_comp(self): + """The component each point belongs to + + Returns + ------- + which_comp : ``numpy.ndarray`` of ``str`` + The component each point belongs to + """ if self._which_comp is None: self.sample() return self._which_comp