1# This file is part of Cantera. See License.txt in the top-level directory or 2# at https://cantera.org/license.txt for license and copyright information. 3 4cdef extern from "cantera/thermo/speciesThermoTypes.h" namespace "Cantera": 5 cdef int SPECIES_THERMO_CONSTANT_CP "CONSTANT_CP" 6 cdef int SPECIES_THERMO_NASA2 "NASA2" 7 cdef int SPECIES_THERMO_SHOMATE2 "SHOMATE2" 8 cdef int SPECIES_THERMO_NASA9MULTITEMP "NASA9MULTITEMP" 9 cdef int SPECIES_THERMO_MU0_INTERP "MU0_INTERP" 10 11 12cdef class SpeciesThermo: 13 """ 14 Base class for representing the reference-state thermodynamic properties of 15 a pure species. These properties are a function of temperature. Derived 16 classes implement a parameterization of this temperature dependence. This is 17 a wrapper for the C++ class :ct:`SpeciesThermoInterpType`. 18 19 :param T_low: 20 The minimum temperature [K] at which the parameterization is valid 21 :param T_high: 22 The maximum temperature [K] at which the parameterization is valid 23 :param P_ref: 24 The reference pressure [Pa] for the parameterization 25 :param coeffs: 26 An array of coefficients for the parameterization. The length of this 27 array and the meaning of each element depends on the specific 28 parameterization. 29 """ 30 def __cinit__(self, T_low=None, T_high=None, P_ref=None, coeffs=None, *args, 31 init=True, **kwargs): 32 if not init: 33 return 34 35 if not self._check_n_coeffs(len(coeffs)): 36 raise ValueError("Coefficient array has incorrect length") 37 cdef np.ndarray[np.double_t, ndim=1] data = np.ascontiguousarray( 38 coeffs, dtype=np.double) 39 self._spthermo.reset(CxxNewSpeciesThermo(self.derived_type, T_low, 40 T_high, P_ref, &data[0])) 41 self.spthermo = self._spthermo.get() 42 43 cdef _assign(self, shared_ptr[CxxSpeciesThermo] other): 44 self._spthermo = other 45 self.spthermo = self._spthermo.get() 46 47 property min_temp: 48 """ Minimum temperature [K] at which the parameterization is valid.""" 49 def __get__(self): 50 return self.spthermo.minTemp() 51 52 property max_temp: 53 """ Maximum temperature [K] at which the parameterization is valid.""" 54 def __get__(self): 55 return self.spthermo.maxTemp() 56 57 property reference_pressure: 58 """ Reference pressure [Pa] for the parameterization.""" 59 def __get__(self): 60 return self.spthermo.refPressure() 61 62 property n_coeffs: 63 """ Number of parameters for the parameterization.""" 64 def __get__(self): 65 return self.spthermo.nCoeffs() 66 67 property coeffs: 68 """ 69 Array of coefficients for the parameterization. The length of this 70 array and the meaning of each element depends on the specific 71 parameterization. 72 """ 73 def __get__(self): 74 cdef size_t index = 0 75 cdef int thermo_type = 0 76 cdef double T_low = 0, T_high = 0, P_ref = 0 77 cdef np.ndarray[np.double_t, ndim=1] data = np.empty(self.n_coeffs) 78 self.spthermo.reportParameters(index, thermo_type, T_low, 79 T_high, P_ref, &data[0]) 80 return data 81 82 def _check_n_coeffs(self, n): 83 """ 84 Check whether number of coefficients is compatible with a given 85 parameterization prior to instantiation of the underlying C++ object. 86 """ 87 raise NotImplementedError('Needs to be overloaded') 88 89 property input_data: 90 def __get__(self): 91 return anymap_to_dict(self.spthermo.parameters(True)) 92 93 def update_user_data(self, data): 94 """ 95 Add the contents of the provided `dict` as additional fields when generating 96 YAML phase definition files with `Solution.write_yaml` or in the data returned 97 by `input_data`. Existing keys with matching names are overwritten. 98 """ 99 self.spthermo.input().update(dict_to_anymap(data), False) 100 101 def clear_user_data(self): 102 """ 103 Clear all saved input data, so that the data given by `input_data` or 104 `Solution.write_yaml` will only include values generated by Cantera based on 105 the current object state. 106 """ 107 self.spthermo.input().clear() 108 109 def cp(self, T): 110 """ 111 Molar heat capacity at constant pressure [J/kmol/K] at temperature *T*. 112 """ 113 cdef double cp_r, h_rt, s_r 114 self.spthermo.updatePropertiesTemp(T, &cp_r, &h_rt, &s_r) 115 return cp_r * gas_constant 116 117 def h(self, T): 118 """ Molar enthalpy [J/kmol] at temperature *T* """ 119 cdef double cp_r, h_rt, s_r 120 self.spthermo.updatePropertiesTemp(T, &cp_r, &h_rt, &s_r) 121 return h_rt * gas_constant * T 122 123 def s(self, T): 124 """ Molar entropy [J/kmol/K] at temperature *T* """ 125 cdef double cp_r, h_rt, s_r 126 self.spthermo.updatePropertiesTemp(T, &cp_r, &h_rt, &s_r) 127 return s_r * gas_constant 128 129 130cdef class ConstantCp(SpeciesThermo): 131 r""" 132 Thermodynamic properties for a species that has a constant specific heat 133 capacity. This is a wrapper for the C++ class :ct:`ConstCpPoly`. 134 135 :param coeffs: 136 An array of 4 elements: 137 138 - `coeffs[0]` = :math:`T_0` [K] 139 - `coeffs[1]` = :math:`H^o(T_0, p_{ref})` [J/kmol] 140 - `coeffs[2]` = :math:`S^o(T_0, p_{ref})` [J/kmol-K] 141 - `coeffs[3]` = :math:`c_p^o(T_0, p_{ref})` [J/kmol-K] 142 """ 143 derived_type = SPECIES_THERMO_CONSTANT_CP 144 145 def _check_n_coeffs(self, n): 146 return n == 4 147 148 149cdef class Mu0Poly(SpeciesThermo): 150 """ 151 Thermodynamic properties for a species which is parameterized using an 152 interpolation of the Gibbs free energy based on a piecewise constant heat 153 capacity approximation. This is a wrapper for the C++ class :ct:`Mu0Poly`. 154 155 :param coeffs: 156 An array of 2+2*npoints elements, in the following order: 157 158 - `coeffs[0]`: number of points (integer) 159 - `coeffs[1]`: h^o(298.15 K) [J/kmol] 160 - `coeffs[2]`: T_1 [Kelvin] 161 - `coeffs[3]`: \mu^o(T_1) [J/kmol] 162 - `coeffs[4]`: T_2 [Kelvin] 163 - `coeffs[5]`: \mu^o(T_2) [J/kmol] 164 - ... 165 """ 166 derived_type = SPECIES_THERMO_MU0_INTERP 167 168 def _check_n_coeffs(self, n): 169 return n > 3 and n % 2 == 0 170 171 172cdef class NasaPoly2(SpeciesThermo): 173 """ 174 Thermodynamic properties for a species which is parameterized using the 175 7-coefficient NASA polynomial form in two temperature ranges. This is a 176 wrapper for the C++ class :ct:`NasaPoly2`. 177 178 :param coeffs: 179 An array of 15 elements, in the following order: 180 181 - `coeffs[0]`: The mid-point temperature [K] between the two 182 parameterizations 183 - `coeffs[1:8]`: The 7 coefficients of the high-temperature 184 parameterization 185 - `coeffs[8:15]`: The 7 coefficients of the low-temperature 186 parameterization 187 188 This is the coefficient order used in the standard fixed-format NASA 189 input files. 190 """ 191 derived_type = SPECIES_THERMO_NASA2 192 193 def _check_n_coeffs(self, n): 194 return n == 15 195 196 197cdef class Nasa9PolyMultiTempRegion(SpeciesThermo): 198 """ 199 Thermodynamic properties for a species which is parameterized using the 200 9-coefficient NASA polynomial form encompassing multiple temperature ranges. 201 This is a wrapper for the C++ class :ct:`Nasa9PolyMultiTempRegion`. 202 203 :param coeffs: 204 An array of 1 + 11*`nzones` elements, in the following order: 205 206 - `coeffs[0]`: Number of zones (`nzones`) 207 - `coeffs[1 + 11*zone]`: minimum temperature within zone 208 - `coeffs[2 + 11*zone]`: maximum temperature within zone 209 - `coeffs[3:11 + 11*zone]`: 9 coefficients of the parameterization 210 211 where `zone` runs from zero to `nzones`-1. 212 """ 213 derived_type = SPECIES_THERMO_NASA9MULTITEMP 214 215 def _check_n_coeffs(self, n): 216 return n > 11 and ((n - 1) % 11) == 0 217 218 219cdef class ShomatePoly2(SpeciesThermo): 220 """ 221 Thermodynamic properties for a species which is parameterized using the 222 Shomate equation in two temperature ranges. This is a wrapper for the C++ 223 class :ct:`ShomatePoly2`. 224 225 :param coeffs: 226 An array of 15 elements, in the following order: 227 228 - `coeffs[0]`: The mid-point temperature [K] between the two 229 parameterizations 230 - `coeffs[1:8]`: The 7 coefficients of the low-temperature 231 parameterization 232 - `coeffs[8:15]`: The 7 coefficients of the high-temperature 233 parameterization 234 235 These coefficients should be provided in their customary units (i.e. 236 such that :math:`c_p^o` is in J/gmol-K and :math:`H^o` is in kJ/gmol, 237 as in the NIST Chemistry WebBook). 238 """ 239 derived_type = SPECIES_THERMO_SHOMATE2 240 241 def _check_n_coeffs(self, n): 242 return n == 15 243 244 245cdef wrapSpeciesThermo(shared_ptr[CxxSpeciesThermo] spthermo): 246 """ 247 Wrap a C++ SpeciesThermoInterpType object with a Python object of the 248 correct derived type. 249 """ 250 cdef int thermo_type = spthermo.get().reportType() 251 252 if thermo_type == SPECIES_THERMO_NASA2: 253 st = NasaPoly2(init=False) 254 elif thermo_type == SPECIES_THERMO_NASA9MULTITEMP: 255 st = Nasa9PolyMultiTempRegion(init=False) 256 elif thermo_type == SPECIES_THERMO_CONSTANT_CP: 257 st = ConstantCp(init=False) 258 elif thermo_type == SPECIES_THERMO_MU0_INTERP: 259 st = Mu0Poly(init=False) 260 elif thermo_type == SPECIES_THERMO_SHOMATE2: 261 st = ShomatePoly2(init=False) 262 else: 263 st = SpeciesThermo() 264 265 st._assign(spthermo) 266 return st 267