[Thermo] address discussion and review comments

* rename C++ object to 'Solution' (from 'SolutionBase')
* remove 'phaseID' from 'Solution' ('id' remains assigned to 'Phase')
* remove 'type' from C++ object (no polymorphism anticipated)
* assign 'name' to 'Solution' (link back from 'Phase' until deprecated)
* clarify 'phase' as 'phase_id' in Python interface
* address various feedback in review comments
This commit is contained in:
Ingmar Schoegl 2019-10-08 15:00:07 -05:00 committed by Ray Speth
parent b5e4f25454
commit 5928d63746
17 changed files with 272 additions and 378 deletions

View file

@ -0,0 +1,72 @@
//! @file Solution.h
// This file is part of Cantera. See License.txt in the top-level directory or
// at https://cantera.org/license.txt for license and copyright information.
#ifndef CT_SOLUTION_H
#define CT_SOLUTION_H
#include "cantera/base/ctexceptions.h"
namespace Cantera
{
class ThermoPhase;
class Kinetics;
class Transport;
//! A container class holding managers for all pieces defining a phase
class Solution : public std::enable_shared_from_this<Solution>
{
private:
Solution();
public:
~Solution() {}
Solution(const Solution&) = delete;
Solution& operator=(const Solution&) = delete;
static shared_ptr<Solution> create() {
return shared_ptr<Solution>( new Solution );
}
//! Return the name of this Solution object
std::string name() const;
//! Set the name of this Solution object
void setName(const std::string& name);
//! Set the ThermoPhase object
void setThermoPhase(shared_ptr<ThermoPhase> thermo);
//! Set the Kinetics object
void setKinetics(shared_ptr<Kinetics> kinetics);
//! Set the Transport object
void setTransport(shared_ptr<Transport> transport);
//! Accessor for the ThermoPhase object
ThermoPhase& thermo() {
return *m_thermo;
}
//! Accessor for the Kinetics object
Kinetics& kinetics() {
return *m_kinetics;
}
//! Accessor for the Transport object
Transport& transport() {
return *m_transport;
}
protected:
shared_ptr<ThermoPhase> m_thermo; //! ThermoPhase manager
shared_ptr<Kinetics> m_kinetics; //! Kinetics manager
shared_ptr<Transport> m_transport; //! Transport manager
std::string m_name; //! name of Solution object
};
}
#endif

View file

@ -1,104 +0,0 @@
//! @file SolutionBase.h
// This file is part of Cantera. See License.txt in the top-level directory or
// at https://cantera.org/license.txt for license and copyright information.
#ifndef CT_SOLUTIONBASE_H
#define CT_SOLUTIONBASE_H
#include "cantera/base/ctexceptions.h"
namespace Cantera
{
class ThermoPhase;
class Kinetics;
class Transport;
//! A container class holding managers for all pieces defining a phase
class SolutionBase : public std::enable_shared_from_this<SolutionBase>
{
public:
SolutionBase();
SolutionBase(const std::string& infile, const std::string& phasename);
~SolutionBase() {}
SolutionBase(const SolutionBase&) = delete;
SolutionBase& operator=(const SolutionBase&) = delete;
static shared_ptr<SolutionBase> create() {
return shared_ptr<SolutionBase>( new SolutionBase );
}
//! String indicating the type of the SolutionBase object. Corresponds
//! to the type of phase originally instantiated
std::string type() const;
//! Set the type of this SolutionBase object
void setType(const std::string& type);
/*! Name and phase
* Class SolutionBase references two strings that identify a SolutionBase.
* The phase is the value of the phase name in YAML (or ID attribute
* of the XML node) that is used to initialize a phase when it is read.
* The name field is also initialized to the value of the phase name
* read from the XML/YAML node.
*
* However, the name field may be changed to another value during the course
* of a calculation. For example, if a SolutionBase is located in two places,
* but has the same constitutive input, the phase of the two SolutionBases
* will be the same, but the names of the two SolutionBases need to differ.
*
* It is an error to have two phases in a single problem with the same name
* attribute. Thus, it is expected that there is a 1-1 correspondence between
* names and unique SolutionBase objects within a Cantera problem.
*/
//! Return the phase string of this SolutionBase.
std::string phase() const;
//! Set the phase string of this SolutionBase.
void setPhase(const std::string& id);
//! Return the name of this SolutionBase object
std::string name() const;
//! Set the name of this SolutionBase object
void setName(const std::string& name);
//! Generate self-documenting YAML string
virtual std::string toYAML() const;
//! Set the ThermoPhase object
void setThermoPhase(shared_ptr<ThermoPhase> thermo);
//! Set the Kinetics object
void setKinetics(shared_ptr<Kinetics> kinetics);
//! Set the Transport object
void setTransport(shared_ptr<Transport> transport);
//! Accessor for the ThermoPhase object
ThermoPhase& thermo() {
return *m_thermo;
}
//! Accessor for the Kinetics object
Kinetics& kinetics() {
return *m_kinetics;
}
//! Accessor for the Transport object
Transport& transport() {
return *m_transport;
}
protected:
shared_ptr<ThermoPhase> m_thermo; //! ThermoPhase manager
shared_ptr<Kinetics> m_kinetics; //! Kinetics manager
shared_ptr<Transport> m_transport; //! Transport manager
std::string m_type; //! type of SolutionBase object
};
}
#endif

View file

@ -19,7 +19,7 @@
namespace Cantera
{
class SolutionBase;
class Solution;
/**
* @defgroup chemkinetics Chemical Kinetics
@ -816,8 +816,8 @@ public:
void selectPhase(const doublereal* data, const thermo_t* phase,
doublereal* phase_data);
//! Set root SolutionBase holding all phase information
virtual void setRoot(std::shared_ptr<SolutionBase> root) {
//! Set root Solution holding all phase information
virtual void setRoot(std::shared_ptr<Solution> root) {
m_root = root;
}
@ -943,8 +943,8 @@ protected:
//! @see skipUndeclaredThirdBodies()
bool m_skipUndeclaredThirdBodies;
//! reference to SolutionBase
std::weak_ptr<SolutionBase> m_root;
//! reference to Solution
std::weak_ptr<Solution> m_root;
};
}

View file

@ -29,7 +29,7 @@ namespace Cantera
* support thermodynamic calculations (see \ref thermoprops).
*/
class SolutionBase;
class Solution;
//! Class Phase is the base class for phases of matter, managing the species and
//! elements in a phase, as well as the independent variables of temperature,
@ -760,8 +760,8 @@ public:
m_caseSensitiveSpecies = cflag;
}
//! Set root SolutionBase holding all phase information
virtual void setRoot(std::shared_ptr<SolutionBase> root) {
//! Set root Solution holding all phase information
virtual void setRoot(std::shared_ptr<Solution> root) {
m_root = root;
}
@ -878,8 +878,8 @@ private:
//! Entropy at 298.15 K and 1 bar of stable state pure elements (J kmol-1)
vector_fp m_entropy298;
//! reference to SolutionBase
std::weak_ptr<SolutionBase> m_root;
//! reference to Solution
std::weak_ptr<Solution> m_root;
};
}

View file

@ -74,7 +74,7 @@ const VelocityBasis VB_SPECIES_2 = 2;
const VelocityBasis VB_SPECIES_3 = 3;
//@}
class SolutionBase;
class Solution;
//! Base class for transport property managers.
/*!
@ -656,8 +656,8 @@ public:
*/
virtual void setThermo(thermo_t& thermo);
//! Set root SolutionBase holding all phase information
virtual void setRoot(std::shared_ptr<SolutionBase> root) {
//! Set root Solution holding all phase information
virtual void setRoot(std::shared_ptr<Solution> root) {
m_root = root;
}
@ -688,8 +688,8 @@ protected:
//! Defaults to the mass averaged basis = -2
int m_velocityBasis;
//! reference to SolutionBase
std::weak_ptr<SolutionBase> m_root;
//! reference to Solution
std::weak_ptr<Solution> m_root;
};
}

View file

@ -121,20 +121,16 @@ cdef extern from "cantera/thermo/Species.h" namespace "Cantera":
cdef vector[shared_ptr[CxxSpecies]] CxxGetSpecies "getSpecies" (CxxAnyValue&) except +translate_exception
cdef extern from "cantera/base/SolutionBase.h" namespace "Cantera":
cdef cppclass CxxSolutionBase "Cantera::SolutionBase":
CxxSolutionBase()
string type()
string setType(string)
string phase()
void setPhase(string)
cdef extern from "cantera/base/Solution.h" namespace "Cantera":
cdef cppclass CxxSolution "Cantera::Solution":
CxxSolution()
string name()
void setName(string)
void setThermoPhase(shared_ptr[CxxThermoPhase])
void setKinetics(shared_ptr[CxxKinetics])
void setTransport(shared_ptr[CxxTransport])
cdef shared_ptr[CxxSolutionBase] CxxNewSolutionBase "Cantera::SolutionBase::create" ()
cdef shared_ptr[CxxSolution] CxxNewSolution "Cantera::Solution::create" ()
cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera":
@ -144,6 +140,8 @@ cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera":
# miscellaneous
string type()
string report(cbool, double) except +translate_exception
string id()
void setID(string)
double minTemp() except +translate_exception
double maxTemp() except +translate_exception
double refPressure() except +translate_exception
@ -941,8 +939,8 @@ cdef class GasTransportData:
cdef _assign(self, shared_ptr[CxxTransportData] other)
cdef class _SolutionBase:
cdef shared_ptr[CxxSolutionBase] _base
cdef CxxSolutionBase* base
cdef shared_ptr[CxxSolution] _base
cdef CxxSolution* base
cdef shared_ptr[CxxThermoPhase] _thermo
cdef CxxThermoPhase* thermo
cdef shared_ptr[CxxKinetics] _kinetics

View file

@ -6,24 +6,24 @@ from collections import defaultdict as _defaultdict
_phase_counts = _defaultdict(int)
cdef class _SolutionBase:
def __cinit__(self, infile='', phase='', adjacent=(), origin=None,
def __cinit__(self, infile='', phase_id='', adjacent=(), origin=None,
source=None, yaml=None, thermo=None, species=(),
kinetics=None, reactions=(), **kwargs):
if 'phaseid' in kwargs:
if phase is not '':
if phase_id is not '':
raise AttributeError('duplicate specification of phase name')
warnings.warn("Keyword `phase` replaces `phaseid`",
warnings.warn("Keyword 'phase_id' replaces 'phaseid'",
FutureWarning)
phase = kwargs['phaseid']
phase_id = kwargs['phaseid']
if 'phases' in kwargs:
if len(adjacent)>0:
raise AttributeError(
'duplicate specification of adjacent phases')
warnings.warn("Keyword `adjacent` replaces `phases`",
warnings.warn("Keyword 'adjacent' replaces 'phases'",
FutureWarning)
adjacent = kwargs['phases']
@ -46,7 +46,7 @@ cdef class _SolutionBase:
return
# Assign base and set managers to NULL
self._base = CxxNewSolutionBase()
self._base = CxxNewSolution()
self.base = self._base.get()
self.thermo = NULL
self.kinetics = NULL
@ -54,9 +54,9 @@ cdef class _SolutionBase:
# Parse inputs
if infile.endswith('.yml') or infile.endswith('.yaml') or yaml:
self._init_yaml(infile, phase, adjacent, yaml)
self._init_yaml(infile, phase_id, adjacent, yaml)
elif infile or source:
self._init_cti_xml(infile, phase, adjacent, source)
self._init_cti_xml(infile, phase_id, adjacent, source)
elif thermo and species:
self._init_parts(thermo, species, kinetics, adjacent, reactions)
else:
@ -72,14 +72,8 @@ cdef class _SolutionBase:
if isinstance(self, Transport):
assert self.transport is not NULL
base_type = kwargs.get('base_type', None)
if base_type:
self.base.setType(stringify(base_type))
else:
raise ValueError('Missing required keyword `base_type`.')
phase_name = pystr(self.base.phase())
name = kwargs.get('name', None)
phase_name = pystr(self.thermo.id())
name = kwargs.get('name')
if name is not None:
self.name = name
elif phase_name in _phase_counts:
@ -90,49 +84,11 @@ cdef class _SolutionBase:
_phase_counts[phase_name] = 0
self.name = phase_name
property type:
"""
The type of the SolutionBase object. The type is set during object
instantiation and cannot be modified.
"""
def __get__(self):
return pystr(self.base.type())
property phase:
"""
The ID of the SolutionBase object. The phase corresponds to the
CTI/XML/YAML input file entry.
"""
def __get__(self):
return pystr(self.base.phase())
def __set__(self, phase_name):
# may consider removing/deprecating, but resetting of the phase name
# is required to associate surface kinetics (with phase name being 'gas')
self.base.setPhase(stringify(phase_name))
property ID:
"""
The ID of the SolutionBase object. The default is taken from the
CTI/XML/YAML input file.
.. deprecated:: 2.5
To be deprecated with version 2.5, and removed thereafter.
Renamed to `phase`.
"""
def __get__(self):
warnings.warn("To be removed after Cantera 2.5. "
"Use `phase` attribute instead", DeprecationWarning)
return pystr(self.base.phase())
def __set__(self, id_):
warnings.warn("To be removed after Cantera 2.5. "
"Use `phase` attribute instead", DeprecationWarning)
self.base.setPhase(stringify(id_))
property name:
"""
The name assigned to this SolutionBase object. The default is
taken from the CTI/XML/YAML input file.
The name assigned to this SolutionBase object. The default value
is based on the phase identifier in the CTI/XML/YAML input file;
a numbered suffix is added if needed to create a unique name.
"""
def __get__(self):
return pystr(self.base.name())
@ -155,7 +111,7 @@ cdef class _SolutionBase:
return thermo, kinetics, transport
def _init_yaml(self, infile, phase, adjacent, source):
def _init_yaml(self, infile, phase_id, adjacent, source):
"""
Instantiate a set of new Cantera C++ objects from a YAML
phase definition
@ -167,7 +123,7 @@ cdef class _SolutionBase:
root = AnyMapFromYamlString(stringify(source))
phaseNode = root[stringify("phases")].getMapWhere(stringify("name"),
stringify(phase))
stringify(phase_id))
# Thermo
if isinstance(self, ThermoPhase):
@ -178,19 +134,19 @@ cdef class _SolutionBase:
# Kinetics
cdef vector[CxxThermoPhase*] v
cdef _SolutionBase adj
cdef _SolutionBase phase
if isinstance(self, Kinetics):
v.push_back(self.thermo)
for adj in adjacent:
for phase in adjacent:
# adjacent bulk phases for a surface phase
v.push_back(adj.thermo)
v.push_back(phase.thermo)
self._kinetics = newKinetics(v, phaseNode, root)
self.kinetics = self._kinetics.get()
else:
self.kinetics = NULL
def _init_cti_xml(self, infile, phase, adjacent, source):
def _init_cti_xml(self, infile, phase_id, adjacent, source):
"""
Instantiate a set of new Cantera C++ objects from a CTI or XML
phase definition
@ -202,8 +158,8 @@ cdef class _SolutionBase:
# Get XML data
cdef XML_Node* phaseNode
if phase:
phaseNode = rootNode.findID(stringify(phase))
if phase_id:
phaseNode = rootNode.findID(stringify(phase_id))
else:
phaseNode = rootNode.findByName(stringify('phase'))
if phaseNode is NULL:
@ -218,13 +174,13 @@ cdef class _SolutionBase:
# Kinetics
cdef vector[CxxThermoPhase*] v
cdef _SolutionBase adj
cdef _SolutionBase phase
if isinstance(self, Kinetics):
v.push_back(self.thermo)
for adj in adjacent:
for phase in adjacent:
# adjacent bulk phases for a surface phase
v.push_back(adj.thermo)
v.push_back(phase.thermo)
self.kinetics = newKineticsMgr(deref(phaseNode), v)
self._kinetics.reset(self.kinetics)
else:
@ -246,15 +202,15 @@ cdef class _SolutionBase:
if not kinetics:
kinetics = "none"
cdef ThermoPhase adj
cdef ThermoPhase phase
cdef Reaction reaction
if isinstance(self, Kinetics):
self.kinetics = CxxNewKinetics(stringify(kinetics))
self._kinetics.reset(self.kinetics)
self.kinetics.addPhase(deref(self.thermo))
for adj in adjacent:
for phase in adjacent:
# adjacent bulk phases for a surface phase
self.kinetics.addPhase(deref(adj.thermo))
self.kinetics.addPhase(deref(phase.thermo))
self.kinetics.init()
self.kinetics.skipUndeclaredThirdBodies(True)
for reaction in reactions:

View file

@ -12,7 +12,7 @@ Usage:
[--thermo=<filename>]
[--transport=<filename>]
[--surface=<filename>]
[--phase=<phasename>]
[--phase-id=<phase-id>]
[--output=<filename>]
[--permissive]
[-d | --debug]
@ -32,7 +32,7 @@ specified as 'input' and the surface phase input file should be specified as
'surface'.
The '--permissive' option allows certain recoverable parsing errors (e.g.
duplicate transport data) to be ignored. The '--phase=<phasename>' option
duplicate transport data) to be ignored. The '--phase-id=<phase-id>' option
is used to override default phase names (i.e. 'gas').
"""
@ -2025,7 +2025,7 @@ def convert_mech(input_file, thermo_file=None, transport_file=None, surface_file
def main(argv):
longOptions = ['input=', 'thermo=', 'transport=', 'surface=', 'phase=',
longOptions = ['input=', 'thermo=', 'transport=', 'surface=', 'phase-id=',
'output=', 'permissive', 'help', 'debug', 'quiet',
'no-validate', 'id=']
@ -2059,9 +2059,9 @@ def main(argv):
if '--id' in options:
phase_name = options.get('--id', 'gas')
logging.warning("\nFutureWarning: "
"option '--id=...' is superseded by '--phase=...'")
"option '--id=...' is superseded by '--phase-id=...'")
else:
phase_name = options.get('--phase', 'gas')
phase_name = options.get('--phase-id', 'gas')
if not input_file and not thermo_file:
print('At least one of the arguments "--input=..." or "--thermo=..."'

View file

@ -31,12 +31,13 @@ class Solution(ThermoPhase, Kinetics, Transport):
gas = ct.Solution('gri30.yaml')
If an input file defines multiple phases, the *phases* entry (in YAML),
*name* (in CTI), or *id* (in XML) can be used to specify the desired
phase via the ``phase`` keyword argument of the constructor::
If an input file defines multiple phases, the corresponding key in the
*phases* map (in YAML), *name* (in CTI), or *id* (in XML) can be used
to specify the desired phase via the ``phase_id`` keyword argument of
the constructor::
gas = ct.Solution('diamond.yaml', phase='gas')
diamond = ct.Solution('diamond.yaml', phase='diamond')
gas = ct.Solution('diamond.yaml', phase_id='gas')
diamond = ct.Solution('diamond.yaml', phase_id='diamond')
The name of the `Solution` object needs to be unique and defaults to the
*phase* specified in the input file. If another object using the same
@ -85,9 +86,6 @@ class Solution(ThermoPhase, Kinetics, Transport):
"""
__slots__ = ()
def __init__(self, *args, **kwargs):
super().__init__(*args, base_type='Solution', **kwargs)
class Interface(InterfacePhase, InterfaceKinetics):
"""
@ -101,16 +99,13 @@ class Interface(InterfacePhase, InterfaceKinetics):
in reactions need to be created and then passed in as a list in the
``adjacent`` argument to the constructor::
gas = ct.Solution('diamond.yaml', phase='gas')
diamond = ct.Solution('diamond.yaml', phase='diamond')
diamond_surf = ct.Interface('diamond.yaml', phase='diamond_100',
gas = ct.Solution('diamond.yaml', phase_id='gas')
diamond = ct.Solution('diamond.yaml', phase_id='diamond')
diamond_surf = ct.Interface('diamond.yaml', phase_id='diamond_100',
adjacent=[gas, diamond])
"""
__slots__ = ('_phase_indices',)
def __init__(self, *args, **kwargs):
super().__init__(*args, base_type='Interface', **kwargs)
class DustyGas(ThermoPhase, Kinetics, DustyGasTransport):
"""
@ -121,9 +116,6 @@ class DustyGas(ThermoPhase, Kinetics, DustyGasTransport):
"""
__slots__ = ()
def __init__(self, *args, **kwargs):
super().__init__(*args, base_type='DustyGas', **kwargs)
class Quantity:
"""

View file

@ -26,11 +26,6 @@ cdef class Kinetics(_SolutionBase):
a reaction mechanism.
"""
def __init__(self, *args, **kwargs):
base_type = kwargs.pop('base_type', 'Kinetics')
kwargs['base_type'] = base_type
super().__init__(*args, **kwargs)
property kinetics_model:
"""
Return type of kinetics.
@ -376,13 +371,13 @@ cdef class InterfaceKinetics(Kinetics):
A kinetics manager for heterogeneous reaction mechanisms. The
reactions are assumed to occur at an interface between bulk phases.
"""
def __init__(self, infile='', phaseid='', phases=(), *args, **kwargs):
super().__init__(infile, phaseid, phases, *args, **kwargs)
def __init__(self, infile='', phase_id='', adjacent=(), *args, **kwargs):
super().__init__(infile, phase_id, adjacent, *args, **kwargs)
if pystr(self.kinetics.kineticsType()) not in ("Surf", "Edge"):
raise TypeError("Underlying Kinetics class is not of the correct type.")
self._phase_indices = {}
for phase in [self] + list(phases):
for phase in [self] + list(adjacent):
i = self.kinetics.phaseIndex(stringify(phase.name))
self._phase_indices[phase] = i
self._phase_indices[phase.name] = i

View file

@ -660,7 +660,7 @@ class cti2yamlTest(utilities.CanteraTest):
Path(self.test_work_dir).joinpath('ptcombust.yaml'))
ctiGas, yamlGas = self.checkConversion('ptcombust')
ctiSurf, yamlSurf = self.checkConversion('ptcombust', ct.Interface,
phase='Pt_surf', ctiphases=[ctiGas], yamlphases=[yamlGas])
phase_id='Pt_surf', ctiphases=[ctiGas], yamlphases=[yamlGas])
self.checkKinetics(ctiGas, yamlGas, [500, 1200], [1e4, 3e5])
self.checkThermo(ctiSurf, yamlSurf, [400, 800, 1600])
@ -670,16 +670,16 @@ class cti2yamlTest(utilities.CanteraTest):
cti2yaml.convert(Path(self.cantera_data).joinpath('sofc.cti'),
Path(self.test_work_dir).joinpath('sofc.yaml'))
ctiGas, yamlGas = self.checkConversion('sofc')
ctiMetal, yamlMetal = self.checkConversion('sofc', phase='metal')
ctiOxide, yamlOxide = self.checkConversion('sofc', phase='oxide_bulk')
ctiMetal, yamlMetal = self.checkConversion('sofc', phase_id='metal')
ctiOxide, yamlOxide = self.checkConversion('sofc', phase_id='oxide_bulk')
ctiMSurf, yamlMSurf = self.checkConversion('sofc', ct.Interface,
phase='metal_surface', ctiphases=[ctiGas, ctiMetal],
phase_id='metal_surface', ctiphases=[ctiGas, ctiMetal],
yamlphases=[yamlGas, yamlMetal])
ctiOSurf, yamlOSurf = self.checkConversion('sofc', ct.Interface,
phase='oxide_surface', ctiphases=[ctiGas, ctiOxide],
phase_id='oxide_surface', ctiphases=[ctiGas, ctiOxide],
yamlphases=[yamlGas, yamlOxide])
cti_tpb, yaml_tpb = self.checkConversion('sofc', ct.Interface,
phase='tpb', ctiphases=[ctiMetal, ctiMSurf, ctiOSurf],
phase_id='tpb', ctiphases=[ctiMetal, ctiMSurf, ctiOSurf],
yamlphases=[yamlMetal, yamlMSurf, yamlOSurf])
self.checkThermo(ctiMSurf, yamlMSurf, [900, 1000, 1100])
@ -694,7 +694,7 @@ class cti2yamlTest(utilities.CanteraTest):
Path(self.test_work_dir).joinpath('liquidvapor.yaml'))
for name in ['water', 'nitrogen', 'methane', 'hydrogen', 'oxygen',
'hfc134a', 'carbondioxide', 'heptane']:
ctiPhase, yamlPhase = self.checkConversion('liquidvapor', phase=name)
ctiPhase, yamlPhase = self.checkConversion('liquidvapor', phase_id=name)
self.checkThermo(ctiPhase, yamlPhase,
[1.3 * ctiPhase.min_temp, 0.7 * ctiPhase.max_temp])
@ -717,10 +717,10 @@ class cti2yamlTest(utilities.CanteraTest):
def test_diamond(self):
cti2yaml.convert(Path(self.cantera_data).joinpath('diamond.cti'),
Path(self.test_work_dir).joinpath('diamond.yaml'))
ctiGas, yamlGas = self.checkConversion('diamond', phase='gas')
ctiSolid, yamlSolid = self.checkConversion('diamond', phase='diamond')
ctiGas, yamlGas = self.checkConversion('diamond', phase_id='gas')
ctiSolid, yamlSolid = self.checkConversion('diamond', phase_id='diamond')
ctiSurf, yamlSurf = self.checkConversion('diamond',
ct.Interface, phase='diamond_100', ctiphases=[ctiGas, ctiSolid],
ct.Interface, phase_id='diamond_100', ctiphases=[ctiGas, ctiSolid],
yamlphases=[yamlGas, yamlSolid])
self.checkThermo(ctiSolid, yamlSolid, [300, 500])
self.checkThermo(ctiSurf, yamlSurf, [330, 490])
@ -730,16 +730,16 @@ class cti2yamlTest(utilities.CanteraTest):
cti2yaml.convert(Path(self.cantera_data).joinpath('lithium_ion_battery.cti'),
Path(self.test_work_dir).joinpath('lithium_ion_battery.yaml'))
name = 'lithium_ion_battery'
ctiAnode, yamlAnode = self.checkConversion(name, phase='anode')
ctiCathode, yamlCathode = self.checkConversion(name, phase='cathode')
ctiMetal, yamlMetal = self.checkConversion(name, phase='electron')
ctiElyt, yamlElyt = self.checkConversion(name, phase='electrolyte')
ctiAnode, yamlAnode = self.checkConversion(name, phase_id='anode')
ctiCathode, yamlCathode = self.checkConversion(name, phase_id='cathode')
ctiMetal, yamlMetal = self.checkConversion(name, phase_id='electron')
ctiElyt, yamlElyt = self.checkConversion(name, phase_id='electrolyte')
ctiAnodeInt, yamlAnodeInt = self.checkConversion(name,
phase='edge_anode_electrolyte',
phase_id='edge_anode_electrolyte',
ctiphases=[ctiAnode, ctiMetal, ctiElyt],
yamlphases=[yamlAnode, yamlMetal, yamlElyt])
ctiCathodeInt, yamlCathodeInt = self.checkConversion(name,
phase='edge_cathode_electrolyte',
phase_id='edge_cathode_electrolyte',
ctiphases=[ctiCathode, ctiMetal, ctiElyt],
yamlphases=[yamlCathode, yamlMetal, yamlElyt])

View file

@ -929,9 +929,9 @@ class TestConstPressureReactor(utilities.CanteraTest):
self.gas.TPX = 900, 25*ct.one_atm, 'CO:0.5, H2O:0.2'
self.gas1 = ct.Solution('gri30.xml')
self.gas1.phase = 'gas'
self.gas1.phase_id = 'gas'
self.gas2 = ct.Solution('gri30.xml')
self.gas2.phase = 'gas'
self.gas2.phase_id = 'gas'
resGas = ct.Solution('gri30.xml')
solid = ct.Solution('diamond.xml', 'diamond')

View file

@ -16,20 +16,18 @@ class TestThermoPhase(utilities.CanteraTest):
self.phase = ct.Solution('h2o2.xml')
def test_base_attributes(self):
self.assertTrue(isinstance(self.phase.type, str))
self.assertTrue(self.phase.type=='Solution')
self.assertTrue(isinstance(self.phase.name, str))
self.assertTrue(isinstance(self.phase.thermo_model, str))
self.assertTrue(isinstance(self.phase.kinetics_model, str))
self.assertTrue(isinstance(self.phase.transport_model, str))
self.assertTrue(isinstance(self.phase.composite, tuple))
self.assertTrue(len(self.phase.composite)==3)
self.assertTrue(
self.phase.composite == (self.phase.thermo_model,
self.phase.kinetics_model,
self.phase.transport_model))
self.assertIsInstance(self.phase.name, str)
self.assertIsInstance(self.phase.thermo_model, str)
self.assertIsInstance(self.phase.kinetics_model, str)
self.assertIsInstance(self.phase.transport_model, str)
self.assertIsInstance(self.phase.composite, tuple)
self.assertEqual(len(self.phase.composite), 3)
self.assertEqual(self.phase.composite,
(self.phase.thermo_model,
self.phase.kinetics_model,
self.phase.transport_model))
self.phase.name = 'spam'
self.assertTrue(self.phase.name=='spam')
self.assertEqual(self.phase.name, 'spam')
with self.assertRaises(AttributeError):
self.phase.type = 'eggs'
@ -325,30 +323,30 @@ class TestThermoPhase(utilities.CanteraTest):
self.assertIn('something', self.phase.report())
def test_phase(self):
self.assertEqual(self.phase.phase, 'ohmech')
self.assertEqual(self.phase.phase_id, 'ohmech')
warnings.simplefilter("always")
with warnings.catch_warnings(record=True) as w:
self.assertEqual(self.phase.ID, 'ohmech')
self.assertTrue(len(w) == 1)
self.assertEqual(len(w), 1)
self.assertTrue(issubclass(w[-1].category, DeprecationWarning))
self.assertTrue("To be removed after Cantera 2.5. "
in str(w[-1].message))
self.assertIn("To be removed after Cantera 2.5. ",
str(w[-1].message))
with warnings.catch_warnings(record=True) as w:
self.phase.ID = 'something'
self.assertEqual(self.phase.phase, 'something')
self.assertTrue(len(w) == 1)
self.assertEqual(self.phase.phase_id, 'something')
self.assertEqual(len(w), 1)
self.assertTrue(issubclass(w[-1].category, DeprecationWarning))
self.assertTrue("To be removed after Cantera 2.5. "
in str(w[-1].message))
self.assertIn("To be removed after Cantera 2.5. ",
str(w[-1].message))
with warnings.catch_warnings(record=True) as w:
gas = ct.Solution('h2o2.cti', phaseid='ohmech')
self.assertTrue(len(w) == 1)
self.assertEqual(len(w), 1)
self.assertTrue(issubclass(w[-1].category, FutureWarning))
self.assertTrue("Keyword `phase` replaces `phaseid`"
in str(w[-1].message))
self.assertIn("Keyword 'phase_id' replaces 'phaseid'",
str(w[-1].message))
def test_badLength(self):
X = np.zeros(5)
@ -883,7 +881,7 @@ class ImportTest(utilities.CanteraTest):
Test the various ways of creating a Solution object
"""
def check(self, gas, phase, T, P, nSpec, nElem):
self.assertEqual(gas.phase, phase)
self.assertEqual(gas.phase_id, phase)
self.assertNear(gas.T, T)
self.assertNear(gas.P, P)
self.assertEqual(gas.n_species, nSpec)
@ -1172,7 +1170,7 @@ class TestSpeciesThermo(utilities.CanteraTest):
def test_wrap(self):
st = self.gas.species('H2O').thermo
self.assertTrue(isinstance(st, ct.NasaPoly2))
self.assertIsInstance(st, ct.NasaPoly2)
for T in [300, 500, 900, 1200, 2000]:
self.gas.TP = T, 101325

View file

@ -264,8 +264,6 @@ cdef class ThermoPhase(_SolutionBase):
# The signature of this function causes warnings for Sphinx documentation
def __init__(self, *args, **kwargs):
base_type = kwargs.pop('base_type', 'ThermoPhase')
kwargs['base_type'] = base_type
super().__init__(*args, **kwargs)
if 'source' not in kwargs:
self.thermo_basis = mass_basis
@ -292,6 +290,37 @@ cdef class ThermoPhase(_SolutionBase):
def __call__(self, *args, **kwargs):
print(self.report(*args, **kwargs))
property phase_id:
"""
The identifier of the object. The default value corresponds to the
CTI/XML/YAML input file phase entry, and should remain unchanged.
"""
def __get__(self):
return pystr(self.thermo.id())
def __set__(self, phase_id):
# may consider removing/deprecating, but resetting of the phase name
# is required to associate surface kinetics (with phase name being 'gas')
self.thermo.setID(stringify(phase_id))
property ID:
"""
The identifier of the object. The default value corresponds to the
CTI/XML/YAML input file phase entry, and should remain unchanged.
.. deprecated:: 2.5
To be deprecated with version 2.5, and removed thereafter.
Renamed to `phase_ID`.
"""
def __get__(self):
warnings.warn("To be removed after Cantera 2.5. "
"Use 'phase' attribute instead", DeprecationWarning)
return pystr(self.thermo.id())
def __set__(self, id_):
warnings.warn("To be removed after Cantera 2.5. "
"Use 'phase' attribute instead", DeprecationWarning)
self.thermo.setID(stringify(id_))
property basis:
"""
Determines whether intensive thermodynamic properties are treated on a

46
src/base/Solution.cpp Normal file
View file

@ -0,0 +1,46 @@
//! @file Solution.cpp
// This file is part of Cantera. See License.txt in the top-level directory or
// at https://cantera.org/license.txt for license and copyright information.
#include "cantera/base/Solution.h"
#include "cantera/thermo/ThermoPhase.h"
#include "cantera/kinetics/Kinetics.h"
#include "cantera/transport/TransportBase.h"
namespace Cantera
{
Solution::Solution() :
m_name("<Solution_name>")
{}
std::string Solution::name() const {
return m_name;
}
void Solution::setName(const std::string& name){
m_name = name;
}
void Solution::setThermoPhase(shared_ptr<ThermoPhase> thermo) {
m_thermo = thermo;
if (m_thermo) {
m_thermo->setRoot(shared_from_this());
}
}
void Solution::setKinetics(shared_ptr<Kinetics> kinetics) {
m_kinetics = kinetics;
if (m_kinetics) {
m_kinetics->setRoot(shared_from_this());
}
}
void Solution::setTransport(shared_ptr<Transport> transport) {
m_transport = transport;
if (m_transport) {
m_transport->setRoot(shared_from_this());
}
}
}

View file

@ -1,99 +0,0 @@
//! @file SolutionBase.cpp
// This file is part of Cantera. See License.txt in the top-level directory or
// at https://cantera.org/license.txt for license and copyright information.
#include "cantera/base/SolutionBase.h"
#include "cantera/thermo/ThermoPhase.h"
#include "cantera/kinetics/Kinetics.h"
#include "cantera/transport/TransportBase.h"
namespace Cantera
{
SolutionBase::SolutionBase() :
m_thermo(nullptr),
m_kinetics(nullptr),
m_transport(nullptr),
m_type("<SolutionBase_type>")
{}
SolutionBase::SolutionBase(const std::string& infile,
const std::string& phasename) :
SolutionBase()
{
// this *may* be a spot to load all pieces of a phase
throw NotImplementedError("SolutionBase constructor from file");
}
std::string SolutionBase::type() const {
return m_type;
}
void SolutionBase::setType(const std::string& type){
m_type = type;
}
std::string SolutionBase::phase() const {
// currently managed by ThermoPhase
if (m_thermo) {
return m_thermo->id();
} else {
throw CanteraError("SolutionBase::id()", "Missing ThermoPhase.");
}
}
void SolutionBase::setPhase(const std::string& id) {
// currently managed by ThermoPhase
// note: may consider removing (but needed for association of surface
// kinetics which require the phase name "gas")
if (m_thermo) {
return m_thermo->setID(id);
} else {
throw CanteraError("SolutionBase::setID()", "Missing ThermoPhase.");
}
}
std::string SolutionBase::name() const {
// currently managed by ThermoPhase
if (m_thermo) {
return m_thermo->name();
} else {
throw CanteraError("SolutionBase::name()", "Missing ThermoPhase.");
}
}
void SolutionBase::setName(const std::string& name){
// currently managed by ThermoPhase
if (m_thermo) {
return m_thermo->setName(name);
} else {
throw CanteraError("SolutionBase::setName()", "Missing ThermoPhase.");
}
}
std::string SolutionBase::toYAML() const {
throw NotImplementedError("SolutionBase::toYAML");
}
void SolutionBase::setThermoPhase(shared_ptr<ThermoPhase> thermo) {
m_thermo = thermo;
if (m_thermo) {
m_thermo->setRoot(shared_from_this());
}
}
void SolutionBase::setKinetics(shared_ptr<Kinetics> kinetics) {
m_kinetics = kinetics;
if (m_kinetics) {
m_kinetics->setRoot(shared_from_this());
}
}
void SolutionBase::setTransport(shared_ptr<Transport> transport) {
m_transport = transport;
if (m_transport) {
m_transport->setRoot(shared_from_this());
}
}
}

View file

@ -9,6 +9,7 @@
#include "cantera/thermo/Phase.h"
#include "cantera/base/utilities.h"
#include "cantera/base/stringUtils.h"
#include "cantera/base/Solution.h"
#include "cantera/base/ctml.h"
#include "cantera/thermo/ThermoFactory.h"
@ -78,12 +79,22 @@ void Phase::setID(const std::string& id_)
std::string Phase::name() const
{
return m_name;
auto root = m_root.lock();
if (root) {
return root->name();
} else {
return m_name;
}
}
void Phase::setName(const std::string& nm)
void Phase::setName(const std::string& name)
{
m_name = nm;
auto root = m_root.lock();
if (root) {
root->setName(name);
} else {
m_name = name;
}
}
size_t Phase::nElements() const