Source code for taurex.data.profiles.chemistry.chemistry
"""Base chemical profile class."""importtypingastimportnumpyasnpimportnumpy.typingasnptfromtaurex.cacheimportGlobalCache,OpacityCachefromtaurex.cache.ktablecacheimportKTableCachefromtaurex.data.citationimportCitablefromtaurex.data.fittableimportFittable,derivedparamfromtaurex.logimportLoggerfromtaurex.outputimportOutputGroupfromtaurex.output.writeableimportWriteablefromtaurex.planetimportPlanetfromtaurex.stellarimportStar
[docs]classChemistry(Fittable,Logger,Writeable,Citable):"""Skeleton for defining chemistry. *Abstract Class* Must implement methods: - :func:`activeGases` - :func:`inactiveGases` - :func:`activeGasMixProfile` - :func:`inactiveGasMixProfile` *Active* are those that are actively absorbing in the atmosphere. In technical terms they are molecules that have absorption cross-sections. You can see which molecules are able to actively absorb by doing: You can find out what molecules can actively absorb by doing: >>> avail_active_mols = OpacityCache().find_list_of_molecules() Active gases are only determined at initialization and cannot be changed during runtime. If you want to change the active gases you will need to reinitialize the chemistry class. """def__init__(self,name:str):"""Initialize chemistry. Parameters ---------- name : str Name of chemistry for logging. """Logger.__init__(self,name)Fittable.__init__(self)self.mu_profile=NoneifGlobalCache()["opacity_method"]=="ktables":self._avail_active=KTableCache().find_list_of_molecules()else:self._avail_active=OpacityCache().find_list_of_molecules()# self._avail_active = OpacityCache().find_list_of_molecules()deactive_list=GlobalCache()["deactive_molecules"]ifdeactive_listisnotNone:self._avail_active=[kforkinself._avail_activeifknotindeactive_list]
[docs]defset_star_planet(self,star:Star,planet:Planet):"""Supplies the star and planet to chemistryfor photochemistry reasons. Does nothing by default Parameters ---------- star: :class:`~taurex.data.stellar.star.Star` A star object planet: :class:`~taurex.data.planet.Planet` A planet object """pass
@propertydefavailableActive(self)->t.List[str]:# noqa: N802"""Returns a list of available actively absorbing molecules. Returns ------- molecules: :obj:`list` Actively absorbing molecules """returnself._avail_active@propertydefactiveGases(self)->t.List[str]:# noqa: N802"""Actively absorbing gases. **Requires implementation** Should return a list of molecule names Returns ------- active : :obj:`list` List of active gases """raiseNotImplementedError@propertydefinactiveGases(self)->t.List[str]:# noqa: N802"""Non absorbing gases. **Requires implementation** Should return a list of molecule names Returns ------- inactive : :obj:`list` List of inactive gases """raiseNotImplementedError
[docs]definitialize_chemistry(self,nlayers:int,temperature_profile:npt.NDArray[np.float64],pressure_profile:npt.NDArray[np.float64],altitude_profile:t.Optional[npt.NDArray[np.float64]]=None,)->None:"""Initialize the profile. Parameters ----------- nlayers : int number of layers temperature_profile : np.ndarray temperature profile pressure_profile : np.ndarray pressure profile altitude_profile : np.ndarray , optional altitude profile, deprecated """pass
@propertydefactiveGasMixProfile(self)->npt.NDArray[np.float64]:# noqa: N802"""Mix profile of actively absorbing gases. **Requires implementation** Should return profiles of shape ``(nactivegases,nlayers)``. Active refers to gases that are actively absorbing in the atmosphere. Another way to put it these are gases where molecular cross-sections are used. """raiseNotImplementedError@propertydefinactiveGasMixProfile(self)->npt.NDArray[np.float64]:# noqa: N802"""Mixing profile of non absorbing gases. **Requires implementation** Should return profiles of shape ``(ninactivegases,nlayers)``. """raiseNotImplementedError@propertydefmuProfile(self)->npt.NDArray[np.float64]:# noqa: N802"""Molecular weight for each layer of atmosphere in kg Returns ------- mix_profile : :obj:`array` """ifself.mu_profileisNone:self.compute_mu_profile(None)returnself.mu_profile
[docs]defget_gas_mix_profile(self,gas_name:str)->npt.NDArray[np.float64]:"""Returns the mix profile of a particular gas Parameters ---------- gas_name : str Name of gas Returns ------- mixprofile : :obj:`array` Mix profile of gas with shape ``(nlayer)`` """ifgas_nameinself.activeGases:idx=self.activeGases.index(gas_name)returnself.activeGasMixProfile[idx]elifgas_nameinself.inactiveGases:idx=self.inactiveGases.index(gas_name)returnself.inactiveGasMixProfile[idx]else:raiseKeyError
[docs]defcompute_mu_profile(self,nlayers:t.Optional[int]=None)->None:"""Computes molecular weight of atmosphere for each layer Parameters ---------- nlayers: int Number of layers, deprecated """active=[]inactive=[]ifself.activeGasMixProfileisnotNone:active=[mix*self.get_molecular_mass(gasname)formix,gasnameinzip(self.activeGasMixProfile,self.activeGases)]ifself.inactiveGasMixProfileisnotNone:inactive=[mix*self.get_molecular_mass(gasname)formix,gasnameinzip(self.inactiveGasMixProfile,self.inactiveGases)]total=active+inactiveifnottotal:raiseValueError("No gases or chemical profile in atmosphere")self.mu_profile=np.sum(total,axis=0)
@propertydefgases(self)->t.List[str]:"""Total list of gases in atmosphere"""returnself.activeGases+self.inactiveGases@propertydefmixProfile(self)->npt.NDArray[np.float64]:# noqa: N802returnnp.concatenate((self.activeGasMixProfile,self.inactiveGasMixProfile))@derivedparam(param_name="mu",param_latex=r"$\mu$",compute=True)defmu(self)->float:"""Mean molecular weight at surface (amu)."""fromtaurex.constantsimportAMUreturnself.muProfile[0]/AMU
[docs]defwrite(self,output:OutputGroup)->OutputGroup:"""Writes chemistry class and arguments to file. Parameters ---------- output: :class:`~taurex.output.output.Output` """gas_entry=output.create_group("Chemistry")gas_entry.write_string("chemistry_type",self.__class__.__name__)gas_entry.write_string_array("active_gases",self.activeGases)gas_entry.write_string_array("inactive_gases",self.inactiveGases)ifself.hasCondensates:gas_entry.write_string_array("condensates",self.condensates)returngas_entry
@propertydefcondensates(self)->t.List[str]:""" Returns a list of condensates in the atmosphere. Returns ------- active : :obj:`list` List of condensates """return[]@propertydefhasCondensates(self)->bool:# noqa: N802"""Returns True if there are condensates in the atmosphere."""returnlen(self.condensates)>0@propertydefcondensateMixProfile(self)->npt.NDArray[np.float64]:# noqa: N802"""Get condensate mix profile. **Requires implementation** Should return profiles of shape ``(ncondensates,nlayers)``. """iflen(self.condensates)==0:returnNoneelse:raiseNotImplementedError
[docs]defget_condensate_mix_profile(self,condensate_name:str)->npt.NDArray[np.float64]:"""Returns the mix profile of a particular condensate. Parameters ---------- condensate_name : str Name of condensate Returns ------- mixprofile : :obj:`array` Mix profile of condensate with shape ``(nlayer)`` """ifcondensate_nameinself.condensates:index=self.condensates.index(condensate_name)returnself.condensateMixProfile[index]else:raiseKeyError(f"Condensate {condensate_name} not found in chemistry")
[docs]defget_molecular_mass(self,molecule:str)->float:"""Returns the molecular mass of a molecule."""fromtaurex.utilimportget_molecular_weightreturnget_molecular_weight(molecule)
[docs]@classmethoddefinput_keywords(cls)->t.Tuple[str,...]:"""Input keywords for chemistry class."""raiseNotImplementedError