diff --git a/include/cantera/base/Base.h b/include/cantera/base/Base.h new file mode 100644 index 000000000..4c3acea5a --- /dev/null +++ b/include/cantera/base/Base.h @@ -0,0 +1,72 @@ +//! @file Base.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_BASE_H +#define CT_BASE_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: + SolutionBase(); + SolutionBase(const std::string& infile, const std::string& phasename); + ~SolutionBase() {} + SolutionBase(const SolutionBase&) = delete; + SolutionBase& operator=(const SolutionBase&) = delete; + + //! String indicating the type of the SolutionBase object. Corresponds + //! to the type of phase originally instantiated + std::string type() const { + return m_type; + } + + //! Set the type of this SolutionBase object + void setType(const std::string& type){ + m_type = type; + } + + //! Return the name of this SolutionBase object + std::string name() const { + return m_name; + } + + //! Set the name of this SolutionBase object + void setName(const std::string& name){ + m_name = name; + } + + //! Generate self-documenting YAML string + virtual std::string toYAML() const { + throw NotImplementedError("SolutionBase::toYAML"); + } + + //! Set the ThermoPhase object + void setThermoPhase(shared_ptr thermo); + + //! Set the Kinetics object + void setKinetics(shared_ptr kinetics); + + //! Set the Transport object + void setTransport(shared_ptr transport); + +protected: + shared_ptr m_thermo; //! ThermoPhase manager + shared_ptr m_kinetics; //! Kinetics manager + shared_ptr m_transport; //! Transport manager + + std::string m_type; //! type of SolutionBase object + std::string m_name; //! name of SolutionBase object +}; + +} +#endif diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index a37104633..ff5ac7219 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -120,6 +120,19 @@ cdef extern from "cantera/thermo/Species.h" namespace "Cantera": cdef shared_ptr[CxxSpecies] CxxNewSpecies "newSpecies" (CxxAnyMap&) except +translate_exception cdef vector[shared_ptr[CxxSpecies]] CxxGetSpecies "getSpecies" (CxxAnyValue&) except +translate_exception + +cdef extern from "cantera/base/Base.h" namespace "Cantera": + cdef cppclass CxxSolutionBase "Cantera::SolutionBase": + CxxSolutionBase() + string type() + string setType(string) + string name() + void setName(string) + void setThermoPhase(shared_ptr[CxxThermoPhase]) + void setKinetics(shared_ptr[CxxKinetics]) + void setTransport(shared_ptr[CxxTransport]) + + cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera": cdef cppclass CxxThermoPhase "Cantera::ThermoPhase": CxxThermoPhase() @@ -928,6 +941,7 @@ cdef class GasTransportData: cdef _assign(self, shared_ptr[CxxTransportData] other) cdef class _SolutionBase: + cdef CxxSolutionBase* base cdef shared_ptr[CxxThermoPhase] _thermo cdef CxxThermoPhase* thermo cdef shared_ptr[CxxKinetics] _kinetics diff --git a/interfaces/cython/cantera/base.pyx b/interfaces/cython/cantera/base.pyx index f2284c1af..802b8c13f 100644 --- a/interfaces/cython/cantera/base.pyx +++ b/interfaces/cython/cantera/base.pyx @@ -1,6 +1,10 @@ # 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. +from collections import defaultdict as _defaultdict + +_phase_counts = _defaultdict(int) + cdef class _SolutionBase: def __cinit__(self, infile='', phaseid='', phases=(), origin=None, source=None, yaml=None, thermo=None, species=(), @@ -10,6 +14,7 @@ cdef class _SolutionBase: if origin is not None: other = <_SolutionBase?>origin + self.base = other.base self.thermo = other.thermo self.kinetics = other.kinetics self.transport = other.transport @@ -21,6 +26,9 @@ cdef class _SolutionBase: self._selected_species = other._selected_species.copy() return + # Assign type and unique_name during __init__ + self.base = new CxxSolutionBase() + if infile.endswith('.yml') or infile.endswith('.yaml') or yaml: self._init_yaml(infile, phaseid, phases, yaml) elif infile or source: @@ -31,6 +39,8 @@ cdef class _SolutionBase: raise ValueError("Arguments are insufficient to define a phase") # Initialization of transport is deferred to Transport.__init__ + self.base.setThermoPhase(self._thermo) + self.base.setKinetics(self._kinetics) self.transport = NULL self._selected_species = np.ndarray(0, dtype=np.integer) @@ -39,6 +49,34 @@ 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`.') + + phasename = pystr(self.thermo.name()) + name = kwargs.get('name', None) + if name is not None: + self.unique_name = name + else: + _phase_counts[phasename] += 1 + n = _phase_counts[phasename] + self.unique_name = '{0}_{1}'.format(phasename, n) + + property type: + """The type of the SolutionBase object.""" + def __get__(self): + return pystr(self.base.type()) + + property unique_name: + """The unique name of the SolutionBase object.""" + def __get__(self): + return pystr(self.base.name()) + + def __set__(self, name): + self.base.setName(stringify(name)) + def _init_yaml(self, infile, phaseid, phases, source): """ Instantiate a set of new Cantera C++ objects from a YAML diff --git a/interfaces/cython/cantera/composite.py b/interfaces/cython/cantera/composite.py index 5ab858faa..ccf937dec 100644 --- a/interfaces/cython/cantera/composite.py +++ b/interfaces/cython/cantera/composite.py @@ -69,6 +69,9 @@ class Solution(ThermoPhase, Kinetics, Transport): """ __slots__ = () + def __init__(self, *args, **kwargs): + super().__init__(*args, base_type='Solution', **kwargs) + class Interface(InterfacePhase, InterfaceKinetics): """ @@ -88,6 +91,9 @@ class Interface(InterfacePhase, InterfaceKinetics): """ __slots__ = ('_phase_indices',) + def __init__(self, *args, **kwargs): + super().__init__(*args, base_type='Interface', **kwargs) + class DustyGas(ThermoPhase, Kinetics, DustyGasTransport): """ @@ -99,6 +105,9 @@ class DustyGas(ThermoPhase, Kinetics, DustyGasTransport): """ __slots__ = () + def __init__(self, *args, **kwargs): + super().__init__(*args, base_type='DustyGas', **kwargs) + class Quantity: """ diff --git a/interfaces/cython/cantera/kinetics.pyx b/interfaces/cython/cantera/kinetics.pyx index 44ae9281f..89e7544c9 100644 --- a/interfaces/cython/cantera/kinetics.pyx +++ b/interfaces/cython/cantera/kinetics.pyx @@ -26,6 +26,11 @@ 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 n_total_species: """ Total number of species in all phases participating in the kinetics diff --git a/interfaces/cython/cantera/thermo.pyx b/interfaces/cython/cantera/thermo.pyx index 5857ccf11..b61b3d624 100644 --- a/interfaces/cython/cantera/thermo.pyx +++ b/interfaces/cython/cantera/thermo.pyx @@ -264,6 +264,8 @@ 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 diff --git a/interfaces/cython/cantera/transport.pyx b/interfaces/cython/cantera/transport.pyx index b6235b7de..82fa37aca 100644 --- a/interfaces/cython/cantera/transport.pyx +++ b/interfaces/cython/cantera/transport.pyx @@ -144,7 +144,11 @@ cdef class Transport(_SolutionBase): model = 'None' self.transport = newTransportMgr(stringify(model), self.thermo) self._transport.reset(self.transport) + + base_type = kwargs.pop('base_type', 'Transport') + kwargs['base_type'] = base_type super().__init__(*args, **kwargs) + self.base.setTransport(self._transport) property transport_model: """ diff --git a/src/base/Base.cpp b/src/base/Base.cpp new file mode 100644 index 000000000..367b5659d --- /dev/null +++ b/src/base/Base.cpp @@ -0,0 +1,38 @@ +//! @file Base.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/Base.h" + +namespace Cantera +{ + +SolutionBase::SolutionBase() : + m_thermo(nullptr), + m_kinetics(nullptr), + m_transport(nullptr), + m_type(""), + m_name("") +{} + +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"); +} + +void SolutionBase::setThermoPhase(shared_ptr thermo) { + m_thermo = thermo; +} + +void SolutionBase::setKinetics(shared_ptr kinetics) { + m_kinetics = kinetics; +} + +void SolutionBase::setTransport(shared_ptr transport) { + m_transport = transport; +} +}