I am running a parameter fitting simulation (in python) where I need to update the value of the standard enthalpy and entropy for Cantera species (in an ideal solution phase). The xml species description looks something like this:
<species name="DummySpecies">
<atomArray> C:1 H:1</atomArray>
<thermo>
<const_cp Tmax="300.0" Tmin="298.0">
<t0 units="K">298.15</t0>
<h0 units="J/mol">0.0</h0>
<s0 units="J/mol/K"> 0.0 </s0>
<cp0 units="J/mol/K"> 0.0</cp0>
</const_cp>
</thermo>
<standardState model="constant_incompressible">
<molarVolume> 0.0 </molarVolume>
</standardState>
</species>
And I am interested in updating the values of ‘h0’ and ‘s0’. To run this simulation, I load the phase data from xml and use it to create a mixture object like so:
phase = cantera.import_phases(XmlFile,['Phase Names'])
mixture = cantera.Mixture(phase)
I then pass the mixture object to the fitting code that performs an iterative calculation. The issue is that at each iteration, I need to update the enthalpy and/or entropy information for the species. Currently, I write the updated values back onto the xml file, and read it again using the ‘import_phases()’ function, but this is inefficient. I tried unsuccessfully to directly update the species data, but this is not possible once the phase object has been created:
phase[phase ID].species()[Species ID].thermo.coeffs[Coefficient index for h0] = New_h0_value *********** does not work
Is there a way to update these values without first writing to, and rereading from the input xml file?
import cantera as ct
gas = ct.Solution('gri30.cti')
h2 = gas.species(0)
h2_new = ct.Species(h2.name, h2.composition, h2.charge, h2.size)
new_coeffs = h2.thermo.coeffs.copy()
new_coeffs[0] = 1
h2_new.thermo = ct.NasaPoly2(h2.thermo.min_temp, h2.thermo.max_temp, h2.thermo.reference_pressure, new_coeffs)
gas = ct.Solution(thermo='IdealGas', kinetics='GasKinetics', species=[h2_new] + gas.species()[1:], reactions=gas.reactions())
assert gas.species(0).thermo.coeffs[0] == 1
Hello Nick
Thanks a lot for your comments. I implemented the steps you suggested for my system and everything looked good until I got to the last line (gas = ct.Solution...), which threw new errors.
Case 1: Error: CanteraError thrown by getElementWeight: element not found: dummy
‘dummy’ refers to a fictitious element I created to model the inert species, dodecane, in elementz.xml. Below’s the script that throws this error:
import cantera as ct
p = ct.Solution('yesdummy.xml','PC88A_liquid')
h2 = p.species(0)
h2_new = ct.Species(h2.name, h2.composition, h2.charge, h2.size)
new_coeff = h2.thermo.coeffs.copy()
new_coeff[1] = -2350000
h2_new.thermo = ct.ConstantCp(h2.thermo.min_temp, h2.thermo.max_temp, h2.thermo.reference_pressure, new_coeff)
p = ct.Solution(thermo='IdealSolidSolution', species=[h2_new]+p.species()[1:], datasrc='elementz.xml')
Case 2: Error: CanteraError thrown by IdealSolidSolnPhase::setDensity: Density is not an independent variable
For this case, I removed the ‘dodecane’ species from the phase to temporarily get rid of the first problem, but then run into this new exception. I do not know if anyone has seen this before (I did a quick search of topics on this forum). Here’s the corresponding script:
import cantera as ct
p = ct.Solution('nodummy.xml','PC88A_liquid')
h2 = p.species(0)
h2_new = ct.Species(h2.name, h2.composition, h2.charge, h2.size)
new_coeff = p.species(0).thermo.coeffs.copy()
new_coeff[1] = -2350000
h2_new.thermo = ct.ConstantCp(h2.thermo.min_temp, h2.thermo.max_temp, h2.thermo.reference_pressure, new_coeff)
p = ct.Solution(thermo='IdealSolidSolution', species=[h2_new]+p.species()[1:])
I’ve also attached the xml files. Thanks a mil.
Nwike
Nwike,
The reason your initial attempt to modify the Species
object in place did not work is because changes to Species
objects do not take effect until the modify_species
function is called. (as noted in a recent update to the documentation). The calls to make should look something like this:
k = p.species_index(name)
S = p.species(k)
S.thermo = ct.ConstantCp(...)
p.modify_species(k, S)
I don’t really understand the purpose of introducing the “dummy” element in your other example. In any case, it is not currently possible to add elements explicitly using the Python interface — they must come from an input file, or are added automatically from the set of actual elements. Assuming the species with the dummy element is not the one you would like to change properties of, you could create the XML definition of a phase containing only that species, and then add the other species using the add_species
method of ThermoPhase
.
All of these capabilities for dynamically adding and modifying species are mostly targeted at ideal gases at the moment. If they work for anything else, it’s a happy accident. There have been some changes under the hood, such as the introduction of the ‘extra’ field that Nick noted, that will eventually provide a mechanism for supplying such properties from Python, but that is still some way off.
Regards,
Ray
Hi,
As in the case of modifying the thermo, this will not work as written. You need to take the Reaction
object, modify the rate, and then call the modify_reaction
function, as noted in the documentation.
Regards,
Ray