From b1d0d7812f80f301055996bc0743c83cce7f4bfa Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Wed, 6 Mar 2019 12:15:50 +0800 Subject: [PATCH 001/139] enable reading and storing data of electron --- include/cantera/electron/Electron.h | 55 ++++++++++++ .../cantera/electron/ElectronCrossSection.h | 60 +++++++++++++ include/cantera/electron/ElectronFactory.h | 72 +++++++++++++++ .../electron/MaxwellBoltzmannElectron.h | 25 ++++++ interfaces/cython/cantera/_cantera.pxd | 35 ++++++++ interfaces/cython/cantera/_cantera.pyx | 1 + interfaces/cython/cantera/base.pyx | 35 +++++++- interfaces/cython/cantera/composite.py | 4 + interfaces/cython/cantera/electron.pyx | 87 +++++++++++++++++++ src/SConscript | 1 + src/electron/Electron.cpp | 64 ++++++++++++++ src/electron/ElectronCrossSection.cpp | 85 ++++++++++++++++++ src/electron/ElectronFactory.cpp | 46 ++++++++++ src/electron/MaxwellBoltzmannElectron.cpp | 14 +++ 14 files changed, 583 insertions(+), 1 deletion(-) create mode 100644 include/cantera/electron/Electron.h create mode 100644 include/cantera/electron/ElectronCrossSection.h create mode 100644 include/cantera/electron/ElectronFactory.h create mode 100644 include/cantera/electron/MaxwellBoltzmannElectron.h create mode 100644 interfaces/cython/cantera/electron.pyx create mode 100644 src/electron/Electron.cpp create mode 100644 src/electron/ElectronCrossSection.cpp create mode 100644 src/electron/ElectronFactory.cpp create mode 100644 src/electron/MaxwellBoltzmannElectron.cpp diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h new file mode 100644 index 00000000000..a074c083e72 --- /dev/null +++ b/include/cantera/electron/Electron.h @@ -0,0 +1,55 @@ +/** + * @file Electron.h + * Header file for class Electron. + */ + +// This file is part of Cantera. See License.txt in the top-level directory or +// at http://www.cantera.org/license.txt for license and copyright information. + +#ifndef CT_ELECTRON_H +#define CT_ELECTRON_H + +#include "cantera/electron/ElectronCrossSection.h" +#include "cantera/base/ctexceptions.h" +#include "cantera/base/ValueCache.h" +#include + +namespace Cantera +{ + +class Electron +{ +public: + Electron(); //!< Default constructor. + + virtual ~Electron(); + + // Electron objects are not copyable or assignable + Electron(const Electron&) = delete; + Electron& operator=(const Electron&) = delete; + + //! Add a electron corss section to this Electron. Returns `true` if the electron cross section was + //! successfully added, or `false` if the electron cross section was ignored. + virtual bool addElectronCrossSection(shared_ptr ecs); + + size_t nElectronCrossSections() const; + + std::vector m_electronCrossSectionTargets; + std::vector m_electronCrossSectionKinds; + vector_fp m_massRatios; + std::vector> m_electronCrossSectionFunctions; + +protected: + //! Cached for saved calculations within each Electron. + /*! + * For more information on how to use this, see examples within the source + * code and documentation for this within ValueCache class itself. + */ + mutable ValueCache m_cache; + + size_t m_ncs; +}; + +} + +#endif diff --git a/include/cantera/electron/ElectronCrossSection.h b/include/cantera/electron/ElectronCrossSection.h new file mode 100644 index 00000000000..14779e2a151 --- /dev/null +++ b/include/cantera/electron/ElectronCrossSection.h @@ -0,0 +1,60 @@ +//! @file Species.h Declaration for class Cantera::Species. + +// This file is part of Cantera. See License.txt in the top-level directory or +// at http://www.cantera.org/license.txt for license and copyright information. + +#ifndef CT_ELECTRONCROSSSECTION_H +#define CT_ELECTRONCROSSSECTION_H + +#include "cantera/base/ct_defs.h" +#include "cantera/base/AnyMap.h" + +namespace Cantera +{ + +//! Contains data about the cross sections of electron collision +/*! + * This class stores the data about cross sections of electron collision + * which may be needed to add it to a Transport object. + */ +class ElectronCrossSection +{ +public: + ElectronCrossSection(); + + //! Constructor + ElectronCrossSection(const std::string& kind, const std::string& target, + const std::vector> data, double mass_ratio=Undef); + + //! ElectronCrossSection objects are not copyable or assignable + ElectronCrossSection(const ElectronCrossSection&) = delete; + ElectronCrossSection& operator=(const ElectronCrossSection& other) = delete; + ~ElectronCrossSection(); + + void validate(); + + //! The name of the kind of electron collision + std::string kind; + + //! The name of the target of electron collision + std::string target; + + //! Data + std::vector data; + + //! The mass ratio of molecule to electron + double mass_ratio; + + //! Extra data used for specific models + AnyMap extra; +}; + +//! Create a new ElectronCrossSection object from an AnyMap specification +unique_ptr newElectronCrossSection(const AnyMap& node); + +//! Generate ElectronCrossSection objects for each item (an AnyMap) in `items`. +std::vector> getElectronCrossSection(const AnyValue& items); + +} + +#endif diff --git a/include/cantera/electron/ElectronFactory.h b/include/cantera/electron/ElectronFactory.h new file mode 100644 index 00000000000..c4d5c30a7e2 --- /dev/null +++ b/include/cantera/electron/ElectronFactory.h @@ -0,0 +1,72 @@ +/** + * @file ElectronFactory.h + * Headers for the factory class that can create known Electron objects + */ + +// This file is part of Cantera. See License.txt in the top-level directory or +// at http://www.cantera.org/license.txt for license and copyright information. + +#ifndef ELECTRON_FACTORY_H +#define ELECTRON_FACTORY_H + +#include "cantera/electron/Electron.h" +#include "cantera/base/FactoryBase.h" + +namespace Cantera +{ +//! Factory class for electron data managers. +/*! + * This class keeps a list of the known Electron classes, and is + * used to create new instances of these classes. + */ +class ElectronFactory : public Factory +{ +public: + //! Static function that creates a static instance of the factory. + static ElectronFactory* factory() { + std::unique_lock lock(electron_mutex); + if (!s_factory) { + s_factory = new ElectronFactory; + } + return s_factory; + } + + //! delete the static instance of this factory + virtual void deleteFactory() { + std::unique_lock lock(electron_mutex); + delete s_factory; + s_factory = 0; + } + + virtual Electron* newElectron(const std::string& model); + +private: + //! static member of a single instance + static ElectronFactory* s_factory; + + //! Private constructors prevents usage + ElectronFactory(); + + //! Decl for locking mutex for thermo factory singleton + static std::mutex electron_mutex; +}; + +//! Create a new electron manager instance. +/*! + * @param model String to look up the model against + * @returns a pointer to a new Electron instance matching the model string. + * Returns NULL if something went wrong. Throws an exception + * UnknownThermoPhaseModel if the string wasn't matched. + */ +inline Electron* newElectron(const std::string& model) +{ + return ElectronFactory::factory()->create(model); +} + +unique_ptr newElectron(const AnyMap& rootNode=AnyMap()); + +void addElectronCrossSections(Electron& electron, const AnyValue& cross_section); + +} + +#endif diff --git a/include/cantera/electron/MaxwellBoltzmannElectron.h b/include/cantera/electron/MaxwellBoltzmannElectron.h new file mode 100644 index 00000000000..30c6f4f98fd --- /dev/null +++ b/include/cantera/electron/MaxwellBoltzmannElectron.h @@ -0,0 +1,25 @@ +/** + * @file MaxwellBoltzmannElectron.h + * Header file for class MaxwellBoltzmannElectron. + */ + +// This file is part of Cantera. See License.txt in the top-level directory or +// at http://www.cantera.org/license.txt for license and copyright information. + +#ifndef CT_MAXWELLBOLTZMANNELECTRON_H +#define CT_MAXWELLBOLTZMANNELECTRON_H + +#include "cantera/electron/Electron.h" + +namespace Cantera +{ + +class MaxwellBoltzmannElectron: public Electron +{ +public: + MaxwellBoltzmannElectron(); //!< Default constructor. +}; + +} + +#endif diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 26ff56dcd3c..208eea86564 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -139,6 +139,26 @@ cdef extern from "cantera/base/Solution.h" namespace "Cantera": cdef shared_ptr[CxxSolution] CxxNewSolution "Cantera::Solution::create" () +cdef extern from "cantera/electron/ElectronCrossSection.h" namespace "Cantera": + cdef cppclass CxxElectronCrossSection "Cantera::ElectronCrossSection": + CxxElectronCrossSection() + CxxElectronCrossSection(string, string, double, vector[double]) + + string kind + string target + double mass_ratio + vector[vector[double]] data + + cdef shared_ptr[CxxElectronCrossSection] CxxNewElectronCrossSection "newElectronCrossSection" (CxxAnyMap&) except +translate_exception + cdef vector[shared_ptr[CxxElectronCrossSection]] CxxGetElectronCrossSection "getElectronCrossSection" (CxxAnyValue&) except +translate_exception + +cdef extern from "cantera/electron/Electron.h" namespace "Cantera": + cdef cppclass CxxElectron "Cantera::Electron": + CxxElectron() + + # initialization + cbool addElectronCrossSection(shared_ptr[CxxElectronCrossSection]) except +translate_exception + cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera": ctypedef enum ThermoBasis: mass "Cantera::ThermoBasis::mass", @@ -690,6 +710,10 @@ cdef extern from "cantera/thermo/ThermoFactory.h" namespace "Cantera": cdef shared_ptr[CxxThermoPhase] newPhase(CxxAnyMap&, CxxAnyMap&) except +translate_exception cdef CxxThermoPhase* newThermoPhase(string) except +translate_exception +cdef extern from "cantera/electron/ElectronFactory.h" namespace "Cantera": + cdef shared_ptr[CxxElectron] newElectron(CxxAnyMap&) except +translate_exception + cdef CxxElectron* newElectron(string) except +translate_exception + cdef extern from "cantera/kinetics/KineticsFactory.h" namespace "Cantera": cdef CxxKinetics* newKineticsMgr(XML_Node&, vector[CxxThermoPhase*]) except +translate_exception cdef shared_ptr[CxxKinetics] newKinetics(vector[CxxThermoPhase*], CxxAnyMap&, CxxAnyMap&) except +translate_exception @@ -961,6 +985,12 @@ ctypedef void (*transportMethod2d)(CxxTransport*, size_t, double*) except +trans ctypedef void (*kineticsMethod1d)(CxxKinetics*, double*) except +translate_exception # classes +cdef class ElectronCrossSection: + cdef shared_ptr[CxxElectronCrossSection] _electron_cross_section + cdef CxxElectronCrossSection* electron_cross_section + + cdef _assign(self, shared_ptr[CxxElectronCrossSection] other) + cdef class Species: cdef shared_ptr[CxxSpecies] _species cdef CxxSpecies* species @@ -987,6 +1017,8 @@ cdef class _SolutionBase: cdef CxxKinetics* kinetics cdef shared_ptr[CxxTransport] _transport cdef CxxTransport* transport + cdef shared_ptr[CxxElectron] _electron + cdef CxxElectron* electron cdef int thermo_basis cdef np.ndarray _selected_species cdef object parent @@ -1019,6 +1051,9 @@ cdef class Falloff: cdef class Kinetics(_SolutionBase): pass +cdef class Electron(_SolutionBase): + pass + cdef class InterfaceKinetics(Kinetics): pass diff --git a/interfaces/cython/cantera/_cantera.pyx b/interfaces/cython/cantera/_cantera.pyx index 98ec9fd7e83..836a91f7338 100644 --- a/interfaces/cython/cantera/_cantera.pyx +++ b/interfaces/cython/cantera/_cantera.pyx @@ -19,6 +19,7 @@ include "thermo.pyx" include "reaction.pyx" include "kinetics.pyx" include "transport.pyx" +include "electron.pyx" include "mixture.pyx" include "reactor.pyx" diff --git a/interfaces/cython/cantera/base.pyx b/interfaces/cython/cantera/base.pyx index d147980dcec..4c2b75acd1a 100644 --- a/interfaces/cython/cantera/base.pyx +++ b/interfaces/cython/cantera/base.pyx @@ -6,7 +6,8 @@ from collections import defaultdict as _defaultdict cdef class _SolutionBase: def __cinit__(self, infile='', name='', adjacent=(), origin=None, source=None, yaml=None, thermo=None, species=(), - kinetics=None, reactions=(), **kwargs): + kinetics=None, reactions=(), electron=None, + electron_cross_sections=(), efile=None, **kwargs): if 'phaseid' in kwargs: if name is not '': @@ -36,9 +37,11 @@ cdef class _SolutionBase: self.transport = other.transport self._base = other._base self._source = other._source + self.electron = other.electron self._thermo = other._thermo self._kinetics = other._kinetics self._transport = other._transport + self._electron = other._electron self.thermo_basis = other.thermo_basis self._selected_species = other._selected_species.copy() @@ -66,6 +69,13 @@ cdef class _SolutionBase: self.base.setThermo(self._thermo) self.base.setKinetics(self._kinetics) + # Initiate electron + if efile: + self._init_efile(efile) + + if electron_cross_sections: + self._init_electron(electron, electron_cross_sections) + self._selected_species = np.ndarray(0, dtype=np.uint64) def __init__(self, *args, **kwargs): @@ -223,6 +233,29 @@ cdef class _SolutionBase: for reaction in reactions: self.kinetics.addReaction(reaction._reaction) + def _init_efile(self, efile): + """ + Instantiate a new Electron object via a yaml file. + """ + cdef CxxAnyMap root + root = AnyMapFromYamlFile(stringify(efile)) + + if isinstance(self, Electron): + self._electron = newElectron(root) + self.electron = self._electron.get() + else: + self.electron = NULL + + def _init_electron(self, electron, electron_cross_sections): + """ + Instantiate a new Electron object. + """ + cdef ElectronCrossSection ecs + if isinstance(self, Electron): + self.electron = newElectron(stringify(electron)) + self._electron.reset(self.electron) + for ecs in electron_cross_sections: + self.electron.addElectronCrossSection(ecs._electron_cross_section) def __getitem__(self, selection): copy = self.__class__(origin=self) diff --git a/interfaces/cython/cantera/composite.py b/interfaces/cython/cantera/composite.py index b614bf67cc9..dbe1c3708b8 100644 --- a/interfaces/cython/cantera/composite.py +++ b/interfaces/cython/cantera/composite.py @@ -98,6 +98,10 @@ class Solution(ThermoPhase, Kinetics, Transport): __slots__ = () +class Plasma(ThermoPhase, Kinetics, Transport, Electron): + __slots__ = () + + class Interface(InterfacePhase, InterfaceKinetics): """ Two-dimensional interfaces. diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/electron.pyx new file mode 100644 index 00000000000..c4a38c1bf1c --- /dev/null +++ b/interfaces/cython/cantera/electron.pyx @@ -0,0 +1,87 @@ +# This file is part of Cantera. See License.txt in the top-level directory or +# at http://www.cantera.org/license.txt for license and copyright information. + +import warnings +import weakref + + +cdef class ElectronCrossSection: + """ + A class which stores data about a cross section of electron. + + :param kind: + A string giving the kind of the collision, e.g. ``'EFFECTIVE'`` + :param target: + A string giving the target of the collision, e.g. ``'N2'`` + :param mass_ratio: + The mass ratio of electron to molecule. + :param init: + Used internally when wrapping :ct:`ElectronCrossSection` objects returned from C++ + + Example: + S = ct.ElectronCrossSection.listFromFile('gri30.yaml') + """ + def __cinit__(self, *args, init=True, **kwargs): + self._electron_cross_section.reset(new CxxElectronCrossSection()) + self.electron_cross_section = self._electron_cross_section.get() + + def __init__(self, kind=None, target=None, mass_ratio=None, data=None, + *args, init=True, **kwargs): + if not init: + return + + if kind is not None: + self.electron_cross_section.kind = stringify(kind) + + if target is not None: + self.electron_cross_section.target = stringify(target) + + if mass_ratio is not None: + self.electron_cross_section.mass_ratio = mass_ratio + + if data is not None: + self.electron_cross_section.data = data + + cdef _assign(self, shared_ptr[CxxElectronCrossSection] other): + self._electron_cross_section = other + self.electron_cross_section = self._electron_cross_section.get() + + @staticmethod + def listFromFile(filename, section='cross_section'): + """ + Create a list of ElectronCrossSection objects from all of the + cross section defined in a YAML. + + Directories on Cantera's input file path will be searched for the + specified file. + """ + if filename.lower().split('.')[-1] in ('yml', 'yaml'): + root = AnyMapFromYamlFile(stringify(filename)) + cxx_electron_cross_section = CxxGetElectronCrossSection(root[stringify(section)]) + + cross_section = [] + for a in cxx_electron_cross_section: + b = ElectronCrossSection(init=False) + b._assign(a) + cross_section.append(b) + return cross_section + + property kind: + """ The kind of the collision. """ + def __get__(self): + return pystr(self.electron_cross_section.kind) + + property target: + """ The target of the collision. """ + def __get__(self): + return pystr(self.electron_cross_section.target) + + property mass_ratio: + """ The mass ratio of electron to molecule. """ + def __get__(self): + return self.electron_cross_section.mass_ratio + + property data: + """ The mass ratio of electron to molecule. """ + def __get__(self): + return self.electron_cross_section.data diff --git a/src/SConscript b/src/SConscript index f179246cdf7..0a1498ebd6e 100644 --- a/src/SConscript +++ b/src/SConscript @@ -27,6 +27,7 @@ libs = [('base', ['cpp'], baseSetup), ('base', ['^application.cpp'], applicationSetup), ('base', ['^global.cpp'], globalSetup), ('thermo', ['cpp'], defaultSetup), + ('electron', ['cpp'], defaultSetup), ('tpx', ['cpp'], defaultSetup), ('equil', ['cpp','c'], defaultSetup), ('numerics', ['cpp'], defaultSetup), diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp new file mode 100644 index 00000000000..44f1c26d139 --- /dev/null +++ b/src/electron/Electron.cpp @@ -0,0 +1,64 @@ +// This file is part of Cantera. See License.txt in the top-level directory or +// at http://www.cantera.org/license.txt for license and copyright information. + +#include "cantera/electron/Electron.h" +#include "cantera/base/stringUtils.h" +#include "cantera/base/ctexceptions.h" +#include "cantera/base/ctml.h" +#include +#include +#include + +namespace Cantera { + +Electron::Electron() + : m_electronCrossSectionTargets(0) + , m_electronCrossSectionKinds(0) + , m_ncs(0) +{ +} + +Electron::~Electron() +{ +} + +size_t Electron::nElectronCrossSections() const +{ + return m_ncs; +} + +bool Electron::addElectronCrossSection(shared_ptr ecs) +{ + if (std::find(m_electronCrossSectionTargets.begin(), + m_electronCrossSectionTargets.end(), + ecs->target) != m_electronCrossSectionTargets.end()) { + if (std::find(m_electronCrossSectionKinds.begin(), + m_electronCrossSectionKinds.end(), + ecs->kind) != m_electronCrossSectionKinds.end()) { + throw CanteraError("Electron::addElectronCrossSection", + "Already contains a data of type '{}' for '{}'.", + ecs->kind, ecs->target); + } + } + ecs->validate(); + m_electronCrossSectionTargets.push_back(ecs->target); + m_electronCrossSectionKinds.push_back(ecs->kind); + m_massRatios.push_back(ecs->mass_ratio); + + // transpose data + std::vector> transdata(2, std::vector(ecs->data.size())); + for (size_t i = 0; i < ecs->data.size(); i++) { + for (size_t j = 0; j < 2; j++) { + transdata[j][i] = ecs->data[i][j]; + } + } + boost::math::barycentric_rational cs(transdata[0].data(), + transdata[1].data(), + transdata[0].size()); + m_electronCrossSectionFunctions.push_back(cs); + m_ncs++; + + return true; +} + +} diff --git a/src/electron/ElectronCrossSection.cpp b/src/electron/ElectronCrossSection.cpp new file mode 100644 index 00000000000..fb662220ece --- /dev/null +++ b/src/electron/ElectronCrossSection.cpp @@ -0,0 +1,85 @@ +// This file is part of Cantera. See License.txt in the top-level directory or +// at http://www.cantera.org/license.txt for license and copyright information. + +#include "cantera/electron/ElectronCrossSection.h" +#include "cantera/base/stringUtils.h" +#include "cantera/base/ctexceptions.h" +#include "cantera/base/ctml.h" +#include +#include +#include + +namespace Cantera { + +ElectronCrossSection::ElectronCrossSection() +{ +} + +ElectronCrossSection::ElectronCrossSection(const std::string& kind_, + const std::string& target_, + const std::vector> data_, + double mass_ratio_) + : kind(kind_) + , target(target_) + , data(data_) + , mass_ratio(mass_ratio_) +{ +} + +ElectronCrossSection::~ElectronCrossSection() +{ +} + +void ElectronCrossSection::validate() +{ + if (kind == "EFFECTIVE") { + if (data[0][0] != 0.0) { + throw CanteraError("ElectronCrossSection::validate", + "Invalid energy value of type '{}' for '{}'. " + "Energy must starts at zero.", kind, target); + } + if (mass_ratio >= 1.0 || mass_ratio < 0.0) { + throw CanteraError("ElectronCrossSection::validate", + "Invalid mass ratio of type '{}' for '{}'. " + "Mass ratio of electron to target must be in the range of 0 to 1.", kind, target); + } + } else { + throw CanteraError("ElectronCrossSection::validate", + "'{}' is an unknown type of cross section data.", kind); + } +} + +unique_ptr newElectronCrossSection(const AnyMap& node) +{ + unique_ptr ecs(new ElectronCrossSection(node["kind"].asString(), + node["target"].asString(), + node["data"].asVector>())); + + if (ecs->kind == "EFFECTIVE") { + ecs->mass_ratio = node["mass_ratio"].asDouble(); + } + + // Store all unparsed keys in the "extra" map + const static std::set known_keys{ + "kind", "target", "data", "mass_ratio" + }; + + for (const auto& item : node) { + if (known_keys.count(item.first) == 0) { + ecs->extra[item.first] = item.second; + } + } + + return ecs; +} + +std::vector> getElectronCrossSection(const AnyValue& items) +{ + std::vector > all_cross_sections; + for (const auto& node : items.asVector()) { + all_cross_sections.emplace_back(newElectronCrossSection(node)); + } + return all_cross_sections; +} + +} diff --git a/src/electron/ElectronFactory.cpp b/src/electron/ElectronFactory.cpp new file mode 100644 index 00000000000..2a44d93bada --- /dev/null +++ b/src/electron/ElectronFactory.cpp @@ -0,0 +1,46 @@ +/** + * @file ElectronFactory.cpp + * Definitions for the factory class that can create known Electron objects + */ + +// This file is part of Cantera. See License.txt in the top-level directory or +// at http://www.cantera.org/license.txt for license and copyright information. + +#include "cantera/electron/ElectronFactory.h" +#include "cantera/electron/Electron.h" +#include "cantera/electron/MaxwellBoltzmannElectron.h" + + +using namespace std; + +namespace Cantera +{ + +ElectronFactory* ElectronFactory::s_factory = 0; +std::mutex ElectronFactory::electron_mutex; + +ElectronFactory::ElectronFactory() +{ + reg("MaxwellBoltzmann", []() { return new MaxwellBoltzmannElectron(); }); +} + +Electron* ElectronFactory::newElectron(const std::string& model) +{ + return create(model); +} + +unique_ptr newElectron(const AnyMap& rootNode) +{ + unique_ptr electron(newElectron(rootNode["electron"].asString())); + addElectronCrossSections(*electron, rootNode["cross_section"]); + return electron; +} + +void addElectronCrossSections(Electron& electron, const AnyValue& cross_section) +{ + for (const auto& item : cross_section.asVector()) { + electron.addElectronCrossSection(newElectronCrossSection(item)); + } +} + +} diff --git a/src/electron/MaxwellBoltzmannElectron.cpp b/src/electron/MaxwellBoltzmannElectron.cpp new file mode 100644 index 00000000000..023b20886c0 --- /dev/null +++ b/src/electron/MaxwellBoltzmannElectron.cpp @@ -0,0 +1,14 @@ +// This file is part of Cantera. See License.txt in the top-level directory or +// at http://www.cantera.org/license.txt for license and copyright information. + +#include "cantera/electron/MaxwellBoltzmannElectron.h" +#include "cantera/electron/ElectronFactory.h" +#include "cantera/base/utilities.h" + +namespace Cantera { + +MaxwellBoltzmannElectron::MaxwellBoltzmannElectron() +{ +} + +} From c1e97ecfd85ea40de1b2854d46eeb2b3edfdeadb Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Wed, 10 Apr 2019 16:59:52 +0800 Subject: [PATCH 002/139] [Numerics] add simpsonQuadrature --- include/cantera/numerics/funcs.h | 3 +++ src/numerics/funcs.cpp | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/cantera/numerics/funcs.h b/include/cantera/numerics/funcs.h index ef3c4593c63..cbb8e4ecafd 100644 --- a/include/cantera/numerics/funcs.h +++ b/include/cantera/numerics/funcs.h @@ -10,6 +10,7 @@ #define CT_FUNCS_H #include "cantera/base/ct_defs.h" +#include "cantera/numerics/polyfit.h" namespace Cantera { @@ -28,6 +29,8 @@ namespace Cantera */ doublereal linearInterp(doublereal x, const vector_fp& xpts, const vector_fp& fpts); + +double simpsonQuadrature(const vector_fp& x, const vector_fp& y); } #endif diff --git a/src/numerics/funcs.cpp b/src/numerics/funcs.cpp index ca1e73c08f8..1373fcf5197 100644 --- a/src/numerics/funcs.cpp +++ b/src/numerics/funcs.cpp @@ -4,6 +4,7 @@ // at https://cantera.org/license.txt for license and copyright information. #include "cantera/numerics/funcs.h" +#include "cantera/base/ctexceptions.h" using namespace std; @@ -27,4 +28,34 @@ doublereal linearInterp(doublereal x, const vector_fp& xpts, return ff; } +double simpsonQuadrature(const vector_fp& x, const vector_fp& y) +{ + if (x.size() != y.size()) { + throw CanteraError("Cantera::simpsonQuadrature", + "size of x is not equal to size of y"); + } + size_t N = x.size(); + vector_fp w(N, -1.0); + size_t ns = (N - 1) / 2; + size_t ms = (N - 1) % 2; + double sum = 0; + for (size_t i = 0; i < ns; i++) { + vector_fp c; + c.resize(3); + vector_fp xs{x[2*i],x[2*i+1],x[2*i+2]}; + vector_fp ys{y[2*i],y[2*i+1],y[2*i+2]}; + polyfit(3, 2, xs.data(), ys.data(), w.data(), c.data()); + sum += c[0] * x[2*i+2] + + c[1] * 0.5 * x[2*i+2] * x[2*i+2] + + c[2] * 1./3. * x[2*i+2] * x[2*i+2] * x[2*i+2] - + c[0] * x[2*i] - + c[1] * 0.5 * x[2*i] * x[2*i] - + c[2] * 1./3. * x[2*i] * x[2*i] * x[2*i]; + } + if (ms == 1) { + sum += 0.5 * (x[N-1] - x[N-2]) * (y[N-1] + y[N-2]); + } + return sum; +} + } From e6a13a6a96d6db60f81598443dccbf209b60b39d Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 16 Mar 2019 14:42:47 +0800 Subject: [PATCH 003/139] [electron] add thermo object and functions to electron --- include/cantera/electron/Electron.h | 74 ++++++++- include/cantera/electron/ElectronFactory.h | 2 +- .../electron/MaxwellBoltzmannElectron.h | 25 ---- include/cantera/electron/WeakIonGasElectron.h | 33 +++++ interfaces/cython/cantera/_cantera.pxd | 10 +- interfaces/cython/cantera/base.pyx | 3 +- interfaces/cython/cantera/electron.pyx | 24 +++ src/electron/Electron.cpp | 140 +++++++++++++++++- src/electron/ElectronFactory.cpp | 7 +- src/electron/MaxwellBoltzmannElectron.cpp | 14 -- src/electron/WeakIonGasElectron.cpp | 32 ++++ 11 files changed, 309 insertions(+), 55 deletions(-) delete mode 100644 include/cantera/electron/MaxwellBoltzmannElectron.h create mode 100644 include/cantera/electron/WeakIonGasElectron.h delete mode 100644 src/electron/MaxwellBoltzmannElectron.cpp create mode 100644 src/electron/WeakIonGasElectron.cpp diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index a074c083e72..903172daefa 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -9,10 +9,10 @@ #ifndef CT_ELECTRON_H #define CT_ELECTRON_H +#include "cantera/thermo/ThermoPhase.h" #include "cantera/electron/ElectronCrossSection.h" #include "cantera/base/ctexceptions.h" #include "cantera/base/ValueCache.h" -#include namespace Cantera { @@ -32,12 +32,32 @@ class Electron //! successfully added, or `false` if the electron cross section was ignored. virtual bool addElectronCrossSection(shared_ptr ecs); - size_t nElectronCrossSections() const; + size_t nElectronCrossSections() const { + return m_ncs; + } + + size_t nPoints() const { + return m_points; + } + + double grid(size_t i) const { + return m_eps[i]; + } + + // Setup grid of electron energy. + void setupGrid(size_t n, const double* eps); + + // Setup cross sections. + void setupCrossSections(); + + double electronDiffusivity(double N); + double electronMobility(double N); + void init(thermo_t* thermo); std::vector m_electronCrossSectionTargets; std::vector m_electronCrossSectionKinds; vector_fp m_massRatios; - std::vector> m_electronCrossSectionFunctions; + std::vector>> m_electronCrossSectionData; protected: //! Cached for saved calculations within each Electron. @@ -47,7 +67,55 @@ class Electron */ mutable ValueCache m_cache; + void calculateTotalCrossSection(); + + virtual void calculateDistributionFunction(); + + // update temperature + void update_T(); + + // update composition + void update_C(); + + // Number of cross section sets size_t m_ncs; + + // Grid of electron energy [eV] + vector_fp m_eps; + + // Number of points for energy grid + size_t m_points; + + // Boltzmann constant times electron temperature + double m_kTe; + + // Boltzmann constant times gas temperature + double m_kT; + + // Electron energy distribution function + vector_fp m_f0; + vector_fp m_df0; + + double m_gamma; + + vector_fp m_moleFractions; + double m_N; + + // Flag + bool m_electronCrossSections_ok; + bool m_f0_ok; + + // Vector of electron cross section on the energy grid + std::vector m_electronCrossSections; + + // Vector of total electron cross section on the energy grid + vector_fp m_totalCrossSection; + + //! pointer to the object representing the phase + thermo_t* m_thermo; + + //! stroe a local gas composition + compositionMap m_gasComposition; }; } diff --git a/include/cantera/electron/ElectronFactory.h b/include/cantera/electron/ElectronFactory.h index c4d5c30a7e2..c8f7a2b4d67 100644 --- a/include/cantera/electron/ElectronFactory.h +++ b/include/cantera/electron/ElectronFactory.h @@ -63,7 +63,7 @@ inline Electron* newElectron(const std::string& model) return ElectronFactory::factory()->create(model); } -unique_ptr newElectron(const AnyMap& rootNode=AnyMap()); +unique_ptr newElectron(const AnyMap& rootNode=AnyMap(), thermo_t* phase = 0); void addElectronCrossSections(Electron& electron, const AnyValue& cross_section); diff --git a/include/cantera/electron/MaxwellBoltzmannElectron.h b/include/cantera/electron/MaxwellBoltzmannElectron.h deleted file mode 100644 index 30c6f4f98fd..00000000000 --- a/include/cantera/electron/MaxwellBoltzmannElectron.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @file MaxwellBoltzmannElectron.h - * Header file for class MaxwellBoltzmannElectron. - */ - -// This file is part of Cantera. See License.txt in the top-level directory or -// at http://www.cantera.org/license.txt for license and copyright information. - -#ifndef CT_MAXWELLBOLTZMANNELECTRON_H -#define CT_MAXWELLBOLTZMANNELECTRON_H - -#include "cantera/electron/Electron.h" - -namespace Cantera -{ - -class MaxwellBoltzmannElectron: public Electron -{ -public: - MaxwellBoltzmannElectron(); //!< Default constructor. -}; - -} - -#endif diff --git a/include/cantera/electron/WeakIonGasElectron.h b/include/cantera/electron/WeakIonGasElectron.h new file mode 100644 index 00000000000..f6ced5ab028 --- /dev/null +++ b/include/cantera/electron/WeakIonGasElectron.h @@ -0,0 +1,33 @@ +/** + * @file WeakIonGasElectron.h + * Header file for class WeakIonGasElectron. + */ + +// This file is part of Cantera. See License.txt in the top-level directory or +// at http://www.cantera.org/license.txt for license and copyright information. + +#ifndef CT_WEAKIONGASELECTRON_H +#define CT_WEAKIONGASELECTRON_H + +#include "cantera/electron/Electron.h" + +namespace Cantera +{ +/** + * This class calculates the properties of electron in a gas. + * assuming a Maxwell-Boltzmann electron energy distribution function. + * @ingroup electron + */ +class WeakIonGasElectron: public Electron +{ +public: + WeakIonGasElectron(); //!< Default constructor. + + void setElectronTemperature(double Te); + + virtual void calculateDistributionFunction(); +}; + +} + +#endif diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 208eea86564..17650c22c2e 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -156,8 +156,16 @@ cdef extern from "cantera/electron/Electron.h" namespace "Cantera": cdef cppclass CxxElectron "Cantera::Electron": CxxElectron() + #Properties + double grid(size_t) + size_t nPoints() + double electronMobility(double); + double electronDiffusivity(double); + # initialization cbool addElectronCrossSection(shared_ptr[CxxElectronCrossSection]) except +translate_exception + void setupGrid(size_t, double*) except +translate_exception + void init(CxxThermoPhase*) except +translate_exception cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera": ctypedef enum ThermoBasis: @@ -711,7 +719,7 @@ cdef extern from "cantera/thermo/ThermoFactory.h" namespace "Cantera": cdef CxxThermoPhase* newThermoPhase(string) except +translate_exception cdef extern from "cantera/electron/ElectronFactory.h" namespace "Cantera": - cdef shared_ptr[CxxElectron] newElectron(CxxAnyMap&) except +translate_exception + cdef shared_ptr[CxxElectron] newElectron(CxxAnyMap&, CxxThermoPhase*) except +translate_exception cdef CxxElectron* newElectron(string) except +translate_exception cdef extern from "cantera/kinetics/KineticsFactory.h" namespace "Cantera": diff --git a/interfaces/cython/cantera/base.pyx b/interfaces/cython/cantera/base.pyx index 4c2b75acd1a..137fcdfa2ce 100644 --- a/interfaces/cython/cantera/base.pyx +++ b/interfaces/cython/cantera/base.pyx @@ -241,7 +241,7 @@ cdef class _SolutionBase: root = AnyMapFromYamlFile(stringify(efile)) if isinstance(self, Electron): - self._electron = newElectron(root) + self._electron = newElectron(root, self.thermo) self.electron = self._electron.get() else: self.electron = NULL @@ -254,6 +254,7 @@ cdef class _SolutionBase: if isinstance(self, Electron): self.electron = newElectron(stringify(electron)) self._electron.reset(self.electron) + self.electron.init(self.thermo) for ecs in electron_cross_sections: self.electron.addElectronCrossSection(ecs._electron_cross_section) diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/electron.pyx index c4a38c1bf1c..a51ea0ad545 100644 --- a/interfaces/cython/cantera/electron.pyx +++ b/interfaces/cython/cantera/electron.pyx @@ -4,6 +4,30 @@ import warnings import weakref +cdef class Electron(_SolutionBase): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + property electron_energy_grid: + """ The grid for this domain """ + def __get__(self): + cdef np.ndarray[np.double_t, ndim=1] grid = np.empty(self.electron.nPoints()) + cdef int i + for i in range(self.electron.nPoints()): + grid[i] = self.electron.grid(i) + return grid + + def __set__(self, grid): + cdef np.ndarray[np.double_t, ndim=1] data = \ + np.ascontiguousarray(grid, dtype=np.double) + self.electron.setupGrid(len(data), &data[0]) + + def electron_mobility(self, N): + return self.electron.electronMobility(N) + + def electron_diffusivity(self, N): + return self.electron.electronDiffusivity(N) + cdef class ElectronCrossSection: """ diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index 44f1c26d139..17dfb5c9469 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -5,6 +5,7 @@ #include "cantera/base/stringUtils.h" #include "cantera/base/ctexceptions.h" #include "cantera/base/ctml.h" +#include "cantera/numerics/funcs.h" #include #include #include @@ -15,16 +16,65 @@ Electron::Electron() : m_electronCrossSectionTargets(0) , m_electronCrossSectionKinds(0) , m_ncs(0) + , m_points(1000) + , m_kTe(Undef) + , m_kT(Undef) + , m_electronCrossSections_ok(false) + , m_f0_ok(false) { + // default energy grid + m_eps.resize(m_points); + for (size_t j = 0; j < m_points; j++) { + m_eps[j] = j / 100.0; + } + + m_gamma = pow(2.0 * ElectronCharge / ElectronMass, 0.5); } Electron::~Electron() { } -size_t Electron::nElectronCrossSections() const +void Electron::init(thermo_t* thermo) +{ + m_thermo = thermo; + m_f0_ok = false; +} + +void Electron::update_T() { - return m_ncs; + // signal that temperature-dependent quantities will need to be recomputed + // before use, and update the local temperature. + m_kT = Boltzmann * m_thermo->temperature() / ElectronCharge; + + // flag for quantities need to be re-calculated + m_f0_ok = false; +} + +void Electron::update_C() +{ + // signal that concentration-dependent quantities will need to be recomputed + // before use, and update the local mole fractions. + compositionMap gas_composition = m_thermo->getMoleFractionsByName(0.0); + m_moleFractions.resize(m_ncs, 0.0); + for (auto const& x : gas_composition) { + bool not_found = true; + for (size_t i = 0; i < m_ncs; i++) { + if (m_electronCrossSectionTargets[i] == x.first) { + m_moleFractions[i] = x.second; + not_found = false; + } + } + if (not_found) { + if (x.second > 0.01) { + std::cout << "The mole fraction of species " << x.first + << " is more than 0.01 but it has no cross section data." + << std::endl; + } + } + } + // flag for quantities need to be re-calculated + m_f0_ok = false; } bool Electron::addElectronCrossSection(shared_ptr ecs) @@ -52,13 +102,89 @@ bool Electron::addElectronCrossSection(shared_ptr ecs) transdata[j][i] = ecs->data[i][j]; } } - boost::math::barycentric_rational cs(transdata[0].data(), - transdata[1].data(), - transdata[0].size()); - m_electronCrossSectionFunctions.push_back(cs); + m_electronCrossSectionData.push_back(transdata); m_ncs++; - + m_electronCrossSections_ok = false; return true; } +void Electron::setupGrid(size_t n, const double* eps) +{ + m_points = n; + m_eps.resize(n); + for (size_t j = 0; j < m_points; j++) { + m_eps[j] = eps[j]; + } + m_electronCrossSections_ok = false; + m_f0_ok = false; +} + +void Electron::setupCrossSections() +{ + m_electronCrossSections.resize(m_ncs, std::vector(m_points)); + for (size_t i = 0; i < m_ncs; i++) { + for (size_t j = 0; j < m_points; j++) { + m_electronCrossSections[i][j] = linearInterp(m_eps[j], + m_electronCrossSectionData[i][0], + m_electronCrossSectionData[i][1]); + } + } + m_electronCrossSections_ok = true; +} + +void Electron::calculateTotalCrossSection() +{ + if (m_electronCrossSections_ok == false) { + setupCrossSections(); + } + m_totalCrossSection.resize(m_points); + for (size_t j = 0; j < m_points; j++) { + for (size_t i = 0; i < m_ncs; i++) { + if (m_electronCrossSectionKinds[i] == "EFFECTIVE") { + m_totalCrossSection[j] += m_moleFractions[i] * m_electronCrossSections[i][j]; + } + } + } +} + +void Electron::calculateDistributionFunction() +{ + update_T(); + update_C(); + calculateTotalCrossSection(); + m_f0.resize(m_points); + m_df0.resize(m_points); + m_f0_ok = true; +} + +double Electron::electronDiffusivity(double N) +{ + if (m_f0_ok == false) { + calculateDistributionFunction(); + } + double vi = netProductionFrequency(m_f0); + vector_fp y(m_points, 0.0); + for (size_t j = 0; j < m_points; j++) { + if (m_eps[j] != 0.0) { + y[j] = m_eps[j] * m_f0[j] / (m_totalCrossSection[j] + vi / pow(m_eps[j], 0.5)); + } + } + return 1./3. * m_gamma * simpsonQuadrature(m_eps, y) / N; +} + +double Electron::electronMobility(double N) +{ + if (m_f0_ok == false) { + calculateDistributionFunction(); + } + double vi = netProductionFrequency(m_f0); + vector_fp y(m_points, 0.0); + for (size_t j = 0; j < m_points; j++) { + if (m_eps[j] != 0.0) { + y[j] = m_eps[j] * m_df0[j] / (m_totalCrossSection[j] + vi / pow(m_eps[j], 0.5)); + } + } + return -1./3. * m_gamma * simpsonQuadrature(m_eps, y) / N; +} + } diff --git a/src/electron/ElectronFactory.cpp b/src/electron/ElectronFactory.cpp index 2a44d93bada..8319e89a26b 100644 --- a/src/electron/ElectronFactory.cpp +++ b/src/electron/ElectronFactory.cpp @@ -8,7 +8,7 @@ #include "cantera/electron/ElectronFactory.h" #include "cantera/electron/Electron.h" -#include "cantera/electron/MaxwellBoltzmannElectron.h" +#include "cantera/electron/WeakIonGasElectron.h" using namespace std; @@ -21,7 +21,7 @@ std::mutex ElectronFactory::electron_mutex; ElectronFactory::ElectronFactory() { - reg("MaxwellBoltzmann", []() { return new MaxwellBoltzmannElectron(); }); + reg("WeaklyIonizedGas", []() { return new WeakIonGasElectron(); }); } Electron* ElectronFactory::newElectron(const std::string& model) @@ -29,9 +29,10 @@ Electron* ElectronFactory::newElectron(const std::string& model) return create(model); } -unique_ptr newElectron(const AnyMap& rootNode) +unique_ptr newElectron(const AnyMap& rootNode, thermo_t* phase) { unique_ptr electron(newElectron(rootNode["electron"].asString())); + electron->init(phase); addElectronCrossSections(*electron, rootNode["cross_section"]); return electron; } diff --git a/src/electron/MaxwellBoltzmannElectron.cpp b/src/electron/MaxwellBoltzmannElectron.cpp deleted file mode 100644 index 023b20886c0..00000000000 --- a/src/electron/MaxwellBoltzmannElectron.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// This file is part of Cantera. See License.txt in the top-level directory or -// at http://www.cantera.org/license.txt for license and copyright information. - -#include "cantera/electron/MaxwellBoltzmannElectron.h" -#include "cantera/electron/ElectronFactory.h" -#include "cantera/base/utilities.h" - -namespace Cantera { - -MaxwellBoltzmannElectron::MaxwellBoltzmannElectron() -{ -} - -} diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp new file mode 100644 index 00000000000..c664e6f987a --- /dev/null +++ b/src/electron/WeakIonGasElectron.cpp @@ -0,0 +1,32 @@ +// This file is part of Cantera. See License.txt in the top-level directory or +// at http://www.cantera.org/license.txt for license and copyright information. + +#include "cantera/electron/WeakIonGasElectron.h" +#include "cantera/electron/ElectronFactory.h" +#include "cantera/base/utilities.h" + +namespace Cantera { + +WeakIonGasElectron::WeakIonGasElectron() +{ +} + +void WeakIonGasElectron::setElectronTemperature(double Te) +{ + m_kTe = Boltzmann * Te / ElectronCharge; + m_f0_ok = false; +} + +void WeakIonGasElectron::calculateDistributionFunction() +{ + Electron::calculateDistributionFunction(); + if (m_kTe == Undef) { + m_kTe = m_kT; + } + for (size_t j = 0; j < m_points; j++) { + m_f0[j] = 2.0 * pow(1.0/Pi, 0.5) * pow(m_kTe, -3./2.) * std::exp(-m_eps[j]/m_kTe); + m_df0[j] = -2.0 * pow(1.0/Pi, 0.5) * pow(m_kTe, -5./2.) * std::exp(-m_eps[j]/m_kTe); + } +} + +} From 7634ebd837a9a22055e6400086a8b35e06ad9017 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 4 Apr 2019 00:26:59 +0800 Subject: [PATCH 004/139] [electron] add netproductionfreq --- include/cantera/electron/Electron.h | 15 +++++++++++++++ src/electron/Electron.cpp | 30 ++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index 903172daefa..571e00bb46e 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -71,6 +71,14 @@ class Electron virtual void calculateDistributionFunction(); + //! Normalized net production frequency + /*! + * param. 1: normalized distribution function + * param. 2: total attachment cross section + * param. 3: total ionization cross section + */ + double netProductionFrequency(const vector_fp& f0); + // update temperature void update_T(); @@ -104,6 +112,7 @@ class Electron // Flag bool m_electronCrossSections_ok; bool m_f0_ok; + bool m_totalCrossSection_ok; // Vector of electron cross section on the energy grid std::vector m_electronCrossSections; @@ -111,6 +120,12 @@ class Electron // Vector of total electron cross section on the energy grid vector_fp m_totalCrossSection; + // Vector of total attachment cross section on the energy grid + vector_fp m_attachCrossSection; + + // Vector of total ionization cross section on the energy grid + vector_fp m_ionizCrossSection; + //! pointer to the object representing the phase thermo_t* m_thermo; diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index 17dfb5c9469..c7cf98bc52b 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -75,6 +75,7 @@ void Electron::update_C() } // flag for quantities need to be re-calculated m_f0_ok = false; + m_totalCrossSection_ok = false; } bool Electron::addElectronCrossSection(shared_ptr ecs) @@ -116,6 +117,7 @@ void Electron::setupGrid(size_t n, const double* eps) m_eps[j] = eps[j]; } m_electronCrossSections_ok = false; + m_totalCrossSection_ok = false; m_f0_ok = false; } @@ -137,14 +139,40 @@ void Electron::calculateTotalCrossSection() if (m_electronCrossSections_ok == false) { setupCrossSections(); } - m_totalCrossSection.resize(m_points); + m_totalCrossSection.resize(m_points, 0.0); + m_attachCrossSection.resize(m_points, 0.0); + m_ionizCrossSection.resize(m_points, 0.0); for (size_t j = 0; j < m_points; j++) { for (size_t i = 0; i < m_ncs; i++) { if (m_electronCrossSectionKinds[i] == "EFFECTIVE") { m_totalCrossSection[j] += m_moleFractions[i] * m_electronCrossSections[i][j]; + } else if (m_electronCrossSectionKinds[i] == "ATTACHMENT") { + m_attachCrossSection[j] += m_moleFractions[i] * m_electronCrossSections[i][j]; + } else if (m_electronCrossSectionKinds[i] == "IONIZATION") { + m_ionizCrossSection[j] += m_moleFractions[i] * m_electronCrossSections[i][j]; } } } + m_totalCrossSection_ok = true; +} + +double Electron::netProductionFrequency(const vector_fp& f0) +{ + if (m_totalCrossSection_ok == false) { + calculateTotalCrossSection(); + } + double vi = 0.0; + if (f0.size() != m_points) { + throw CanteraError("Electron::netProductionFrequency", + "The size of input vector must equal to grid points, {}.", + m_points); + } + for (size_t j = 0; j < m_points - 1; j++) { + double left = (m_ionizCrossSection[j] - m_attachCrossSection[j]) * m_eps[j] * f0[j]; + double right = (m_ionizCrossSection[j+1] - m_attachCrossSection[j+1]) * m_eps[j+1] * f0[j+1]; + vi += 0.5 * (left + right) * (m_eps[j+1] - m_eps[j]); + } + return vi; } void Electron::calculateDistributionFunction() From f140679f3a610ccfad48d7cdfbac023faa86abe7 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 4 Apr 2019 14:19:06 +0800 Subject: [PATCH 005/139] [electron] improve setupCrossSection to extrapolate --- src/electron/Electron.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index c7cf98bc52b..952b5bef5aa 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -125,10 +125,16 @@ void Electron::setupCrossSections() { m_electronCrossSections.resize(m_ncs, std::vector(m_points)); for (size_t i = 0; i < m_ncs; i++) { + vector_fp x = m_electronCrossSectionData[i][0]; + vector_fp y = m_electronCrossSectionData[i][1]; + if (x[0] > 0.0) { + x.insert(x.begin(), 0.0); + y.insert(y.begin(), m_electronCrossSectionData[i][1][0]); + } + x.push_back(1e8); + y.push_back(m_electronCrossSectionData[i][1].back()); for (size_t j = 0; j < m_points; j++) { - m_electronCrossSections[i][j] = linearInterp(m_eps[j], - m_electronCrossSectionData[i][0], - m_electronCrossSectionData[i][1]); + m_electronCrossSections[i][j] = linearInterp(m_eps[j], x, y); } } m_electronCrossSections_ok = true; From cf2e341e77c570abc14ed437096b0ef9a20f05e1 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 4 Apr 2019 15:03:19 +0800 Subject: [PATCH 006/139] [electron] add ATTACHMENT and IONIZATION type and fix addElectronCrossSection --- src/electron/Electron.cpp | 18 +++++++++--------- src/electron/ElectronCrossSection.cpp | 16 ++++++++++++++-- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index 952b5bef5aa..9144cd4db75 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -80,15 +80,15 @@ void Electron::update_C() bool Electron::addElectronCrossSection(shared_ptr ecs) { - if (std::find(m_electronCrossSectionTargets.begin(), - m_electronCrossSectionTargets.end(), - ecs->target) != m_electronCrossSectionTargets.end()) { - if (std::find(m_electronCrossSectionKinds.begin(), - m_electronCrossSectionKinds.end(), - ecs->kind) != m_electronCrossSectionKinds.end()) { - throw CanteraError("Electron::addElectronCrossSection", - "Already contains a data of type '{}' for '{}'.", - ecs->kind, ecs->target); + if (ecs->kind == "EFFECTIVE") { + for (size_t i = 0; i < m_ncs; i++) { + if (m_electronCrossSectionTargets[i] == ecs->target) { + if (m_electronCrossSectionKinds[i] == "EFFECTIVE") { + throw CanteraError("Electron::addElectronCrossSection", + "Already contains a data of EFFECTIVE cross section for '{}'.", + ecs->target); + } + } } } ecs->validate(); diff --git a/src/electron/ElectronCrossSection.cpp b/src/electron/ElectronCrossSection.cpp index fb662220ece..60f334e6dc7 100644 --- a/src/electron/ElectronCrossSection.cpp +++ b/src/electron/ElectronCrossSection.cpp @@ -43,9 +43,21 @@ void ElectronCrossSection::validate() "Invalid mass ratio of type '{}' for '{}'. " "Mass ratio of electron to target must be in the range of 0 to 1.", kind, target); } - } else { + } else if (kind == "IONIZATION") { + if (data[0][1] != 0.0) { + throw CanteraError("ElectronCrossSection::validate", + "Invalid cross section value of type '{}' for '{}'. " + "Cross section must starts at zero.", kind, target); + } + } else if (kind == "ATTACHMENT") { + if (data[0][1] != 0.0) { throw CanteraError("ElectronCrossSection::validate", - "'{}' is an unknown type of cross section data.", kind); + "Invalid cross section value of type '{}' for '{}'. " + "Cross section must starts at zero.", kind, target); + } + } else { + throw CanteraError("ElectronCrossSection::validate", + "'{}' is an unknown type of cross section data.", kind); } } From ab5e3b97ed9f030957d2a37862034396266f0403 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 4 Apr 2019 16:31:33 +0800 Subject: [PATCH 007/139] [electron] update update_C msg --- src/electron/Electron.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index 9144cd4db75..0f32baf3fc3 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -67,9 +67,11 @@ void Electron::update_C() } if (not_found) { if (x.second > 0.01) { - std::cout << "The mole fraction of species " << x.first - << " is more than 0.01 but it has no cross section data." - << std::endl; + writelog("Cantera::Electron::update_C"); + writelog("\n"); + writelog("Warning: The mole fraction of species {} is more than 0.01", x.first); + writelog(" but it has no data of cross section."); + writelog("\n"); } } } From b6f7790ff5cf471768fcddaf0500ec5ab54dbaef Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 4 Apr 2019 17:08:02 +0800 Subject: [PATCH 008/139] [electron] add comments --- include/cantera/electron/Electron.h | 67 ++++++++++++------- .../cantera/electron/ElectronCrossSection.h | 3 +- include/cantera/electron/WeakIonGasElectron.h | 12 +++- interfaces/cython/cantera/electron.pyx | 7 +- 4 files changed, 60 insertions(+), 29 deletions(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index 571e00bb46e..d8a6eb07ffc 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -16,7 +16,10 @@ namespace Cantera { - +/** + * This class calculates the properties of electron in a gas. + * @ingroup electron + */ class Electron { public: @@ -32,26 +35,35 @@ class Electron //! successfully added, or `false` if the electron cross section was ignored. virtual bool addElectronCrossSection(shared_ptr ecs); + //! number of cross section dataset size_t nElectronCrossSections() const { return m_ncs; } + //! number of points of energy grid size_t nPoints() const { return m_points; } + //! energy grid double grid(size_t i) const { return m_eps[i]; } - // Setup grid of electron energy. + //! Setup grid of electron energy. void setupGrid(size_t n, const double* eps); - // Setup cross sections. + //! Setup cross sections. void setupCrossSections(); + //! electron diffusivity + //! @param N gas number density in SI double electronDiffusivity(double N); + + //! electron mobility + //! @param N gas number density in SI double electronMobility(double N); + void init(thermo_t* thermo); std::vector m_electronCrossSectionTargets; @@ -67,69 +79,76 @@ class Electron */ mutable ValueCache m_cache; + //! calculate total cross section void calculateTotalCrossSection(); + //! calculate electron energy distribution function virtual void calculateDistributionFunction(); - //! Normalized net production frequency - /*! - * param. 1: normalized distribution function - * param. 2: total attachment cross section - * param. 3: total ionization cross section - */ + //! normalized net production frequency + //! Equation 10 of [1] + //! vi / (N gamma) + //! @param f0 normalized electron energy distribution function double netProductionFrequency(const vector_fp& f0); - // update temperature + //! update temperature void update_T(); - // update composition + //! update composition void update_C(); - // Number of cross section sets + //! number of cross section sets size_t m_ncs; - // Grid of electron energy [eV] + //! grid of electron energy [eV] vector_fp m_eps; - // Number of points for energy grid + //! number of points for energy grid size_t m_points; - // Boltzmann constant times electron temperature + //! Boltzmann constant times electron temperature double m_kTe; - // Boltzmann constant times gas temperature + //! Boltzmann constant times gas temperature double m_kT; - // Electron energy distribution function + //! normalized electron energy distribution function vector_fp m_f0; + + //! the derivative of normalized electron energy distribution function vector_fp m_df0; + //! constant gamma double m_gamma; + //! mole fractions of target vector_fp m_moleFractions; - double m_N; - // Flag + //! flag of electron Cross Sections bool m_electronCrossSections_ok; + + //! flag of electron energy distribution function bool m_f0_ok; + + //! flag of total cross section bool m_totalCrossSection_ok; - // Vector of electron cross section on the energy grid + //! vector of electron cross section on the energy grid std::vector m_electronCrossSections; - // Vector of total electron cross section on the energy grid + //! vector of total electron cross section on the energy grid vector_fp m_totalCrossSection; - // Vector of total attachment cross section on the energy grid + //! vector of total attachment cross section on the energy grid vector_fp m_attachCrossSection; - // Vector of total ionization cross section on the energy grid + //! vector of total ionization cross section on the energy grid vector_fp m_ionizCrossSection; //! pointer to the object representing the phase thermo_t* m_thermo; - //! stroe a local gas composition + //! local gas composition compositionMap m_gasComposition; }; diff --git a/include/cantera/electron/ElectronCrossSection.h b/include/cantera/electron/ElectronCrossSection.h index 14779e2a151..3aee37d88c0 100644 --- a/include/cantera/electron/ElectronCrossSection.h +++ b/include/cantera/electron/ElectronCrossSection.h @@ -14,8 +14,7 @@ namespace Cantera //! Contains data about the cross sections of electron collision /*! - * This class stores the data about cross sections of electron collision - * which may be needed to add it to a Transport object. + * This class stores the cross section data of electron collision */ class ElectronCrossSection { diff --git a/include/cantera/electron/WeakIonGasElectron.h b/include/cantera/electron/WeakIonGasElectron.h index f6ced5ab028..bf6b5a79289 100644 --- a/include/cantera/electron/WeakIonGasElectron.h +++ b/include/cantera/electron/WeakIonGasElectron.h @@ -14,8 +14,16 @@ namespace Cantera { /** - * This class calculates the properties of electron in a gas. - * assuming a Maxwell-Boltzmann electron energy distribution function. + * This class calculates the properties of electron in a weakly ionized gas. + * Only electron-neutral collisions are considered for calculating the + * electron energy distribution function. + * + * Reference: + * [1] G. J. M. Hagelaar and L. C. Pitchford + * "Solving the Boltzmann equation to obtain electron transport + * coefficients and rate coefficients for fluid models." + * Plasma Sources Science and Technology 14.4 (2005): 722. + * doi: https://doi.org/10.1088/0963-0252/14/4/011 * @ingroup electron */ class WeakIonGasElectron: public Electron diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/electron.pyx index a51ea0ad545..6fcbdd1efa2 100644 --- a/interfaces/cython/cantera/electron.pyx +++ b/interfaces/cython/cantera/electron.pyx @@ -5,11 +5,14 @@ import warnings import weakref cdef class Electron(_SolutionBase): + """ + This class is used to compute electron properties for a phase of matter. + """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) property electron_energy_grid: - """ The grid for this domain """ + """ The grid of electron energy """ def __get__(self): cdef np.ndarray[np.double_t, ndim=1] grid = np.empty(self.electron.nPoints()) cdef int i @@ -23,9 +26,11 @@ cdef class Electron(_SolutionBase): self.electron.setupGrid(len(data), &data[0]) def electron_mobility(self, N): + """electron mobility [m^2/V/s)]""" return self.electron.electronMobility(N) def electron_diffusivity(self, N): + """electron diffusivity [m^2/s]""" return self.electron.electronDiffusivity(N) From 8382458fdf354e2072142a8c7c1ae1f318831584 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 13 Apr 2019 20:27:34 +0800 Subject: [PATCH 009/139] [electron][interface] enable solving EEDF with Eigen --- include/cantera/electron/Electron.h | 159 +++++--- .../cantera/electron/ElectronCrossSection.h | 6 +- include/cantera/electron/WeakIonGasElectron.h | 97 ++++- interfaces/cython/cantera/_cantera.pxd | 10 +- interfaces/cython/cantera/electron.pyx | 42 +- src/electron/Electron.cpp | 225 +++++------ src/electron/ElectronCrossSection.cpp | 14 +- src/electron/ElectronFactory.cpp | 2 +- src/electron/WeakIonGasElectron.cpp | 373 +++++++++++++++++- 9 files changed, 720 insertions(+), 208 deletions(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index d8a6eb07ffc..219d9046c68 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -13,6 +13,7 @@ #include "cantera/electron/ElectronCrossSection.h" #include "cantera/base/ctexceptions.h" #include "cantera/base/ValueCache.h" +#include "cantera/numerics/eigen_dense.h" namespace Cantera { @@ -23,7 +24,7 @@ namespace Cantera class Electron { public: - Electron(); //!< Default constructor. + Electron(); virtual ~Electron(); @@ -47,29 +48,85 @@ class Electron //! energy grid double grid(size_t i) const { - return m_eps[i]; + return m_gridC[i]; } //! Setup grid of electron energy. void setupGrid(size_t n, const double* eps); - //! Setup cross sections. - void setupCrossSections(); - //! electron diffusivity //! @param N gas number density in SI - double electronDiffusivity(double N); + virtual double electronDiffusivity(double N)=0; //! electron mobility //! @param N gas number density in SI - double electronMobility(double N); + virtual double electronMobility(double N)=0; + + //! mean electron energy + virtual double meanElectronEnergy() = 0; + //! initialize Electron. Need to be called after adding all cross sections. void init(thermo_t* thermo); - std::vector m_electronCrossSectionTargets; - std::vector m_electronCrossSectionKinds; + //! Reduced electric field + double reducedElectricField() const { + return m_EN; + } + + //! Set reduced electric field + void setReducedElectricField(double EN) { + if (m_EN != EN) { + m_EN = EN; + m_f0_ok = false; + } + } + + /** + * Set the parameters for the Boltzmann solver + * @param maxn Maximum number of iterations + * @param rtol Relative tolerance. The iteration is stopped when the norm + * of the absolute difference between EEDFs is smaller than rtol. + * @param delta0 Initial value of the iteration parameter. This parameter + * is adapted in succesive iterations to improve convergence. + * @param m Reduction factor of error. The Richardson extrapolation attemps + * to reduce the error by a factor of m in each iteration. Larger m + * means faster convergence but also has higher risk of encountering + * numerical instabilities. + * @param init_kTe Initial electron mean energy in [eV]. Assume + * initial EEDF to be Maxwell-Boltzmann distribution at init_kTe. + * @param warn Flag of showing warning of insufficient cross section data. + */ + void setBoltzmannSolver(size_t maxn, double rtol, double delta0, + double m, double init_kTe, bool warn) { + m_maxn = maxn; + m_rtol = rtol; + m_delta0 = delta0; + m_factorM = m; + m_init_kTe = init_kTe; + m_warn = warn; + } + + //! Return electron temperature + virtual double electronTemperature() = 0; + + //! Set chemionization scattering-in rate + //! Equal to the reaction rate divided by gas and electron number density + virtual void setChemionScatRate(double rate) = 0; + + //! list of targets of electron collision + std::vector m_targets; + + //! list of kinds of electron collision + std::vector m_kinds; + + //! list of mass ratio of electron to target species vector_fp m_massRatios; - std::vector>> m_electronCrossSectionData; + + //! list of thresholds of electron collision + vector_fp m_thresholds; + + //! cross sections + std::vector>> m_crossSections; protected: //! Cached for saved calculations within each Electron. @@ -79,44 +136,35 @@ class Electron */ mutable ValueCache m_cache; - //! calculate total cross section - void calculateTotalCrossSection(); - - //! calculate electron energy distribution function - virtual void calculateDistributionFunction(); - - //! normalized net production frequency - //! Equation 10 of [1] - //! vi / (N gamma) - //! @param f0 normalized electron energy distribution function - double netProductionFrequency(const vector_fp& f0); - - //! update temperature + //! Update temperature void update_T(); - //! update composition + //! Update composition void update_C(); + //! Calculate elastic cross section + void calculateElasticCrossSection(); + //! number of cross section sets size_t m_ncs; - //! grid of electron energy [eV] - vector_fp m_eps; + //! Grid of electron energy (cell center) [eV] + vector_fp m_gridC; + + //! Grid of electron energy (cell boundary i-1/2) [eV] + vector_fp m_gridB; //! number of points for energy grid size_t m_points; - //! Boltzmann constant times electron temperature - double m_kTe; - //! Boltzmann constant times gas temperature double m_kT; - //! normalized electron energy distribution function - vector_fp m_f0; + //! reduced electric field + double m_EN; - //! the derivative of normalized electron energy distribution function - vector_fp m_df0; + //! normalized electron energy distribution function + Eigen::VectorXd m_f0; //! constant gamma double m_gamma; @@ -124,32 +172,45 @@ class Electron //! mole fractions of target vector_fp m_moleFractions; - //! flag of electron Cross Sections - bool m_electronCrossSections_ok; + //! shift factor + std::vector m_shiftFactor; + std::vector m_inFactor; + + //! list elastic + std::vector m_kElastic; + + //! list inelastic + std::vector m_kInelastic; + + //! list effective + std::vector m_kEffective; //! flag of electron energy distribution function bool m_f0_ok; - //! flag of total cross section - bool m_totalCrossSection_ok; + //! pointer to the object representing the phase + thermo_t* m_thermo; + + //! local gas composition + compositionMap m_gasComposition; - //! vector of electron cross section on the energy grid - std::vector m_electronCrossSections; + //! Maximum number of iterations + size_t m_maxn; - //! vector of total electron cross section on the energy grid - vector_fp m_totalCrossSection; + //! Relative tolerance + double m_rtol; - //! vector of total attachment cross section on the energy grid - vector_fp m_attachCrossSection; + //! Initial value of the iteration parameter + double m_delta0; - //! vector of total ionization cross section on the energy grid - vector_fp m_ionizCrossSection; + //! Reduction factor of error + double m_factorM; - //! pointer to the object representing the phase - thermo_t* m_thermo; + //! Initial electron mean energy + double m_init_kTe; - //! local gas composition - compositionMap m_gasComposition; + //! Flag of warning of insufficient cross section data + bool m_warn; }; } diff --git a/include/cantera/electron/ElectronCrossSection.h b/include/cantera/electron/ElectronCrossSection.h index 3aee37d88c0..d285b893cbd 100644 --- a/include/cantera/electron/ElectronCrossSection.h +++ b/include/cantera/electron/ElectronCrossSection.h @@ -23,7 +23,8 @@ class ElectronCrossSection //! Constructor ElectronCrossSection(const std::string& kind, const std::string& target, - const std::vector> data, double mass_ratio=Undef); + const std::vector> data, double mass_ratio=Undef, + double threshold=0.0); //! ElectronCrossSection objects are not copyable or assignable ElectronCrossSection(const ElectronCrossSection&) = delete; @@ -44,6 +45,9 @@ class ElectronCrossSection //! The mass ratio of molecule to electron double mass_ratio; + //! The threshold of a process + double threshold; + //! Extra data used for specific models AnyMap extra; }; diff --git a/include/cantera/electron/WeakIonGasElectron.h b/include/cantera/electron/WeakIonGasElectron.h index bf6b5a79289..111079f7a36 100644 --- a/include/cantera/electron/WeakIonGasElectron.h +++ b/include/cantera/electron/WeakIonGasElectron.h @@ -10,13 +10,17 @@ #define CT_WEAKIONGASELECTRON_H #include "cantera/electron/Electron.h" +#include + +typedef Eigen::SparseMatrix SpMat; +typedef Eigen::Triplet T; namespace Cantera { /** * This class calculates the properties of electron in a weakly ionized gas. * Only electron-neutral collisions are considered for calculating the - * electron energy distribution function. + * electron energy distribution function (EEDF). * * Reference: * [1] G. J. M. Hagelaar and L. C. Pitchford @@ -24,16 +28,101 @@ namespace Cantera * coefficients and rate coefficients for fluid models." * Plasma Sources Science and Technology 14.4 (2005): 722. * doi: https://doi.org/10.1088/0963-0252/14/4/011 + * [2] A. Luque, "BOLOS: An open source solver for the Boltzmann equation," + * https://github.com/aluque/bolos. + * [3] D. McElroy, C. Walsh, A. Markwick, M. Cordiner, K. Smith, T. Millar, + * "The umist database for astrochemistry 2012," + * Astronomy & Astrophysics 550 (2013) A36. + * doi: https://doi.org/10.1051/0004-6361/201220465 * @ingroup electron */ class WeakIonGasElectron: public Electron { public: - WeakIonGasElectron(); //!< Default constructor. + WeakIonGasElectron(); + + virtual double electronDiffusivity(double N); + virtual double electronMobility(double N); + virtual double meanElectronEnergy(); + + //! electron temperature + //! If the reduced electric field is set, electron tempeature is calculated + //! from EEDF. + virtual double electronTemperature(); + + //! Set chemionization scattering-in rate + virtual void setChemionScatRate(double rate) { + m_chemionScatRate = rate; + m_f0_ok = false; + } + +protected: + //! Calculate distribution function + void calculateDistributionFunction(); + + //! Calculate total cross section + void calculateTotalCrossSection(); + + //! Calculate total elastic cross section + void calculateTotalElasticCrossSection(); + + //! Set grid cache + void setGridCache(); + + //! The integral in [a, b] of x * u(x) exp[g * (x0 - x)] + //! assuming that u is linear with u(a) = u0 and u(b) = u1 + double integralPQ(double a, double b, double u0, double u1, + double g, double x0); + + //! Norm of electron energy distribution function + double norm(Eigen::VectorXd f); + + //! Vector g is used by matrix_PQ. + vector_fp vector_g(Eigen::VectorXd f0); + + //! The matrix of scattering-out and scattering-in + SpMat matrix_PQ(Eigen::VectorXd f0, vector_fp g, size_t k); + + //! matrix A represents equation (45) of ref. [1] + SpMat matrix_A(Eigen::VectorXd f0); + + //! An iteration of solving electron energy distribution function + Eigen::VectorXd iterate(Eigen::VectorXd f0, double delta = 1e14); + + //! Iterate until convergence and obtain EEDF + Eigen::VectorXd converge(Eigen::VectorXd f0); + + //! Reduced net production frequency. Equation (10) of ref. [1] + //! divided by N. + //! @param f0 EEDF + //! @param chem_rate Chemionization rate. This is an optional source of + //! electron. + double netProductionFreq(Eigen::VectorXd f0); + + //! Total electron cross section on the cell center of energy grid + vector_fp m_totalCrossSectionC; + + //! Total electron cross section on the cell boundary (i-1/2) of + //! energy grid + vector_fp m_totalCrossSectionB; + + //! vector of total elastic cross section weighted with mass ratio + vector_fp m_sigmaElastic; + + //! Location of cell j for grid cache + std::vector> m_j; + + //! Location of cell i for grid cache + std::vector> m_i; + + //! Cross section at the boundaries of the overlap of cell i and j + std::vector> m_sigma; - void setElectronTemperature(double Te); + //! The energy boundaries of the overlap of cell i and j + std::vector> m_eps; - virtual void calculateDistributionFunction(); + //! Set chemionization scattering-in rate + double m_chemionScatRate; }; } diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 17650c22c2e..af81f574f6f 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -159,8 +159,14 @@ cdef extern from "cantera/electron/Electron.h" namespace "Cantera": #Properties double grid(size_t) size_t nPoints() - double electronMobility(double); - double electronDiffusivity(double); + double electronMobility(double) + double electronDiffusivity(double) + double meanElectronEnergy() + double reducedElectricField() + void setReducedElectricField(double) + double electronTemperature() + void setChemionScatRate(double) + void setBoltzmannSolver(size_t, double, double, double, double, cbool) # initialization cbool addElectronCrossSection(shared_ptr[CxxElectronCrossSection]) except +translate_exception diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/electron.pyx index 6fcbdd1efa2..63605a37945 100644 --- a/interfaces/cython/cantera/electron.pyx +++ b/interfaces/cython/cantera/electron.pyx @@ -11,19 +11,16 @@ cdef class Electron(_SolutionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - property electron_energy_grid: - """ The grid of electron energy """ + def set_electron_energy_grid(self, grid): + """ Set the grid of cell boundary of electron energy [eV]""" + cdef np.ndarray[np.double_t, ndim=1] data = \ + np.ascontiguousarray(grid, dtype=np.double) + self.electron.setupGrid(len(data), &data[0]) + + property electron_temperature: + """electron temperature""" def __get__(self): - cdef np.ndarray[np.double_t, ndim=1] grid = np.empty(self.electron.nPoints()) - cdef int i - for i in range(self.electron.nPoints()): - grid[i] = self.electron.grid(i) - return grid - - def __set__(self, grid): - cdef np.ndarray[np.double_t, ndim=1] data = \ - np.ascontiguousarray(grid, dtype=np.double) - self.electron.setupGrid(len(data), &data[0]) + return self.electron.electronTemperature() def electron_mobility(self, N): """electron mobility [m^2/V/s)]""" @@ -33,6 +30,27 @@ cdef class Electron(_SolutionBase): """electron diffusivity [m^2/s]""" return self.electron.electronDiffusivity(N) + def set_chemionization_scattering_rate(self, rate): + """ Set chemionization scattering-in rate """ + self.electron.setChemionScatRate(rate) + + def set_boltzmann_solver(self, maxn=100, rtol=1e-5, delta0=1e14, + m=4.0, init_kTe=0.0, warn=True): + """ Set boltzmann solver""" + self.electron.setBoltzmannSolver(maxn, rtol, delta0, m, init_kTe, warn) + + property mean_electron_energy: + """mean electron energy [eV]""" + def __get__(self): + return self.electron.meanElectronEnergy() + + property reduced_electric_field: + """reduced electric field strength [V-m2]""" + def __get__(self): + return self.electron.reducedElectricField() + def __set__(self, EN): + self.electron.setReducedElectricField(EN) + cdef class ElectronCrossSection: """ diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index 0f32baf3fc3..0c819a0b02c 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -13,21 +13,29 @@ namespace Cantera { Electron::Electron() - : m_electronCrossSectionTargets(0) - , m_electronCrossSectionKinds(0) + : m_targets(0) + , m_kinds(0) , m_ncs(0) - , m_points(1000) - , m_kTe(Undef) + , m_points(200) , m_kT(Undef) - , m_electronCrossSections_ok(false) + , m_EN(Undef) , m_f0_ok(false) + , m_maxn(100) + , m_rtol(1e-5) + , m_delta0(1e14) + , m_factorM(4.0) + , m_init_kTe(0.0) + , m_warn(true) { // default energy grid - m_eps.resize(m_points); + m_gridC.resize(m_points); + m_gridB.resize(m_points + 1); + m_f0.resize(m_points); for (size_t j = 0; j < m_points; j++) { - m_eps[j] = j / 100.0; + m_gridC[j] = j / 20.0 + 1.0 / 40.0; + m_gridB[j] = j / 20.0; } - + m_gridB[m_points] = 10.0; m_gamma = pow(2.0 * ElectronCharge / ElectronMass, 0.5); } @@ -39,16 +47,18 @@ void Electron::init(thermo_t* thermo) { m_thermo = thermo; m_f0_ok = false; + calculateElasticCrossSection(); } void Electron::update_T() { // signal that temperature-dependent quantities will need to be recomputed // before use, and update the local temperature. - m_kT = Boltzmann * m_thermo->temperature() / ElectronCharge; - - // flag for quantities need to be re-calculated - m_f0_ok = false; + double kT = Boltzmann * m_thermo->temperature() / ElectronCharge; + if (m_kT != kT) { + m_kT = kT; + m_f0_ok = false; + } } void Electron::update_C() @@ -59,14 +69,17 @@ void Electron::update_C() m_moleFractions.resize(m_ncs, 0.0); for (auto const& x : gas_composition) { bool not_found = true; - for (size_t i = 0; i < m_ncs; i++) { - if (m_electronCrossSectionTargets[i] == x.first) { - m_moleFractions[i] = x.second; + for (size_t k = 0; k < m_ncs; k++) { + if (m_targets[k] == x.first) { + if (m_moleFractions[k] != x.second) { + m_moleFractions[k] = x.second; + m_f0_ok = false; + } not_found = false; } } if (not_found) { - if (x.second > 0.01) { + if (x.second > 0.01 && m_warn) { writelog("Cantera::Electron::update_C"); writelog("\n"); writelog("Warning: The mole fraction of species {} is more than 0.01", x.first); @@ -75,28 +88,15 @@ void Electron::update_C() } } } - // flag for quantities need to be re-calculated - m_f0_ok = false; - m_totalCrossSection_ok = false; } bool Electron::addElectronCrossSection(shared_ptr ecs) { - if (ecs->kind == "EFFECTIVE") { - for (size_t i = 0; i < m_ncs; i++) { - if (m_electronCrossSectionTargets[i] == ecs->target) { - if (m_electronCrossSectionKinds[i] == "EFFECTIVE") { - throw CanteraError("Electron::addElectronCrossSection", - "Already contains a data of EFFECTIVE cross section for '{}'.", - ecs->target); - } - } - } - } ecs->validate(); - m_electronCrossSectionTargets.push_back(ecs->target); - m_electronCrossSectionKinds.push_back(ecs->kind); + m_targets.push_back(ecs->target); + m_kinds.push_back(ecs->kind); m_massRatios.push_back(ecs->mass_ratio); + m_thresholds.push_back(ecs->threshold); // transpose data std::vector> transdata(2, std::vector(ecs->data.size())); @@ -105,122 +105,89 @@ bool Electron::addElectronCrossSection(shared_ptr ecs) transdata[j][i] = ecs->data[i][j]; } } - m_electronCrossSectionData.push_back(transdata); - m_ncs++; - m_electronCrossSections_ok = false; - return true; -} + m_crossSections.push_back(transdata); -void Electron::setupGrid(size_t n, const double* eps) -{ - m_points = n; - m_eps.resize(n); - for (size_t j = 0; j < m_points; j++) { - m_eps[j] = eps[j]; + // shift factor + if (ecs->kind == "IONIZATION") { + m_shiftFactor.push_back(2); + } else { + m_shiftFactor.push_back(1); } - m_electronCrossSections_ok = false; - m_totalCrossSection_ok = false; - m_f0_ok = false; -} -void Electron::setupCrossSections() -{ - m_electronCrossSections.resize(m_ncs, std::vector(m_points)); - for (size_t i = 0; i < m_ncs; i++) { - vector_fp x = m_electronCrossSectionData[i][0]; - vector_fp y = m_electronCrossSectionData[i][1]; - if (x[0] > 0.0) { - x.insert(x.begin(), 0.0); - y.insert(y.begin(), m_electronCrossSectionData[i][1][0]); - } - x.push_back(1e8); - y.push_back(m_electronCrossSectionData[i][1].back()); - for (size_t j = 0; j < m_points; j++) { - m_electronCrossSections[i][j] = linearInterp(m_eps[j], x, y); - } + // scattering-in factor + if (ecs->kind == "IONIZATION") { + m_inFactor.push_back(2); + } else if (ecs->kind == "ATTACHMENT") { + m_inFactor.push_back(0); + } else { + m_inFactor.push_back(1); } - m_electronCrossSections_ok = true; -} -void Electron::calculateTotalCrossSection() -{ - if (m_electronCrossSections_ok == false) { - setupCrossSections(); - } - m_totalCrossSection.resize(m_points, 0.0); - m_attachCrossSection.resize(m_points, 0.0); - m_ionizCrossSection.resize(m_points, 0.0); - for (size_t j = 0; j < m_points; j++) { - for (size_t i = 0; i < m_ncs; i++) { - if (m_electronCrossSectionKinds[i] == "EFFECTIVE") { - m_totalCrossSection[j] += m_moleFractions[i] * m_electronCrossSections[i][j]; - } else if (m_electronCrossSectionKinds[i] == "ATTACHMENT") { - m_attachCrossSection[j] += m_moleFractions[i] * m_electronCrossSections[i][j]; - } else if (m_electronCrossSectionKinds[i] == "IONIZATION") { - m_ionizCrossSection[j] += m_moleFractions[i] * m_electronCrossSections[i][j]; + if (ecs->kind == "EFFECTIVE") { + for (size_t k = 0; k < m_ncs; k++) { + if (m_targets[k] == ecs->target && m_kinds[k] == ecs->kind) { + throw CanteraError("Electron::addElectronCrossSection", + "Already contains a data of EFFECTIVE cross section for '{}'.", + ecs->target); } } + // list effective + m_kEffective.push_back(m_ncs); + // add elastic cross section + m_targets.push_back(ecs->target); + m_kinds.push_back("ELASTIC"); + m_massRatios.push_back(ecs->mass_ratio); + m_thresholds.push_back(ecs->threshold); + m_crossSections.push_back(transdata); + m_shiftFactor.push_back(1); + m_inFactor.push_back(1); + m_ncs++; + // list elastic + m_kElastic.push_back(m_ncs); + } else { + // list inelastic + m_kInelastic.push_back(m_ncs); } - m_totalCrossSection_ok = true; -} -double Electron::netProductionFrequency(const vector_fp& f0) -{ - if (m_totalCrossSection_ok == false) { - calculateTotalCrossSection(); - } - double vi = 0.0; - if (f0.size() != m_points) { - throw CanteraError("Electron::netProductionFrequency", - "The size of input vector must equal to grid points, {}.", - m_points); - } - for (size_t j = 0; j < m_points - 1; j++) { - double left = (m_ionizCrossSection[j] - m_attachCrossSection[j]) * m_eps[j] * f0[j]; - double right = (m_ionizCrossSection[j+1] - m_attachCrossSection[j+1]) * m_eps[j+1] * f0[j+1]; - vi += 0.5 * (left + right) * (m_eps[j+1] - m_eps[j]); - } - return vi; -} + // add one to number of cross sections + m_ncs++; -void Electron::calculateDistributionFunction() -{ - update_T(); - update_C(); - calculateTotalCrossSection(); - m_f0.resize(m_points); - m_df0.resize(m_points); - m_f0_ok = true; + m_f0_ok = false; + + return true; } -double Electron::electronDiffusivity(double N) +void Electron::calculateElasticCrossSection() { - if (m_f0_ok == false) { - calculateDistributionFunction(); - } - double vi = netProductionFrequency(m_f0); - vector_fp y(m_points, 0.0); - for (size_t j = 0; j < m_points; j++) { - if (m_eps[j] != 0.0) { - y[j] = m_eps[j] * m_f0[j] / (m_totalCrossSection[j] + vi / pow(m_eps[j], 0.5)); + for (size_t ke : m_kElastic) { + for (size_t k : m_kInelastic) { + if (m_targets[k] == m_targets[ke]) { + vector_fp x = m_crossSections[k][0]; + vector_fp y = m_crossSections[k][1]; + for (size_t i = 0; i < m_crossSections[ke][0].size(); i++) { + m_crossSections[ke][1][i] -= linearInterp(m_crossSections[ke][0][i], x, y); + } + } + } + // replace negative values with zero. + for (size_t i = 0; i < m_crossSections[ke][0].size(); i++) { + m_crossSections[ke][1][i] = std::max(0.0, m_crossSections[ke][1][i]); } } - return 1./3. * m_gamma * simpsonQuadrature(m_eps, y) / N; } -double Electron::electronMobility(double N) +void Electron::setupGrid(size_t n, const double* eps) { - if (m_f0_ok == false) { - calculateDistributionFunction(); - } - double vi = netProductionFrequency(m_f0); - vector_fp y(m_points, 0.0); - for (size_t j = 0; j < m_points; j++) { - if (m_eps[j] != 0.0) { - y[j] = m_eps[j] * m_df0[j] / (m_totalCrossSection[j] + vi / pow(m_eps[j], 0.5)); - } + m_points = n-1; + m_gridC.resize(n-1); + m_gridB.resize(n); + m_f0.resize(m_points); + m_gridB[n-1] = eps[n-1]; + for (size_t i = 0; i < m_points; i++) { + m_gridB[i] = eps[i]; + m_gridC[i] = 0.5 * (eps[i] + eps[i+1]); } - return -1./3. * m_gamma * simpsonQuadrature(m_eps, y) / N; + m_f0_ok = false; } } diff --git a/src/electron/ElectronCrossSection.cpp b/src/electron/ElectronCrossSection.cpp index 60f334e6dc7..b2c7ac55c82 100644 --- a/src/electron/ElectronCrossSection.cpp +++ b/src/electron/ElectronCrossSection.cpp @@ -18,11 +18,13 @@ ElectronCrossSection::ElectronCrossSection() ElectronCrossSection::ElectronCrossSection(const std::string& kind_, const std::string& target_, const std::vector> data_, - double mass_ratio_) + double mass_ratio_, + double threshold_) : kind(kind_) , target(target_) , data(data_) , mass_ratio(mass_ratio_) + , threshold(threshold_) { } @@ -55,6 +57,12 @@ void ElectronCrossSection::validate() "Invalid cross section value of type '{}' for '{}'. " "Cross section must starts at zero.", kind, target); } + } else if (kind == "EXCITATION") { + if (data[0][1] != 0.0) { + throw CanteraError("ElectronCrossSection::validate", + "Invalid cross section value of type '{}' for '{}'. " + "Cross section must starts at zero.", kind, target); + } } else { throw CanteraError("ElectronCrossSection::validate", "'{}' is an unknown type of cross section data.", kind); @@ -69,11 +77,13 @@ unique_ptr newElectronCrossSection(const AnyMap& node) if (ecs->kind == "EFFECTIVE") { ecs->mass_ratio = node["mass_ratio"].asDouble(); + } else if (ecs->kind != "ATTACHMENT") { + ecs->threshold = node["threshold"].asDouble(); } // Store all unparsed keys in the "extra" map const static std::set known_keys{ - "kind", "target", "data", "mass_ratio" + "kind", "target", "data", "mass_ratio", "threshold" }; for (const auto& item : node) { diff --git a/src/electron/ElectronFactory.cpp b/src/electron/ElectronFactory.cpp index 8319e89a26b..c50958e9c35 100644 --- a/src/electron/ElectronFactory.cpp +++ b/src/electron/ElectronFactory.cpp @@ -32,8 +32,8 @@ Electron* ElectronFactory::newElectron(const std::string& model) unique_ptr newElectron(const AnyMap& rootNode, thermo_t* phase) { unique_ptr electron(newElectron(rootNode["electron"].asString())); - electron->init(phase); addElectronCrossSections(*electron, rootNode["cross_section"]); + electron->init(phase); return electron; } diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index c664e6f987a..cb985142c15 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -4,28 +4,385 @@ #include "cantera/electron/WeakIonGasElectron.h" #include "cantera/electron/ElectronFactory.h" #include "cantera/base/utilities.h" +#include "cantera/numerics/funcs.h" +#include namespace Cantera { WeakIonGasElectron::WeakIonGasElectron() + : m_chemionScatRate(0.0) { } -void WeakIonGasElectron::setElectronTemperature(double Te) +void WeakIonGasElectron::calculateTotalCrossSection() { - m_kTe = Boltzmann * Te / ElectronCharge; - m_f0_ok = false; + m_totalCrossSectionC.clear(); + m_totalCrossSectionC.resize(m_points, 0.0); + m_totalCrossSectionB.clear(); + m_totalCrossSectionB.resize(m_points + 1, 0.0); + for (size_t k : m_kEffective) { + vector_fp x = m_crossSections[k][0]; + vector_fp y = m_crossSections[k][1]; + for (size_t i = 0; i < m_points; i++) { + m_totalCrossSectionC[i] += m_moleFractions[k] * linearInterp(m_gridC[i], x, y); + } + for (size_t i = 0; i < m_points + 1; i++) { + m_totalCrossSectionB[i] += m_moleFractions[k] * linearInterp(m_gridB[i], x, y); + } + } +} + +void WeakIonGasElectron::setGridCache() +{ + m_sigma.clear(); + m_sigma.resize(m_ncs); + m_eps.clear(); + m_eps.resize(m_ncs); + m_j.clear(); + m_j.resize(m_ncs); + m_i.clear(); + m_i.resize(m_ncs); + for (size_t k = 0; k < m_ncs; k++) { + vector_fp x = m_crossSections[k][0]; + vector_fp y = m_crossSections[k][1]; + vector_fp eps1(m_points + 1); + for (size_t i = 0; i < m_points + 1; i++) { + eps1[i] = m_shiftFactor[k] * m_gridB[i] + m_thresholds[k]; + eps1[i] = std::max(eps1[i], m_gridB[0] + 1e-9); + eps1[i] = std::min(eps1[i], m_gridB[m_points] - 1e-9); + } + + vector_fp nodes = eps1; + for (size_t i = 0; i < m_points + 1; i++) { + if (m_gridB[i] >= eps1[0] && m_gridB[i] <= eps1[m_points]) { + nodes.push_back(m_gridB[i]); + } + } + for (size_t i = 0; i < x.size(); i++) { + if (x[i] >= eps1[0] && x[i] <= eps1[m_points]) { + nodes.push_back(x[i]); + } + } + + std::sort(nodes.begin(), nodes.end()); + vector_fp::iterator last = std::unique(nodes.begin(), nodes.end()); + nodes.resize(std::distance(nodes.begin(), last)); + vector_fp sigma0(nodes.size()); + for (size_t i = 0; i < nodes.size(); i++) { + sigma0[i] = linearInterp(nodes[i], x, y); + } + + // search position of cell j + for (size_t i = 1; i < nodes.size(); i++) { + vector_fp::iterator low; + low = std::lower_bound(m_gridB.begin(), m_gridB.end(), nodes[i]); + m_j[k].push_back(low - m_gridB.begin() - 1); + } + + // search position of cell i + for (size_t i = 1; i < nodes.size(); i++) { + vector_fp::iterator low; + low = std::lower_bound(eps1.begin(), eps1.end(), nodes[i]); + m_i[k].push_back(low - eps1.begin() - 1); + } + + // construct sigma + for (size_t i = 0; i < nodes.size() - 1; i++) { + vector_fp sigma{sigma0[i], sigma0[i+1]}; + m_sigma[k].push_back(sigma); + } + + // construct eps + for (size_t i = 0; i < nodes.size() - 1; i++) { + vector_fp eps{nodes[i], nodes[i+1]}; + m_eps[k].push_back(eps); + } + } +} + +void WeakIonGasElectron::calculateTotalElasticCrossSection() +{ + m_sigmaElastic.clear(); + m_sigmaElastic.resize(m_points, 0.0); + for (size_t k : m_kElastic) { + vector_fp x = m_crossSections[k][0]; + vector_fp y = m_crossSections[k][1]; + for (size_t i = 0; i < m_points; i++) { + m_sigmaElastic[i] += 2.0 * m_massRatios[k] * m_moleFractions[k] * + linearInterp(m_gridB[i], x, y); + } + } } void WeakIonGasElectron::calculateDistributionFunction() { - Electron::calculateDistributionFunction(); - if (m_kTe == Undef) { - m_kTe = m_kT; + // check if T or C is changed + update_T(); + update_C(); + if (m_f0_ok == true) { + return; } + + calculateTotalCrossSection(); + calculateTotalElasticCrossSection(); + setGridCache(); + + if (m_init_kTe == 0.0) { + m_init_kTe = m_kT; + } + for (size_t j = 0; j < m_points; j++) { - m_f0[j] = 2.0 * pow(1.0/Pi, 0.5) * pow(m_kTe, -3./2.) * std::exp(-m_eps[j]/m_kTe); - m_df0[j] = -2.0 * pow(1.0/Pi, 0.5) * pow(m_kTe, -5./2.) * std::exp(-m_eps[j]/m_kTe); + m_f0(j) = 2.0 * pow(1.0/Pi, 0.5) * pow(m_init_kTe, -3./2.) * + std::exp(-m_gridC[j]/m_init_kTe); + } + + if (m_EN != Undef) { + m_f0 = converge(m_f0); + } + m_f0_ok = true; +} + +double WeakIonGasElectron::norm(Eigen::VectorXd f) +{ + vector_fp p(f.size()); + for (int i = 0; i < f.size(); i++) { + p[i] = f(i) * pow(m_gridC[i], 0.5); + } + return simpsonQuadrature(m_gridC, p); +} + +double WeakIonGasElectron::integralPQ(double a, double b, double u0, double u1, + double g, double x0) +{ + double A1; + double A2; + if (g != 0.0) { + double expm1a = std::expm1(g * (-a + x0)); + double expm1b = std::expm1(g * (-b + x0)); + double ag = a * g; + double ag1 = ag + 1; + double bg = b * g; + double bg1 = bg + 1; + A1 = (expm1a * ag1 + ag - expm1b * bg1 - bg) / (g*g); + A2 = (expm1a * (2 * ag1 + ag * ag) + ag * (ag + 2) - + expm1b * (2 * bg1 + bg * bg) - bg * (bg + 2)) / (g*g*g); + } else { + A1 = 0.5 * (b*b - a*a); + A2 = 1.0 / 3.0 * (b*b*b - a*a*a); + } + + // The interpolation formula of u(x) = c0 + c1 * x + double c0 = (a * u1 - b * u0) / (a - b); + double c1 = (u0 - u1) / (a - b); + + return c0 * A1 + c1 * A2; +} + +vector_fp WeakIonGasElectron::vector_g(Eigen::VectorXd f0) +{ + vector_fp g(m_points, 0.0); + g[0] = std::log(f0(1)/f0(0)) / (m_gridC[1] - m_gridC[0]); + double N = m_points - 1; + g[N] = std::log(f0(N)/f0(N-1)) / (m_gridC[N] - m_gridC[N-1]); + for (size_t i = 1; i < m_points - 1; i++) { + g[i] = std::log(f0(i+1)/f0(i-1)) / (m_gridC[i+1] - m_gridC[i-1]); + } + return g; +} + +SpMat WeakIonGasElectron::matrix_PQ(Eigen::VectorXd f0, vector_fp g, size_t k) +{ + std::vector tripletList; + for (size_t n = 0; n < m_eps[k].size(); n++) { + double eps_a = m_eps[k][n][0]; + double eps_b = m_eps[k][n][1]; + double sigma_a = m_sigma[k][n][0]; + double sigma_b = m_sigma[k][n][1]; + double i = m_i[k][n]; + double j = m_j[k][n]; + double r = integralPQ(eps_a, eps_b, sigma_a, sigma_b, g[j], m_gridC[j]); + double q = m_inFactor[k] * m_gamma * m_moleFractions[k] * r; + double p = - m_gamma * m_moleFractions[k] * r; + tripletList.push_back(T(i, j, q)); + tripletList.push_back(T(j, j, p)); + } + SpMat PQ(m_points, m_points); + PQ.setFromTriplets(tripletList.begin(), tripletList.end()); + return PQ; +} + +SpMat WeakIonGasElectron::matrix_A(Eigen::VectorXd f0) +{ + vector_fp a0(m_points + 1); + vector_fp a1(m_points + 1); + size_t N = m_points - 1; + // Scharfetter-Gummel scheme + double nu = netProductionFreq(f0); + a0[0] = NAN; + a1[0] = NAN; + a0[N+1] = NAN; + a1[N+1] = NAN; + for (size_t j = 1; j < m_points; j++) { + double sigma_tilde = m_totalCrossSectionB[j] + nu / pow(m_gridB[j], 0.5) / m_gamma; + double W = -m_gamma * m_gridB[j] * m_gridB[j] * m_sigmaElastic[j]; + double DA = m_gamma / 3.0 * m_EN * m_EN * m_gridB[j]; + double DB = m_gamma * m_kT * m_gridB[j] * m_gridB[j] * m_sigmaElastic[j]; + double D = DA / sigma_tilde + DB; + double z = W * (m_gridC[j] - m_gridC[j-1]) / D; + a0[j] = W / (1 - std::exp(-z)); + a1[j] = W / (1 - std::exp(z)); + } + + std::vector tripletList; + // center diagonal + // zero flux b.c. at energy = 0 + tripletList.push_back(T(0, 0, a0[1])); + for (size_t j = 1; j < m_points - 1; j++) { + tripletList.push_back(T(j, j, a0[j+1] - a1[j])); + } + + // upper diagonal + for (size_t j = 0; j < m_points - 1; j++) { + tripletList.push_back(T(j, j+1, a1[j+1])); + } + + // lower diagonal + for (size_t j = 1; j < m_points; j++) { + tripletList.push_back(T(j, j-1, -a0[j])); + } + + // zero flux b.c. + tripletList.push_back(T(N, N, -a1[N])); + + SpMat A(m_points, m_points); + A.setFromTriplets(tripletList.begin(), tripletList.end()); + + //plus G + SpMat G(m_points, m_points); + for (size_t i = 0; i < m_points; i++) { + G.insert(i,i) = 2.0 / 3.0 * (pow(m_gridB[i+1], 1.5) - pow(m_gridB[i], 1.5)) * nu; + } + return A + G; +} + +Eigen::VectorXd WeakIonGasElectron::iterate(Eigen::VectorXd f0, double delta) +{ + SpMat PQ(m_points, m_points); + vector_fp g = vector_g(f0); + for (size_t k : m_kInelastic) { + PQ += matrix_PQ(f0, g, k); + } + + SpMat A = matrix_A(f0); + SpMat I(m_points, m_points); + for (size_t i = 0; i < m_points; i++) { + I.insert(i,i) = 1.0; + } + A -= PQ; + A *= delta; + A += I; + + // add chemionization scattering-in rate at the first grid + f0(0) += m_chemionScatRate; + + // solve f0 + Eigen::SparseLU solver(A); + Eigen::VectorXd f1 = solver.solve(f0); + + f1 *= 1.0 / norm(f1); + return f1; +} + +Eigen::VectorXd WeakIonGasElectron::converge(Eigen::VectorXd f0) +{ + double err0 = 0.0; + double err1 = 0.0; + double delta = m_delta0; + for (size_t n = 0; n < m_maxn; n++) { + if (0.0 < err1 && err1 < err0) { + // log extrapolation attempting to reduce the error a factor m + delta *= std::log(m_factorM) / (std::log(err0) - std::log(err1)); + } + Eigen::VectorXd f1 = iterate(f0, delta); + err0 = err1; + Eigen::VectorXd Df0(m_points); + for (size_t i = 0; i < m_points; i++) { + Df0(i) = std::abs(f0(i) - f1(i)); + } + err1 = norm(Df0); + if (err1 < m_rtol) { + return f1; + } + f0 = f1; + } + throw CanteraError("WeakIonGasElectron::converge", "Convergence failed"); +} + +double WeakIonGasElectron::netProductionFreq(Eigen::VectorXd f0) +{ + double nu = m_chemionScatRate; + vector_fp g = vector_g(f0); + + for (size_t k = 0; k < m_ncs; k++) { + if (m_kinds[k] == "IONIZATION" || + m_kinds[k] == "ATTACHMENT") { + SpMat PQ = matrix_PQ(f0, g, k); + Eigen::VectorXd s = PQ * f0; + for (size_t i = 0; i < m_points; i++) { + nu += s[i]; + } + } + } + return nu; +} + +double WeakIonGasElectron::electronDiffusivity(double N) +{ + calculateDistributionFunction(); + vector_fp y(m_points, 0.0); + double nu = netProductionFreq(m_f0); + for (size_t i = 0; i < m_points; i++) { + if (m_gridC[i] != 0.0) { + y[i] = m_gridC[i] * m_f0(i) / + (m_totalCrossSectionC[i] + nu / m_gamma / pow(m_gridC[i], 0.5)); + } + } + return 1./3. * m_gamma * simpsonQuadrature(m_gridC, y) / N; +} + +double WeakIonGasElectron::electronMobility(double N) +{ + calculateDistributionFunction(); + double nu = netProductionFreq(m_f0); + vector_fp y(m_points + 1, 0.0); + for (size_t i = 1; i < m_points; i++) { + // calculate df0 at i-1/2 + double df0 = (m_f0(i) - m_f0(i-1)) / (m_gridC[i] - m_gridC[i-1]); + if (m_gridB[i] != 0.0) { + y[i] = m_gridB[i] * df0 / + (m_totalCrossSectionB[i] + nu / m_gamma / pow(m_gridB[i], 0.5)); + } + } + return -1./3. * m_gamma * simpsonQuadrature(m_gridB, y) / N; +} + +double WeakIonGasElectron::meanElectronEnergy() +{ + calculateDistributionFunction(); + double sum = 0; + for (size_t i = 0; i < m_points - 1; i++) { + sum += (pow(m_gridB[i+1], 2.5) - pow(m_gridB[i], 2.5)) * m_f0(i); + } + return 0.4 * sum; +} + +double WeakIonGasElectron::electronTemperature() +{ + double Te = 2./3. * meanElectronEnergy() / Boltzmann * ElectronCharge; + if (Te < m_thermo->temperature()) { + return m_thermo->temperature(); + } else { + return Te; } } From d476d31ab8ef580c5b62c061111ed50edfc9599f Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 28 Apr 2019 18:40:15 -0400 Subject: [PATCH 010/139] [interface] add electron_reaction to ctml_writer --- interfaces/cython/cantera/ctml_writer.py | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/interfaces/cython/cantera/ctml_writer.py b/interfaces/cython/cantera/ctml_writer.py index 3eb2b6f2cd0..52cc8c6abf4 100644 --- a/interfaces/cython/cantera/ctml_writer.py +++ b/interfaces/cython/cantera/ctml_writer.py @@ -1303,6 +1303,8 @@ def build(self, p): kfnode = r.addChild('rateCoeff') if self._type == '': self._kf = [self._kf] + elif self._type == 'electron': + self._kf = [self._kf] elif self._type == 'surface': self._kf = [self._kf] if self._rate_coeff_type: @@ -1355,6 +1357,36 @@ def build(self, p): #------------------- +class electron_reaction(reaction): + """ + An electron reaction. + """ + def __init__(self, + equation = '', + kf = None, + id = '', + order = '', + options = []): + """ + :param equation: + A string specifying the chemical equation. The reaction can be + written in either the association or dissociation directions, and + may be reversible or irreversible. + :param kf: + The rate coefficient for the forward direction. If a sequence of + three numbers is given, these will be interpreted as [A, b, E] in + the modified Arrhenius function. + :param id: + An optional identification string. If omitted, it defaults to a + four-digit numeric string beginning with 0001 for the first + reaction in the file. + :param options: Processing options, as described in + `Options `__. + """ + reaction.__init__(self, equation, kf, id, '', options) + self._type = 'electron' + + class three_body_reaction(reaction): """ A three-body reaction. From 34d0bc8c4c03c27bf0fc62c157792483b03cfc15 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 2 May 2019 12:12:03 -0400 Subject: [PATCH 011/139] [electron] change electronMobility and electronDiffusivity --- include/cantera/electron/Electron.h | 6 ++---- include/cantera/electron/WeakIonGasElectron.h | 4 ++-- interfaces/cython/cantera/_cantera.pxd | 4 ++-- interfaces/cython/cantera/electron.pyx | 10 ++++++---- src/electron/WeakIonGasElectron.cpp | 6 ++++-- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index 219d9046c68..2df4c56a7f5 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -55,12 +55,10 @@ class Electron void setupGrid(size_t n, const double* eps); //! electron diffusivity - //! @param N gas number density in SI - virtual double electronDiffusivity(double N)=0; + virtual double electronDiffusivity()=0; //! electron mobility - //! @param N gas number density in SI - virtual double electronMobility(double N)=0; + virtual double electronMobility()=0; //! mean electron energy virtual double meanElectronEnergy() = 0; diff --git a/include/cantera/electron/WeakIonGasElectron.h b/include/cantera/electron/WeakIonGasElectron.h index 111079f7a36..a53175c7cfe 100644 --- a/include/cantera/electron/WeakIonGasElectron.h +++ b/include/cantera/electron/WeakIonGasElectron.h @@ -41,8 +41,8 @@ class WeakIonGasElectron: public Electron public: WeakIonGasElectron(); - virtual double electronDiffusivity(double N); - virtual double electronMobility(double N); + virtual double electronDiffusivity(); + virtual double electronMobility(); virtual double meanElectronEnergy(); //! electron temperature diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index af81f574f6f..e11a9f2ec06 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -159,8 +159,8 @@ cdef extern from "cantera/electron/Electron.h" namespace "Cantera": #Properties double grid(size_t) size_t nPoints() - double electronMobility(double) - double electronDiffusivity(double) + double electronMobility() + double electronDiffusivity() double meanElectronEnergy() double reducedElectricField() void setReducedElectricField(double) diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/electron.pyx index 63605a37945..b9bb58e2d6b 100644 --- a/interfaces/cython/cantera/electron.pyx +++ b/interfaces/cython/cantera/electron.pyx @@ -22,13 +22,15 @@ cdef class Electron(_SolutionBase): def __get__(self): return self.electron.electronTemperature() - def electron_mobility(self, N): + property electron_mobility: """electron mobility [m^2/V/s)]""" - return self.electron.electronMobility(N) + def __get__(self): + return self.electron.electronMobility() - def electron_diffusivity(self, N): + property electron_diffusivity: """electron diffusivity [m^2/s]""" - return self.electron.electronDiffusivity(N) + def __get__(self): + return self.electron.electronDiffusivity() def set_chemionization_scattering_rate(self, rate): """ Set chemionization scattering-in rate """ diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index cb985142c15..90aa9409cc4 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -336,7 +336,7 @@ double WeakIonGasElectron::netProductionFreq(Eigen::VectorXd f0) return nu; } -double WeakIonGasElectron::electronDiffusivity(double N) +double WeakIonGasElectron::electronDiffusivity() { calculateDistributionFunction(); vector_fp y(m_points, 0.0); @@ -347,10 +347,11 @@ double WeakIonGasElectron::electronDiffusivity(double N) (m_totalCrossSectionC[i] + nu / m_gamma / pow(m_gridC[i], 0.5)); } } + double N = m_thermo->pressure() / Boltzmann / m_thermo->temperature(); return 1./3. * m_gamma * simpsonQuadrature(m_gridC, y) / N; } -double WeakIonGasElectron::electronMobility(double N) +double WeakIonGasElectron::electronMobility() { calculateDistributionFunction(); double nu = netProductionFreq(m_f0); @@ -363,6 +364,7 @@ double WeakIonGasElectron::electronMobility(double N) (m_totalCrossSectionB[i] + nu / m_gamma / pow(m_gridB[i], 0.5)); } } + double N = m_thermo->pressure() / Boltzmann / m_thermo->temperature(); return -1./3. * m_gamma * simpsonQuadrature(m_gridB, y) / N; } From 05bfbd9e5f13e608bd42fc831da8810e2f785342 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 2 May 2019 15:40:57 -0400 Subject: [PATCH 012/139] fix init kte --- src/electron/WeakIonGasElectron.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index 90aa9409cc4..31415dbf4e7 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -127,13 +127,14 @@ void WeakIonGasElectron::calculateDistributionFunction() calculateTotalElasticCrossSection(); setGridCache(); - if (m_init_kTe == 0.0) { - m_init_kTe = m_kT; + double kT = m_kT; + if (m_init_kTe != 0.0) { + kT = m_init_kTe; } for (size_t j = 0; j < m_points; j++) { - m_f0(j) = 2.0 * pow(1.0/Pi, 0.5) * pow(m_init_kTe, -3./2.) * - std::exp(-m_gridC[j]/m_init_kTe); + m_f0(j) = 2.0 * pow(1.0/Pi, 0.5) * pow(kT, -3./2.) * + std::exp(-m_gridC[j]/kT); } if (m_EN != Undef) { From d57e3e3baf6d8ffaca9169c25abc5dd70cf7b83c Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 2 May 2019 16:08:52 -0400 Subject: [PATCH 013/139] change m_EN to m_E --- include/cantera/electron/Electron.h | 15 +++++++++------ interfaces/cython/cantera/_cantera.pxd | 4 ++-- interfaces/cython/cantera/electron.pyx | 8 ++++---- src/electron/Electron.cpp | 3 ++- src/electron/WeakIonGasElectron.cpp | 10 ++++------ 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index 2df4c56a7f5..bccc21bde77 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -67,14 +67,14 @@ class Electron void init(thermo_t* thermo); //! Reduced electric field - double reducedElectricField() const { - return m_EN; + double electricField() const { + return m_E; } //! Set reduced electric field - void setReducedElectricField(double EN) { - if (m_EN != EN) { - m_EN = EN; + void setElectricField(double E) { + if (m_E != E) { + m_E = E; m_f0_ok = false; } } @@ -159,7 +159,7 @@ class Electron double m_kT; //! reduced electric field - double m_EN; + double m_E; //! normalized electron energy distribution function Eigen::VectorXd m_f0; @@ -209,6 +209,9 @@ class Electron //! Flag of warning of insufficient cross section data bool m_warn; + + //! Gas number density + double m_N; }; } diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index e11a9f2ec06..7d0edc30be4 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -162,8 +162,8 @@ cdef extern from "cantera/electron/Electron.h" namespace "Cantera": double electronMobility() double electronDiffusivity() double meanElectronEnergy() - double reducedElectricField() - void setReducedElectricField(double) + double electricField() + void setElectricField(double) double electronTemperature() void setChemionScatRate(double) void setBoltzmannSolver(size_t, double, double, double, double, cbool) diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/electron.pyx index b9bb58e2d6b..5bff774e376 100644 --- a/interfaces/cython/cantera/electron.pyx +++ b/interfaces/cython/cantera/electron.pyx @@ -46,12 +46,12 @@ cdef class Electron(_SolutionBase): def __get__(self): return self.electron.meanElectronEnergy() - property reduced_electric_field: + property electric_field: """reduced electric field strength [V-m2]""" def __get__(self): - return self.electron.reducedElectricField() - def __set__(self, EN): - self.electron.setReducedElectricField(EN) + return self.electron.electricField() + def __set__(self, E): + self.electron.setElectricField(E) cdef class ElectronCrossSection: diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index 0c819a0b02c..b233a42b9f1 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -18,7 +18,7 @@ Electron::Electron() , m_ncs(0) , m_points(200) , m_kT(Undef) - , m_EN(Undef) + , m_E(Undef) , m_f0_ok(false) , m_maxn(100) , m_rtol(1e-5) @@ -57,6 +57,7 @@ void Electron::update_T() double kT = Boltzmann * m_thermo->temperature() / ElectronCharge; if (m_kT != kT) { m_kT = kT; + m_N = m_thermo->pressure() / Boltzmann / m_thermo->temperature(); m_f0_ok = false; } } diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index 31415dbf4e7..3e2a38d7173 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -137,7 +137,7 @@ void WeakIonGasElectron::calculateDistributionFunction() std::exp(-m_gridC[j]/kT); } - if (m_EN != Undef) { + if (m_E != Undef) { m_f0 = converge(m_f0); } m_f0_ok = true; @@ -226,7 +226,7 @@ SpMat WeakIonGasElectron::matrix_A(Eigen::VectorXd f0) for (size_t j = 1; j < m_points; j++) { double sigma_tilde = m_totalCrossSectionB[j] + nu / pow(m_gridB[j], 0.5) / m_gamma; double W = -m_gamma * m_gridB[j] * m_gridB[j] * m_sigmaElastic[j]; - double DA = m_gamma / 3.0 * m_EN * m_EN * m_gridB[j]; + double DA = m_gamma / 3.0 * pow(m_E / m_N, 2.0) * m_gridB[j]; double DB = m_gamma * m_kT * m_gridB[j] * m_gridB[j] * m_sigmaElastic[j]; double D = DA / sigma_tilde + DB; double z = W * (m_gridC[j] - m_gridC[j-1]) / D; @@ -348,8 +348,7 @@ double WeakIonGasElectron::electronDiffusivity() (m_totalCrossSectionC[i] + nu / m_gamma / pow(m_gridC[i], 0.5)); } } - double N = m_thermo->pressure() / Boltzmann / m_thermo->temperature(); - return 1./3. * m_gamma * simpsonQuadrature(m_gridC, y) / N; + return 1./3. * m_gamma * simpsonQuadrature(m_gridC, y) / m_N; } double WeakIonGasElectron::electronMobility() @@ -365,8 +364,7 @@ double WeakIonGasElectron::electronMobility() (m_totalCrossSectionB[i] + nu / m_gamma / pow(m_gridB[i], 0.5)); } } - double N = m_thermo->pressure() / Boltzmann / m_thermo->temperature(); - return -1./3. * m_gamma * simpsonQuadrature(m_gridB, y) / N; + return -1./3. * m_gamma * simpsonQuadrature(m_gridB, y) / m_N; } double WeakIonGasElectron::meanElectronEnergy() From 9de848b96f163b3376aa1041e015eb9fd2e2b784 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 2 May 2019 23:49:35 -0400 Subject: [PATCH 014/139] [electron] add internal func electronTemperature and fix calEEDf to prevent Tetemperature()) { + for (size_t j = 0; j < m_points; j++) { + m_f0(j) = 2.0 * pow(1.0/Pi, 0.5) * pow(m_kT, -3./2.) * + std::exp(-m_gridC[j]/m_kT); + } + } } m_f0_ok = true; } @@ -387,4 +394,13 @@ double WeakIonGasElectron::electronTemperature() } } +double WeakIonGasElectron::electronTemperature(Eigen::VectorXd f0) +{ + double sum = 0; + for (size_t i = 0; i < m_points - 1; i++) { + sum += (pow(m_gridB[i+1], 2.5) - pow(m_gridB[i], 2.5)) * f0(i); + } + return 2./3. * 0.4 * sum / Boltzmann * ElectronCharge; +} + } From 597847dccad490e97992ea92235bcf22641856c9 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 3 May 2019 12:00:46 -0400 Subject: [PATCH 015/139] add elastic cs --- include/cantera/electron/Electron.h | 3 +++ src/electron/Electron.cpp | 22 ++++++++++++++++++---- src/electron/ElectronCrossSection.cpp | 11 +++++++++++ src/electron/WeakIonGasElectron.cpp | 14 ++++++++++++++ 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index bccc21bde77..a018a6f12a9 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -183,6 +183,9 @@ class Electron //! list effective std::vector m_kEffective; + //! list solo elastic + std::vector m_kSoloElastic; + //! flag of electron energy distribution function bool m_f0_ok; diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index b233a42b9f1..64a352a4ea7 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -126,10 +126,11 @@ bool Electron::addElectronCrossSection(shared_ptr ecs) if (ecs->kind == "EFFECTIVE") { for (size_t k = 0; k < m_ncs; k++) { - if (m_targets[k] == ecs->target && m_kinds[k] == ecs->kind) { - throw CanteraError("Electron::addElectronCrossSection", - "Already contains a data of EFFECTIVE cross section for '{}'.", - ecs->target); + if (m_targets[k] == ecs->target) + if (m_kinds[k] == "ELASTIC" || m_kinds[k] == "EFFECTIVE") { + throw CanteraError("Electron::addElectronCrossSection", + "Already contains a data of EFFECTIVE/ELASTIC cross section for '{}'.", + ecs->target); } } // list effective @@ -145,6 +146,19 @@ bool Electron::addElectronCrossSection(shared_ptr ecs) m_ncs++; // list elastic m_kElastic.push_back(m_ncs); + } else if (ecs->kind == "ELASTIC") { + for (size_t k = 0; k < m_ncs; k++) { + if (m_targets[k] == ecs->target) + if (m_kinds[k] == "ELASTIC" || m_kinds[k] == "EFFECTIVE") { + throw CanteraError("Electron::addElectronCrossSection", + "Already contains a data of EFFECTIVE/ELASTIC cross section for '{}'.", + ecs->target); + } + } + // list elastic + m_kElastic.push_back(m_ncs); + // list solo elastic + m_kSoloElastic.push_back(m_ncs); } else { // list inelastic m_kInelastic.push_back(m_ncs); diff --git a/src/electron/ElectronCrossSection.cpp b/src/electron/ElectronCrossSection.cpp index b2c7ac55c82..1fd11876f64 100644 --- a/src/electron/ElectronCrossSection.cpp +++ b/src/electron/ElectronCrossSection.cpp @@ -45,6 +45,17 @@ void ElectronCrossSection::validate() "Invalid mass ratio of type '{}' for '{}'. " "Mass ratio of electron to target must be in the range of 0 to 1.", kind, target); } + } else if (kind == "ELASTIC") { + if (data[0][0] != 0.0) { + throw CanteraError("ElectronCrossSection::validate", + "Invalid energy value of type '{}' for '{}'. " + "Energy must starts at zero.", kind, target); + } + if (mass_ratio >= 1.0 || mass_ratio < 0.0) { + throw CanteraError("ElectronCrossSection::validate", + "Invalid mass ratio of type '{}' for '{}'. " + "Mass ratio of electron to target must be in the range of 0 to 1.", kind, target); + } } else if (kind == "IONIZATION") { if (data[0][1] != 0.0) { throw CanteraError("ElectronCrossSection::validate", diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index 332d0627078..e3511d9d708 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -30,6 +30,20 @@ void WeakIonGasElectron::calculateTotalCrossSection() m_totalCrossSectionB[i] += m_moleFractions[k] * linearInterp(m_gridB[i], x, y); } } + for (size_t ke : m_kSoloElastic) { + for (size_t k = 0; k < m_ncs; k++) { + if (m_targets[k] == m_targets[ke]) { + vector_fp x = m_crossSections[k][0]; + vector_fp y = m_crossSections[k][1]; + for (size_t i = 0; i < m_points; i++) { + m_totalCrossSectionC[i] += m_moleFractions[k] * linearInterp(m_gridC[i], x, y); + } + for (size_t i = 0; i < m_points + 1; i++) { + m_totalCrossSectionB[i] += m_moleFractions[k] * linearInterp(m_gridB[i], x, y); + } + } + } + } } void WeakIonGasElectron::setGridCache() From cb946f3db17b7926d5cb65abb91b475700811d8a Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 3 May 2019 19:41:01 -0400 Subject: [PATCH 016/139] [electron] add electric frequency --- include/cantera/electron/Electron.h | 16 ++++++++++++++++ interfaces/cython/cantera/_cantera.pxd | 2 ++ interfaces/cython/cantera/electron.pyx | 7 +++++++ src/electron/Electron.cpp | 1 + src/electron/WeakIonGasElectron.cpp | 5 ++++- 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index a018a6f12a9..1ebdb7d0d1e 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -79,6 +79,19 @@ class Electron } } + //! Electric field frequency + double electricFieldFreq() const { + return m_F; + } + + //! Set electric field frequency + void setElectricFieldFreq(double F) { + if (m_F != F) { + m_F = F; + m_f0_ok = false; + } + } + /** * Set the parameters for the Boltzmann solver * @param maxn Maximum number of iterations @@ -161,6 +174,9 @@ class Electron //! reduced electric field double m_E; + //! electric field freq + double m_F; + //! normalized electron energy distribution function Eigen::VectorXd m_f0; diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 7d0edc30be4..8678f7b2ccb 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -163,7 +163,9 @@ cdef extern from "cantera/electron/Electron.h" namespace "Cantera": double electronDiffusivity() double meanElectronEnergy() double electricField() + double electricFieldFreq() void setElectricField(double) + void setElectricFieldFreq(double) double electronTemperature() void setChemionScatRate(double) void setBoltzmannSolver(size_t, double, double, double, double, cbool) diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/electron.pyx index 5bff774e376..eab861d71d4 100644 --- a/interfaces/cython/cantera/electron.pyx +++ b/interfaces/cython/cantera/electron.pyx @@ -53,6 +53,13 @@ cdef class Electron(_SolutionBase): def __set__(self, E): self.electron.setElectricField(E) + property electric_field_freq: + """electric field freq [Hz]""" + def __get__(self): + return self.electron.electricFieldFreq() + def __set__(self, F): + self.electron.setElectricFieldFreq(F) + cdef class ElectronCrossSection: """ diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index 64a352a4ea7..a9a0e6c60a6 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -19,6 +19,7 @@ Electron::Electron() , m_points(200) , m_kT(Undef) , m_E(Undef) + , m_F(0.0) , m_f0_ok(false) , m_maxn(100) , m_rtol(1e-5) diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index e3511d9d708..f233d6f691c 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -246,10 +246,13 @@ SpMat WeakIonGasElectron::matrix_A(Eigen::VectorXd f0) a1[N+1] = NAN; for (size_t j = 1; j < m_points; j++) { double sigma_tilde = m_totalCrossSectionB[j] + nu / pow(m_gridB[j], 0.5) / m_gamma; + double omega = 2 * Pi * m_F; + double q = omega / (m_N * m_gamma * pow(m_gridB[j], 0.5)); double W = -m_gamma * m_gridB[j] * m_gridB[j] * m_sigmaElastic[j]; + double F = sigma_tilde * sigma_tilde / (sigma_tilde * sigma_tilde + q * q); double DA = m_gamma / 3.0 * pow(m_E / m_N, 2.0) * m_gridB[j]; double DB = m_gamma * m_kT * m_gridB[j] * m_gridB[j] * m_sigmaElastic[j]; - double D = DA / sigma_tilde + DB; + double D = DA / sigma_tilde * F + DB; double z = W * (m_gridC[j] - m_gridC[j-1]) / D; a0[j] = W / (1 - std::exp(-z)); a1[j] = W / (1 - std::exp(z)); From 295986fda1a43e251690746515216dbe8af66422 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 6 May 2019 14:36:10 -0400 Subject: [PATCH 017/139] fix electron cross section reading --- src/electron/ElectronCrossSection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/electron/ElectronCrossSection.cpp b/src/electron/ElectronCrossSection.cpp index 1fd11876f64..67272033b1f 100644 --- a/src/electron/ElectronCrossSection.cpp +++ b/src/electron/ElectronCrossSection.cpp @@ -86,9 +86,9 @@ unique_ptr newElectronCrossSection(const AnyMap& node) node["target"].asString(), node["data"].asVector>())); - if (ecs->kind == "EFFECTIVE") { + if (ecs->kind == "EFFECTIVE" || ecs->kind == "ELASTIC") { ecs->mass_ratio = node["mass_ratio"].asDouble(); - } else if (ecs->kind != "ATTACHMENT") { + } else { ecs->threshold = node["threshold"].asDouble(); } From ee76231799ec3a2d7ecf419591fb5034fb10f19f Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 10 May 2019 18:26:35 -0400 Subject: [PATCH 018/139] [electron] add functions --- include/cantera/electron/Electron.h | 9 ++ include/cantera/electron/WeakIonGasElectron.h | 15 ++- interfaces/cython/cantera/_cantera.pxd | 2 + interfaces/cython/cantera/electron.pyx | 8 ++ src/electron/WeakIonGasElectron.cpp | 109 +++++++++++++++++- 5 files changed, 139 insertions(+), 4 deletions(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index 1ebdb7d0d1e..aa165788d6f 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -63,6 +63,15 @@ class Electron //! mean electron energy virtual double meanElectronEnergy() = 0; + //! elastic power loss + virtual double elasticPowerLoss() = 0; + + //! rate coefficient. [m^3/s] + virtual double rateCoefficient(size_t k) = 0; + + //! inverse rate coefficient. [m^3/s] + virtual double inverseRateCoefficient(size_t k) = 0; + //! initialize Electron. Need to be called after adding all cross sections. void init(thermo_t* thermo); diff --git a/include/cantera/electron/WeakIonGasElectron.h b/include/cantera/electron/WeakIonGasElectron.h index 02ff6b6020b..9c4df9e3e32 100644 --- a/include/cantera/electron/WeakIonGasElectron.h +++ b/include/cantera/electron/WeakIonGasElectron.h @@ -44,6 +44,13 @@ class WeakIonGasElectron: public Electron virtual double electronDiffusivity(); virtual double electronMobility(); virtual double meanElectronEnergy(); + virtual double powerGain(); + virtual double elasticPowerLoss(); + virtual double inverseRateCoefficient(size_t k); + virtual double rateCoefficient(size_t k); + + //! The real part of the mobility. This is used in power gain for case of AC. + double realMobility(); //! electron temperature //! If the reduced electric field is set, electron tempeature is calculated @@ -81,7 +88,13 @@ class WeakIonGasElectron: public Electron vector_fp vector_g(Eigen::VectorXd f0); //! The matrix of scattering-out and scattering-in - SpMat matrix_PQ(Eigen::VectorXd f0, vector_fp g, size_t k); + SpMat matrix_PQ(vector_fp g, size_t k); + + //! The matrix of scattering-out + SpMat matrix_P(vector_fp g, size_t k); + + //! The matrix of scattering-in + SpMat matrix_Q(vector_fp g, size_t k); //! matrix A represents equation (45) of ref. [1] SpMat matrix_A(Eigen::VectorXd f0); diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 8678f7b2ccb..ff4db54cdcf 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -162,6 +162,8 @@ cdef extern from "cantera/electron/Electron.h" namespace "Cantera": double electronMobility() double electronDiffusivity() double meanElectronEnergy() + double rateCoefficient(size_t) + double inverseRateCoefficient(size_t) double electricField() double electricFieldFreq() void setElectricField(double) diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/electron.pyx index eab861d71d4..7df5c964ef9 100644 --- a/interfaces/cython/cantera/electron.pyx +++ b/interfaces/cython/cantera/electron.pyx @@ -32,6 +32,14 @@ cdef class Electron(_SolutionBase): def __get__(self): return self.electron.electronDiffusivity() + def electron_rate_coefficient(self, k): + """rate coefficient of process k""" + return self.electron.rateCoefficient(k) + + def electron_inverse_rate_coefficient(self, k): + """inverse rate coefficient of process k""" + return self.electron.inverseRateCoefficient(k) + def set_chemionization_scattering_rate(self, rate): """ Set chemionization scattering-in rate """ self.electron.setChemionScatRate(rate) diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index f233d6f691c..f9b299c2259 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -212,7 +212,7 @@ vector_fp WeakIonGasElectron::vector_g(Eigen::VectorXd f0) return g; } -SpMat WeakIonGasElectron::matrix_PQ(Eigen::VectorXd f0, vector_fp g, size_t k) +SpMat WeakIonGasElectron::matrix_PQ(vector_fp g, size_t k) { std::vector tripletList; for (size_t n = 0; n < m_eps[k].size(); n++) { @@ -233,6 +233,43 @@ SpMat WeakIonGasElectron::matrix_PQ(Eigen::VectorXd f0, vector_fp g, size_t k) return PQ; } +SpMat WeakIonGasElectron::matrix_P(vector_fp g, size_t k) +{ + std::vector tripletList; + for (size_t n = 0; n < m_eps[k].size(); n++) { + double eps_a = m_eps[k][n][0]; + double eps_b = m_eps[k][n][1]; + double sigma_a = m_sigma[k][n][0]; + double sigma_b = m_sigma[k][n][1]; + double j = m_j[k][n]; + double r = integralPQ(eps_a, eps_b, sigma_a, sigma_b, g[j], m_gridC[j]); + double p = m_gamma * m_moleFractions[k] * r; + tripletList.push_back(T(j, j, p)); + } + SpMat P(m_points, m_points); + P.setFromTriplets(tripletList.begin(), tripletList.end()); + return P; +} + +SpMat WeakIonGasElectron::matrix_Q(vector_fp g, size_t k) +{ + std::vector tripletList; + for (size_t n = 0; n < m_eps[k].size(); n++) { + double eps_a = m_eps[k][n][0]; + double eps_b = m_eps[k][n][1]; + double sigma_a = m_sigma[k][n][0]; + double sigma_b = m_sigma[k][n][1]; + double i = m_i[k][n]; + double j = m_j[k][n]; + double r = integralPQ(eps_a, eps_b, sigma_a, sigma_b, g[j], m_gridC[j]); + double q = m_inFactor[k] * m_gamma * m_moleFractions[k] * r; + tripletList.push_back(T(i, j, q)); + } + SpMat Q(m_points, m_points); + Q.setFromTriplets(tripletList.begin(), tripletList.end()); + return Q; +} + SpMat WeakIonGasElectron::matrix_A(Eigen::VectorXd f0) { vector_fp a0(m_points + 1); @@ -295,7 +332,7 @@ Eigen::VectorXd WeakIonGasElectron::iterate(Eigen::VectorXd f0, double delta) SpMat PQ(m_points, m_points); vector_fp g = vector_g(f0); for (size_t k : m_kInelastic) { - PQ += matrix_PQ(f0, g, k); + PQ += matrix_PQ(g, k); } SpMat A = matrix_A(f0); @@ -351,7 +388,7 @@ double WeakIonGasElectron::netProductionFreq(Eigen::VectorXd f0) for (size_t k = 0; k < m_ncs; k++) { if (m_kinds[k] == "IONIZATION" || m_kinds[k] == "ATTACHMENT") { - SpMat PQ = matrix_PQ(f0, g, k); + SpMat PQ = matrix_PQ(g, k); Eigen::VectorXd s = PQ * f0; for (size_t i = 0; i < m_points; i++) { nu += s[i]; @@ -391,6 +428,72 @@ double WeakIonGasElectron::electronMobility() return -1./3. * m_gamma * simpsonQuadrature(m_gridB, y) / m_N; } +double WeakIonGasElectron::realMobility() +{ + calculateDistributionFunction(); + double nu = netProductionFreq(m_f0); + vector_fp y(m_points + 1, 0.0); + for (size_t i = 1; i < m_points; i++) { + // calculate df0 at i-1/2 + double df0 = (m_f0(i) - m_f0(i-1)) / (m_gridC[i] - m_gridC[i-1]); + if (m_gridB[i] != 0.0) { + double Q = m_totalCrossSectionB[i] + nu / m_gamma / pow(m_gridB[i], 0.5); + double q = 2.0 * Pi * m_F / (m_N * m_gamma * pow(m_gridB[i], 0.5)); + y[i] = m_gridB[i] * Q / (Q * Q + q * q) * df0; + } + } + return -1./3. * m_gamma * simpsonQuadrature(m_gridB, y) / m_N; +} + +double WeakIonGasElectron::powerGain() +{ + if (m_F != 0.0) { + return ElectronCharge * m_E * m_E * electronMobility(); + } else { + return ElectronCharge * m_E * m_E * realMobility(); + } +} + +double WeakIonGasElectron::elasticPowerLoss() +{ + double sum = 0.0; + vector_fp y(m_points + 1, 0.0); + for (size_t i = 1; i < m_points; i++) { + // calculate df0 at i-1/2 + double df0 = (m_f0(i) - m_f0(i-1)) / (m_gridC[i] - m_gridC[i-1]); + double f0 = 0.5 * (m_f0(i-1) + m_f0(i)); + y[i] = m_sigmaElastic[i] * (m_gridB[i] * m_gridB[i] * f0 + m_kT * df0); + } + sum += m_gamma * simpsonQuadrature(m_gridB, y); + return sum * m_N; +} + +double WeakIonGasElectron::rateCoefficient(size_t k) +{ + calculateDistributionFunction(); + vector_fp g = vector_g(m_f0); + SpMat P = matrix_P(g, k); + Eigen::VectorXd s = P * m_f0; + double sum = 0.0; + for (size_t i = 0; i < m_points; i++) { + sum += s[i]; + } + return sum; +} + +double WeakIonGasElectron::inverseRateCoefficient(size_t k) +{ + calculateDistributionFunction(); + vector_fp g = vector_g(m_f0); + SpMat Q = matrix_Q(g, k); + Eigen::VectorXd s = Q * m_f0; + double sum = 0.0; + for (size_t i = 0; i < m_points; i++) { + sum += s[i]; + } + return sum; +} + double WeakIonGasElectron::meanElectronEnergy() { calculateDistributionFunction(); From bffaf200aa8ce8ce6b7dc5dee3803bf519aeea37 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 12 May 2019 18:51:32 -0400 Subject: [PATCH 019/139] fix ElectronCrossSection --- .../cantera/electron/ElectronCrossSection.h | 8 +++---- src/electron/ElectronCrossSection.cpp | 22 +++++-------------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/include/cantera/electron/ElectronCrossSection.h b/include/cantera/electron/ElectronCrossSection.h index d285b893cbd..d151a269acb 100644 --- a/include/cantera/electron/ElectronCrossSection.h +++ b/include/cantera/electron/ElectronCrossSection.h @@ -21,10 +21,10 @@ class ElectronCrossSection public: ElectronCrossSection(); - //! Constructor - ElectronCrossSection(const std::string& kind, const std::string& target, - const std::vector> data, double mass_ratio=Undef, - double threshold=0.0); + // //! Constructor + // ElectronCrossSection(const std::string& kind, const std::string& target, + // const std::vector> data, double mass_ratio=Undef, + // double threshold=0.0); //! ElectronCrossSection objects are not copyable or assignable ElectronCrossSection(const ElectronCrossSection&) = delete; diff --git a/src/electron/ElectronCrossSection.cpp b/src/electron/ElectronCrossSection.cpp index 67272033b1f..5c7487c68c7 100644 --- a/src/electron/ElectronCrossSection.cpp +++ b/src/electron/ElectronCrossSection.cpp @@ -12,19 +12,8 @@ namespace Cantera { ElectronCrossSection::ElectronCrossSection() -{ -} - -ElectronCrossSection::ElectronCrossSection(const std::string& kind_, - const std::string& target_, - const std::vector> data_, - double mass_ratio_, - double threshold_) - : kind(kind_) - , target(target_) - , data(data_) - , mass_ratio(mass_ratio_) - , threshold(threshold_) + : mass_ratio(Undef) + , threshold(0.0) { } @@ -82,10 +71,11 @@ void ElectronCrossSection::validate() unique_ptr newElectronCrossSection(const AnyMap& node) { - unique_ptr ecs(new ElectronCrossSection(node["kind"].asString(), - node["target"].asString(), - node["data"].asVector>())); + unique_ptr ecs(new ElectronCrossSection()); + ecs->kind = node["kind"].asString(); + ecs->target = node["target"].asString(); + ecs->data = node["data"].asVector>(); if (ecs->kind == "EFFECTIVE" || ecs->kind == "ELASTIC") { ecs->mass_ratio = node["mass_ratio"].asDouble(); } else { From b57ca636fd8fb1af66f5fba27edf669c09f85acf Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 12 May 2019 19:18:19 -0400 Subject: [PATCH 020/139] [electron] add product --- include/cantera/electron/Electron.h | 3 +++ include/cantera/electron/ElectronCrossSection.h | 8 +++----- src/electron/Electron.cpp | 6 +++--- src/electron/ElectronCrossSection.cpp | 6 ++++-- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index aa165788d6f..e42e7970722 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -139,6 +139,9 @@ class Electron //! list of kinds of electron collision std::vector m_kinds; + //! list of products of electron collision + std::vector m_products; + //! list of mass ratio of electron to target species vector_fp m_massRatios; diff --git a/include/cantera/electron/ElectronCrossSection.h b/include/cantera/electron/ElectronCrossSection.h index d151a269acb..8537a8d79e0 100644 --- a/include/cantera/electron/ElectronCrossSection.h +++ b/include/cantera/electron/ElectronCrossSection.h @@ -21,11 +21,6 @@ class ElectronCrossSection public: ElectronCrossSection(); - // //! Constructor - // ElectronCrossSection(const std::string& kind, const std::string& target, - // const std::vector> data, double mass_ratio=Undef, - // double threshold=0.0); - //! ElectronCrossSection objects are not copyable or assignable ElectronCrossSection(const ElectronCrossSection&) = delete; ElectronCrossSection& operator=(const ElectronCrossSection& other) = delete; @@ -39,6 +34,9 @@ class ElectronCrossSection //! The name of the target of electron collision std::string target; + //! The product of electron collision + std::string product; + //! Data std::vector data; diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index a9a0e6c60a6..26925d63a8c 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -13,9 +13,7 @@ namespace Cantera { Electron::Electron() - : m_targets(0) - , m_kinds(0) - , m_ncs(0) + : m_ncs(0) , m_points(200) , m_kT(Undef) , m_E(Undef) @@ -97,6 +95,7 @@ bool Electron::addElectronCrossSection(shared_ptr ecs) ecs->validate(); m_targets.push_back(ecs->target); m_kinds.push_back(ecs->kind); + m_products.push_back(ecs->product); m_massRatios.push_back(ecs->mass_ratio); m_thresholds.push_back(ecs->threshold); @@ -139,6 +138,7 @@ bool Electron::addElectronCrossSection(shared_ptr ecs) // add elastic cross section m_targets.push_back(ecs->target); m_kinds.push_back("ELASTIC"); + m_products.push_back(ecs->product); m_massRatios.push_back(ecs->mass_ratio); m_thresholds.push_back(ecs->threshold); m_crossSections.push_back(transdata); diff --git a/src/electron/ElectronCrossSection.cpp b/src/electron/ElectronCrossSection.cpp index 5c7487c68c7..2f10a0b9d05 100644 --- a/src/electron/ElectronCrossSection.cpp +++ b/src/electron/ElectronCrossSection.cpp @@ -12,7 +12,8 @@ namespace Cantera { ElectronCrossSection::ElectronCrossSection() - : mass_ratio(Undef) + : product("") + , mass_ratio(Undef) , threshold(0.0) { } @@ -80,11 +81,12 @@ unique_ptr newElectronCrossSection(const AnyMap& node) ecs->mass_ratio = node["mass_ratio"].asDouble(); } else { ecs->threshold = node["threshold"].asDouble(); + ecs->product = node["product"].asString(); } // Store all unparsed keys in the "extra" map const static std::set known_keys{ - "kind", "target", "data", "mass_ratio", "threshold" + "kind", "target", "product", "data", "mass_ratio", "threshold" }; for (const auto& item : node) { From 0e203d5f6f7aa040880648678802b5a72463ba3b Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 12 May 2019 21:38:42 -0400 Subject: [PATCH 021/139] [electron] add getNetProductionRate --- include/cantera/clib/ct.h | 2 + include/cantera/cython/wrappers.h | 4 ++ include/cantera/electron/Electron.h | 42 +++++++++++++++---- include/cantera/electron/WeakIonGasElectron.h | 1 + interfaces/cython/cantera/_cantera.pxd | 5 +++ interfaces/cython/cantera/electron.pyx | 16 +++++++ src/clib/ct.cpp | 3 ++ src/electron/Electron.cpp | 7 ++++ src/electron/WeakIonGasElectron.cpp | 40 ++++++++++++++++++ 9 files changed, 112 insertions(+), 8 deletions(-) diff --git a/include/cantera/clib/ct.h b/include/cantera/clib/ct.h index 7cc572cea65..7799fd3dd59 100644 --- a/include/cantera/clib/ct.h +++ b/include/cantera/clib/ct.h @@ -157,6 +157,8 @@ extern "C" { CANTERA_CAPI int trans_getMassFluxes(int n, const double* state1, const double* state2, double delta, double* fluxes); + CANTERA_CAPI int elect_getNetPlasmaProductionRates(int n, size_t len, double* wdot); + CANTERA_CAPI int ct_getCanteraError(int buflen, char* buf); CANTERA_CAPI int ct_setLogWriter(void* logger); CANTERA_CAPI int ct_addCanteraDirectory(size_t buflen, const char* buf); diff --git a/include/cantera/cython/wrappers.h b/include/cantera/cython/wrappers.h index 65225289a69..a3800ff8d53 100644 --- a/include/cantera/cython/wrappers.h +++ b/include/cantera/cython/wrappers.h @@ -5,6 +5,7 @@ #include "cantera/thermo/ThermoPhase.h" #include "cantera/transport/TransportBase.h" #include "cantera/kinetics/Kinetics.h" +#include "cantera/electron/Electron.h" #include "Python.h" @@ -64,6 +65,7 @@ void CxxArray2D_set(Cantera::Array2D& array, size_t i, size_t j, double value) #define KIN_1D(FUNC_NAME) ARRAY_FUNC(kin, Kinetics, FUNC_NAME) #define TRANSPORT_1D(FUNC_NAME) ARRAY_FUNC(tran, Transport, FUNC_NAME) #define TRANSPORT_2D(FUNC_NAME) ARRAY_FUNC2(tran, Transport, FUNC_NAME) +#define ELECTRON_1D(FUNC_NAME) ARRAY_FUNC(elect, Electron, FUNC_NAME) THERMO_1D(getMassFractions) THERMO_1D(setMassFractions) @@ -117,3 +119,5 @@ TRANSPORT_1D(getMobilities) TRANSPORT_2D(getMultiDiffCoeffs) TRANSPORT_2D(getBinaryDiffCoeffs) + +ELECTRON_1D(getNetPlasmaProductionRates) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index e42e7970722..6b472163ed6 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -55,22 +55,39 @@ class Electron void setupGrid(size_t n, const double* eps); //! electron diffusivity - virtual double electronDiffusivity()=0; + virtual double electronDiffusivity() { + throw NotImplementedError("Electron::electronDiffusivity"); + } //! electron mobility - virtual double electronMobility()=0; + virtual double electronMobility() { + throw NotImplementedError("Electron::electronMobility"); + } //! mean electron energy - virtual double meanElectronEnergy() = 0; + virtual double meanElectronEnergy() { + throw NotImplementedError("Electron::meanElectronEnergy"); + } //! elastic power loss - virtual double elasticPowerLoss() = 0; + virtual double elasticPowerLoss() { + throw NotImplementedError("Electron::elasticPowerLoss"); + } //! rate coefficient. [m^3/s] - virtual double rateCoefficient(size_t k) = 0; + virtual double rateCoefficient(size_t k) { + throw NotImplementedError("Electron::rateCoefficient"); + } //! inverse rate coefficient. [m^3/s] - virtual double inverseRateCoefficient(size_t k) = 0; + virtual double inverseRateCoefficient(size_t k) { + throw NotImplementedError("Electron::inverseRateCoefficient"); + } + + //! net plasma production rates + virtual void getNetPlasmaProductionRates(double* wdot) { + throw NotImplementedError("Electron::getNetPlasmaProductionRates"); + } //! initialize Electron. Need to be called after adding all cross sections. void init(thermo_t* thermo); @@ -127,11 +144,20 @@ class Electron } //! Return electron temperature - virtual double electronTemperature() = 0; + virtual double electronTemperature() { + throw NotImplementedError("Electron::electronTemperature"); + } //! Set chemionization scattering-in rate //! Equal to the reaction rate divided by gas and electron number density - virtual void setChemionScatRate(double rate) = 0; + virtual void setChemionScatRate(double rate) { + throw NotImplementedError("Electron::setChemionScatRate"); + } + + //! Check that an array size is at least nSpecies() + //! Throws an exception if kk is less than nSpecies(). Used before calls + //! which take an array pointer. + void checkSpeciesArraySize(size_t k) const; //! list of targets of electron collision std::vector m_targets; diff --git a/include/cantera/electron/WeakIonGasElectron.h b/include/cantera/electron/WeakIonGasElectron.h index 9c4df9e3e32..3e38c828dc9 100644 --- a/include/cantera/electron/WeakIonGasElectron.h +++ b/include/cantera/electron/WeakIonGasElectron.h @@ -48,6 +48,7 @@ class WeakIonGasElectron: public Electron virtual double elasticPowerLoss(); virtual double inverseRateCoefficient(size_t k); virtual double rateCoefficient(size_t k); + virtual void getNetPlasmaProductionRates(double* wdot); //! The real part of the mobility. This is used in power gain for case of AC. double realMobility(); diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index ff4db54cdcf..8e66764c218 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -985,6 +985,9 @@ cdef extern from "cantera/cython/wrappers.h": cdef void kin_getDestructionRates(CxxKinetics*, double*) except +translate_exception cdef void kin_getNetProductionRates(CxxKinetics*, double*) except +translate_exception + # Electron + cdef void elect_getNetPlasmaProductionRates(CxxElectron*, double*) except +translate_exception + # Transport properties cdef void tran_getMixDiffCoeffs(CxxTransport*, double*) except +translate_exception cdef void tran_getMixDiffCoeffsMass(CxxTransport*, double*) except +translate_exception @@ -1001,6 +1004,7 @@ ctypedef void (*thermoMethod1d)(CxxThermoPhase*, double*) except +translate_exce ctypedef void (*transportMethod1d)(CxxTransport*, double*) except +translate_exception ctypedef void (*transportMethod2d)(CxxTransport*, size_t, double*) except +translate_exception ctypedef void (*kineticsMethod1d)(CxxKinetics*, double*) except +translate_exception +ctypedef void (*electronMethod1d)(CxxElectron*, double*) except +translate_exception # classes cdef class ElectronCrossSection: @@ -1235,6 +1239,7 @@ cdef np.ndarray get_species_array(Kinetics kin, kineticsMethod1d method) cdef np.ndarray get_reaction_array(Kinetics kin, kineticsMethod1d method) cdef np.ndarray get_transport_1d(Transport tran, transportMethod1d method) cdef np.ndarray get_transport_2d(Transport tran, transportMethod2d method) +cdef np.ndarray get_electron_1d(Electron elect, electronMethod1d method) cdef CxxIdealGasPhase* getIdealGasPhase(ThermoPhase phase) except * cdef wrapSpeciesThermo(shared_ptr[CxxSpeciesThermo] spthermo) cdef Reaction wrapReaction(shared_ptr[CxxReaction] reaction) diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/electron.pyx index 7df5c964ef9..cef3192f5c0 100644 --- a/interfaces/cython/cantera/electron.pyx +++ b/interfaces/cython/cantera/electron.pyx @@ -4,6 +4,14 @@ import warnings import weakref +cdef np.ndarray get_electron_1d(Electron elect, electronMethod1d method): + cdef np.ndarray[np.double_t, ndim=1] data = np.empty(elect.thermo.nSpecies()) + method(elect.electron, &data[0]) + if elect._selected_species.size: + return data[elect._selected_species] + else: + return data + cdef class Electron(_SolutionBase): """ This class is used to compute electron properties for a phase of matter. @@ -40,6 +48,14 @@ cdef class Electron(_SolutionBase): """inverse rate coefficient of process k""" return self.electron.inverseRateCoefficient(k) + property net_plasma_production_rates: + """ + Net plasma production rates for each species. [kmol/m^3/s] for bulk phases or + [kmol/m^2/s] for surface phases. + """ + def __get__(self): + return get_electron_1d(self, elect_getNetPlasmaProductionRates) + def set_chemionization_scattering_rate(self, rate): """ Set chemionization scattering-in rate """ self.electron.setChemionScatRate(rate) diff --git a/src/clib/ct.cpp b/src/clib/ct.cpp index a9c40a2cb24..ab97d16c5c5 100644 --- a/src/clib/ct.cpp +++ b/src/clib/ct.cpp @@ -17,6 +17,7 @@ // Cantera includes #include "cantera/kinetics/KineticsFactory.h" #include "cantera/transport/TransportFactory.h" +#include "cantera/electron/ElectronFactory.h" #include "cantera/base/ctml.h" #include "cantera/kinetics/importKinetics.h" #include "cantera/thermo/ThermoFactory.h" @@ -30,11 +31,13 @@ using namespace Cantera; typedef Cabinet ThermoCabinet; typedef Cabinet KineticsCabinet; typedef Cabinet TransportCabinet; +typedef Cabinet ElectronCabinet; typedef Cabinet XmlCabinet; template<> ThermoCabinet* ThermoCabinet::s_storage = 0; template<> KineticsCabinet* KineticsCabinet::s_storage = 0; template<> TransportCabinet* TransportCabinet::s_storage = 0; +template<> ElectronCabinet* ElectronCabinet::s_storage = 0; /** * Exported functions. diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index 26925d63a8c..dcc1f7f8806 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -206,4 +206,11 @@ void Electron::setupGrid(size_t n, const double* eps) m_f0_ok = false; } +void Electron::checkSpeciesArraySize(size_t k) const +{ + if (m_thermo->nSpecies() > k) { + throw ArraySizeError("checkSpeciesArraySize", k, m_thermo->nSpecies()); + } +} + } diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index f9b299c2259..d75ef83159b 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -523,4 +523,44 @@ double WeakIonGasElectron::electronTemperature(Eigen::VectorXd f0) return 2./3. * 0.4 * sum / Boltzmann * ElectronCharge; } +void WeakIonGasElectron::getNetPlasmaProductionRates(double* wdot) +{ + calculateDistributionFunction(); + for (size_t k = 0; k < m_thermo->nSpecies(); k++) { + wdot[k] = 0.0; + } + size_t k_E = m_thermo->speciesIndex("E"); + if (k_E == npos) { + return; + } + double X_E = m_thermo->moleFraction("E"); + for (size_t k : m_kInelastic) { + size_t kr = m_thermo->speciesIndex(m_targets[k]); + if (kr != npos) { + double rate = m_N * m_N * m_moleFractions[k] * X_E * + rateCoefficient(k) / 1e3 / Avogadro; + std::string prdct = m_products[k]; + size_t dp = prdct.find(" + "); + if (dp != npos) { + size_t kp0 = m_thermo->speciesIndex(prdct.substr(0, dp)); + prdct.erase(0, dp + 3); + size_t kp1 = m_thermo->speciesIndex(prdct); + if (kp0 != npos && kp1 != npos) { + wdot[kp0] += rate; + wdot[kp1] += rate; + wdot[kr] -= rate; + wdot[k_E] += (m_inFactor[k] - 1) * rate; + } + } else { + size_t kp0 = m_thermo->speciesIndex(prdct); + if (kp0 != npos) { + wdot[kp0] += rate; + wdot[kr] -= rate; + wdot[k_E] += (m_inFactor[k] - 1) * rate; + } + } + } + } +} + } From ff74d43e0c192ff0d4948b916e8c3b1a9f87ef76 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 13 May 2019 15:38:52 -0400 Subject: [PATCH 022/139] [electron] fix rateCoefficient --- src/electron/WeakIonGasElectron.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index d75ef83159b..1feabdcf299 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -476,7 +476,7 @@ double WeakIonGasElectron::rateCoefficient(size_t k) Eigen::VectorXd s = P * m_f0; double sum = 0.0; for (size_t i = 0; i < m_points; i++) { - sum += s[i]; + sum += s(i); } return sum; } @@ -489,7 +489,7 @@ double WeakIonGasElectron::inverseRateCoefficient(size_t k) Eigen::VectorXd s = Q * m_f0; double sum = 0.0; for (size_t i = 0; i < m_points; i++) { - sum += s[i]; + sum += s(i); } return sum; } From 62e5ad84fba60778675d011277860444d53e849e Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 13 May 2019 15:42:46 -0400 Subject: [PATCH 023/139] [electron] fix elasticPowerLoss --- src/electron/WeakIonGasElectron.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index 1feabdcf299..d115bef722f 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -456,6 +456,7 @@ double WeakIonGasElectron::powerGain() double WeakIonGasElectron::elasticPowerLoss() { + calculateDistributionFunction(); double sum = 0.0; vector_fp y(m_points + 1, 0.0); for (size_t i = 1; i < m_points; i++) { @@ -478,6 +479,7 @@ double WeakIonGasElectron::rateCoefficient(size_t k) for (size_t i = 0; i < m_points; i++) { sum += s(i); } + std::cout< Date: Mon, 13 May 2019 19:08:33 -0400 Subject: [PATCH 024/139] [electron] add electron power loss --- include/cantera/electron/Electron.h | 5 ++++ include/cantera/electron/WeakIonGasElectron.h | 5 ++++ interfaces/cython/cantera/_cantera.pxd | 2 ++ interfaces/cython/cantera/electron.pyx | 14 +++++++++ src/electron/WeakIonGasElectron.cpp | 29 +++++++++++++++++-- 5 files changed, 52 insertions(+), 3 deletions(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index 6b472163ed6..47c334d6122 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -74,6 +74,11 @@ class Electron throw NotImplementedError("Electron::elasticPowerLoss"); } + //! inelastic power loss + virtual double inelasticPowerLoss() { + throw NotImplementedError("Electron::inelasticPowerLoss"); + } + //! rate coefficient. [m^3/s] virtual double rateCoefficient(size_t k) { throw NotImplementedError("Electron::rateCoefficient"); diff --git a/include/cantera/electron/WeakIonGasElectron.h b/include/cantera/electron/WeakIonGasElectron.h index 3e38c828dc9..e0f482b2d75 100644 --- a/include/cantera/electron/WeakIonGasElectron.h +++ b/include/cantera/electron/WeakIonGasElectron.h @@ -46,6 +46,7 @@ class WeakIonGasElectron: public Electron virtual double meanElectronEnergy(); virtual double powerGain(); virtual double elasticPowerLoss(); + virtual double inelasticPowerLoss(); virtual double inverseRateCoefficient(size_t k); virtual double rateCoefficient(size_t k); virtual void getNetPlasmaProductionRates(double* wdot); @@ -116,6 +117,10 @@ class WeakIonGasElectron: public Electron //! electron temperature. For internal use only. double electronTemperature(Eigen::VectorXd f0); + //! bi-Maxwellian Boltzmann factor. Assume that the excitation + //! temperature equals to the gas temperature. + double biMaxwellFraction(size_t k); + //! Total electron cross section on the cell center of energy grid vector_fp m_totalCrossSectionC; diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 8e66764c218..ac6b37e26c1 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -164,6 +164,8 @@ cdef extern from "cantera/electron/Electron.h" namespace "Cantera": double meanElectronEnergy() double rateCoefficient(size_t) double inverseRateCoefficient(size_t) + double elasticPowerLoss() + double inelasticPowerLoss() double electricField() double electricFieldFreq() void setElectricField(double) diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/electron.pyx index cef3192f5c0..dc140750ce4 100644 --- a/interfaces/cython/cantera/electron.pyx +++ b/interfaces/cython/cantera/electron.pyx @@ -48,6 +48,20 @@ cdef class Electron(_SolutionBase): """inverse rate coefficient of process k""" return self.electron.inverseRateCoefficient(k) + property electron_elastic_power_loss: + """ + Electron elastic power loss. [eV/s] + """ + def __get__(self): + return self.electron.elasticPowerLoss() + + property electron_inelastic_power_loss: + """ + Electron inelastic power loss. [eV/s] + """ + def __get__(self): + return self.electron.inelasticPowerLoss() + property net_plasma_production_rates: """ Net plasma production rates for each species. [kmol/m^3/s] for bulk phases or diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index d115bef722f..6bc29c42760 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -243,7 +243,7 @@ SpMat WeakIonGasElectron::matrix_P(vector_fp g, size_t k) double sigma_b = m_sigma[k][n][1]; double j = m_j[k][n]; double r = integralPQ(eps_a, eps_b, sigma_a, sigma_b, g[j], m_gridC[j]); - double p = m_gamma * m_moleFractions[k] * r; + double p = m_gamma * r; tripletList.push_back(T(j, j, p)); } SpMat P(m_points, m_points); @@ -262,7 +262,7 @@ SpMat WeakIonGasElectron::matrix_Q(vector_fp g, size_t k) double i = m_i[k][n]; double j = m_j[k][n]; double r = integralPQ(eps_a, eps_b, sigma_a, sigma_b, g[j], m_gridC[j]); - double q = m_inFactor[k] * m_gamma * m_moleFractions[k] * r; + double q = m_inFactor[k] * m_gamma * r; tripletList.push_back(T(i, j, q)); } SpMat Q(m_points, m_points); @@ -469,6 +469,30 @@ double WeakIonGasElectron::elasticPowerLoss() return sum * m_N; } +double WeakIonGasElectron::biMaxwellFraction(size_t k) +{ + double y0 = 1.0; + double y1 = std::exp(-m_thresholds[k] / m_kT); + y0 *= 1.0 / (y0 + y1); + return y0; +} + +double WeakIonGasElectron::inelasticPowerLoss() +{ + calculateDistributionFunction(); + double sum = 0.0; + for (size_t k : m_kInelastic) { + if (m_kinds[k] == "EXCITATION") { + double y_low = biMaxwellFraction(k); + double y_up = 1.0 - y_low; + sum += m_thresholds[k] * m_moleFractions[k] * + (y_low * rateCoefficient(k) - + y_up * inverseRateCoefficient(k)); + } + } + return sum * m_N; +} + double WeakIonGasElectron::rateCoefficient(size_t k) { calculateDistributionFunction(); @@ -479,7 +503,6 @@ double WeakIonGasElectron::rateCoefficient(size_t k) for (size_t i = 0; i < m_points; i++) { sum += s(i); } - std::cout< Date: Mon, 20 May 2019 12:41:23 -0400 Subject: [PATCH 025/139] [electron] add powerGain --- include/cantera/electron/Electron.h | 4 ++++ interfaces/cython/cantera/_cantera.pxd | 1 + interfaces/cython/cantera/electron.pyx | 7 +++++++ src/electron/WeakIonGasElectron.cpp | 4 ++-- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index 47c334d6122..dac9430a14f 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -69,6 +69,10 @@ class Electron throw NotImplementedError("Electron::meanElectronEnergy"); } + virtual double powerGain() { + throw NotImplementedError("Electron::powerGain"); + } + //! elastic power loss virtual double elasticPowerLoss() { throw NotImplementedError("Electron::elasticPowerLoss"); diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index ac6b37e26c1..127dc6b814c 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -164,6 +164,7 @@ cdef extern from "cantera/electron/Electron.h" namespace "Cantera": double meanElectronEnergy() double rateCoefficient(size_t) double inverseRateCoefficient(size_t) + double powerGain() double elasticPowerLoss() double inelasticPowerLoss() double electricField() diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/electron.pyx index dc140750ce4..2d7a41cb1e3 100644 --- a/interfaces/cython/cantera/electron.pyx +++ b/interfaces/cython/cantera/electron.pyx @@ -48,6 +48,13 @@ cdef class Electron(_SolutionBase): """inverse rate coefficient of process k""" return self.electron.inverseRateCoefficient(k) + property electron_power_gain: + """ + Electron power gain. [eV/s] + """ + def __get__(self): + return self.electron.powerGain() + property electron_elastic_power_loss: """ Electron elastic power loss. [eV/s] diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index 6bc29c42760..28e4fe6ca4c 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -448,9 +448,9 @@ double WeakIonGasElectron::realMobility() double WeakIonGasElectron::powerGain() { if (m_F != 0.0) { - return ElectronCharge * m_E * m_E * electronMobility(); + return m_E * m_E * electronMobility(); } else { - return ElectronCharge * m_E * m_E * realMobility(); + return m_E * m_E * realMobility(); } } From 71de595e2a99af50c2da0e7f7bd334aade44517b Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 20 May 2019 13:06:05 -0400 Subject: [PATCH 026/139] [electron] add totalCollisionFreq --- include/cantera/electron/Electron.h | 5 +++++ include/cantera/electron/WeakIonGasElectron.h | 1 + interfaces/cython/cantera/_cantera.pxd | 1 + interfaces/cython/cantera/electron.pyx | 5 +++++ src/electron/WeakIonGasElectron.cpp | 9 +++++++++ 5 files changed, 21 insertions(+) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index dac9430a14f..75186de68db 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -83,6 +83,11 @@ class Electron throw NotImplementedError("Electron::inelasticPowerLoss"); } + //! total collision frequency + virtual double totalCollisionFreq() { + throw NotImplementedError("Electron::inelasticPowerLoss"); + } + //! rate coefficient. [m^3/s] virtual double rateCoefficient(size_t k) { throw NotImplementedError("Electron::rateCoefficient"); diff --git a/include/cantera/electron/WeakIonGasElectron.h b/include/cantera/electron/WeakIonGasElectron.h index e0f482b2d75..26b8a899bd4 100644 --- a/include/cantera/electron/WeakIonGasElectron.h +++ b/include/cantera/electron/WeakIonGasElectron.h @@ -47,6 +47,7 @@ class WeakIonGasElectron: public Electron virtual double powerGain(); virtual double elasticPowerLoss(); virtual double inelasticPowerLoss(); + virtual double totalCollisionFreq(); virtual double inverseRateCoefficient(size_t k); virtual double rateCoefficient(size_t k); virtual void getNetPlasmaProductionRates(double* wdot); diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 127dc6b814c..2d60deffa3b 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -162,6 +162,7 @@ cdef extern from "cantera/electron/Electron.h" namespace "Cantera": double electronMobility() double electronDiffusivity() double meanElectronEnergy() + double totalCollisionFreq() double rateCoefficient(size_t) double inverseRateCoefficient(size_t) double powerGain() diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/electron.pyx index 2d7a41cb1e3..db91c93b5e0 100644 --- a/interfaces/cython/cantera/electron.pyx +++ b/interfaces/cython/cantera/electron.pyx @@ -40,6 +40,11 @@ cdef class Electron(_SolutionBase): def __get__(self): return self.electron.electronDiffusivity() + property electron_total_collision_frequency: + """electron total collision frequency""" + def __get__(self): + return self.electron.totalCollisionFreq() + def electron_rate_coefficient(self, k): """rate coefficient of process k""" return self.electron.rateCoefficient(k) diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index 28e4fe6ca4c..ae26b201735 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -469,6 +469,15 @@ double WeakIonGasElectron::elasticPowerLoss() return sum * m_N; } +double WeakIonGasElectron::totalCollisionFreq() +{ + double sum = 0.0; + for (size_t k = 0; k < m_ncs; k++) { + sum += m_moleFractions[k] * rateCoefficient(k); + } + return sum * m_N; +} + double WeakIonGasElectron::biMaxwellFraction(size_t k) { double y0 = 1.0; From 6f1dc9c83b7c65e1edcda9aba3aa81b3e648bc7e Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 20 May 2019 16:05:05 -0400 Subject: [PATCH 027/139] [electron] fix getNetPlasmaProductionRates --- src/electron/WeakIonGasElectron.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index ae26b201735..0eceaca87a3 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -572,7 +572,7 @@ void WeakIonGasElectron::getNetPlasmaProductionRates(double* wdot) size_t kr = m_thermo->speciesIndex(m_targets[k]); if (kr != npos) { double rate = m_N * m_N * m_moleFractions[k] * X_E * - rateCoefficient(k) / 1e3 / Avogadro; + rateCoefficient(k) / Avogadro; std::string prdct = m_products[k]; size_t dp = prdct.find(" + "); if (dp != npos) { From 079ad6b28a3471955ec65c2819d231f8d00f6e44 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 21 May 2019 12:29:55 -0400 Subject: [PATCH 028/139] [electron] fix type of inFactor --- include/cantera/electron/Electron.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index 75186de68db..492a37c4d04 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -239,8 +239,8 @@ class Electron vector_fp m_moleFractions; //! shift factor - std::vector m_shiftFactor; - std::vector m_inFactor; + std::vector m_shiftFactor; + std::vector m_inFactor; //! list elastic std::vector m_kElastic; From 8307379e22e927b239d9a75cc8017fb171b16c16 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 24 May 2019 13:05:04 -0400 Subject: [PATCH 029/139] [electron] move setGridCache to class Electron --- include/cantera/electron/Electron.h | 15 ++++ include/cantera/electron/WeakIonGasElectron.h | 15 ---- src/electron/Electron.cpp | 70 +++++++++++++++++++ src/electron/WeakIonGasElectron.cpp | 69 ------------------ 4 files changed, 85 insertions(+), 84 deletions(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index 492a37c4d04..b366279c0d5 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -199,6 +199,9 @@ class Electron */ mutable ValueCache m_cache; + // set grid cache + void setGridCache(); + //! Update temperature void update_T(); @@ -283,6 +286,18 @@ class Electron //! Gas number density double m_N; + + //! Location of cell j for grid cache + std::vector> m_j; + + //! Location of cell i for grid cache + std::vector> m_i; + + //! Cross section at the boundaries of the overlap of cell i and j + std::vector> m_sigma; + + //! The energy boundaries of the overlap of cell i and j + std::vector> m_eps; }; } diff --git a/include/cantera/electron/WeakIonGasElectron.h b/include/cantera/electron/WeakIonGasElectron.h index 26b8a899bd4..ac6a0b0a516 100644 --- a/include/cantera/electron/WeakIonGasElectron.h +++ b/include/cantera/electron/WeakIonGasElectron.h @@ -76,9 +76,6 @@ class WeakIonGasElectron: public Electron //! Calculate total elastic cross section void calculateTotalElasticCrossSection(); - //! Set grid cache - void setGridCache(); - //! The integral in [a, b] of x * u(x) exp[g * (x0 - x)] //! assuming that u is linear with u(a) = u0 and u(b) = u1 double integralPQ(double a, double b, double u0, double u1, @@ -132,18 +129,6 @@ class WeakIonGasElectron: public Electron //! vector of total elastic cross section weighted with mass ratio vector_fp m_sigmaElastic; - //! Location of cell j for grid cache - std::vector> m_j; - - //! Location of cell i for grid cache - std::vector> m_i; - - //! Cross section at the boundaries of the overlap of cell i and j - std::vector> m_sigma; - - //! The energy boundaries of the overlap of cell i and j - std::vector> m_eps; - //! Set chemionization scattering-in rate double m_chemionScatRate; }; diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index dcc1f7f8806..35d291d98be 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -47,6 +47,75 @@ void Electron::init(thermo_t* thermo) m_thermo = thermo; m_f0_ok = false; calculateElasticCrossSection(); + setGridCache(); +} + +void Electron::setGridCache() +{ + m_sigma.clear(); + m_sigma.resize(m_ncs); + m_eps.clear(); + m_eps.resize(m_ncs); + m_j.clear(); + m_j.resize(m_ncs); + m_i.clear(); + m_i.resize(m_ncs); + for (size_t k = 0; k < m_ncs; k++) { + vector_fp x = m_crossSections[k][0]; + vector_fp y = m_crossSections[k][1]; + vector_fp eps1(m_points + 1); + for (size_t i = 0; i < m_points + 1; i++) { + eps1[i] = m_shiftFactor[k] * m_gridB[i] + m_thresholds[k]; + eps1[i] = std::max(eps1[i], m_gridB[0] + 1e-9); + eps1[i] = std::min(eps1[i], m_gridB[m_points] - 1e-9); + } + + vector_fp nodes = eps1; + for (size_t i = 0; i < m_points + 1; i++) { + if (m_gridB[i] >= eps1[0] && m_gridB[i] <= eps1[m_points]) { + nodes.push_back(m_gridB[i]); + } + } + for (size_t i = 0; i < x.size(); i++) { + if (x[i] >= eps1[0] && x[i] <= eps1[m_points]) { + nodes.push_back(x[i]); + } + } + + std::sort(nodes.begin(), nodes.end()); + vector_fp::iterator last = std::unique(nodes.begin(), nodes.end()); + nodes.resize(std::distance(nodes.begin(), last)); + vector_fp sigma0(nodes.size()); + for (size_t i = 0; i < nodes.size(); i++) { + sigma0[i] = linearInterp(nodes[i], x, y); + } + + // search position of cell j + for (size_t i = 1; i < nodes.size(); i++) { + vector_fp::iterator low; + low = std::lower_bound(m_gridB.begin(), m_gridB.end(), nodes[i]); + m_j[k].push_back(low - m_gridB.begin() - 1); + } + + // search position of cell i + for (size_t i = 1; i < nodes.size(); i++) { + vector_fp::iterator low; + low = std::lower_bound(eps1.begin(), eps1.end(), nodes[i]); + m_i[k].push_back(low - eps1.begin() - 1); + } + + // construct sigma + for (size_t i = 0; i < nodes.size() - 1; i++) { + vector_fp sigma{sigma0[i], sigma0[i+1]}; + m_sigma[k].push_back(sigma); + } + + // construct eps + for (size_t i = 0; i < nodes.size() - 1; i++) { + vector_fp eps{nodes[i], nodes[i+1]}; + m_eps[k].push_back(eps); + } + } } void Electron::update_T() @@ -203,6 +272,7 @@ void Electron::setupGrid(size_t n, const double* eps) m_gridB[i] = eps[i]; m_gridC[i] = 0.5 * (eps[i] + eps[i+1]); } + setGridCache(); m_f0_ok = false; } diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index 0eceaca87a3..217e6f43df2 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -46,74 +46,6 @@ void WeakIonGasElectron::calculateTotalCrossSection() } } -void WeakIonGasElectron::setGridCache() -{ - m_sigma.clear(); - m_sigma.resize(m_ncs); - m_eps.clear(); - m_eps.resize(m_ncs); - m_j.clear(); - m_j.resize(m_ncs); - m_i.clear(); - m_i.resize(m_ncs); - for (size_t k = 0; k < m_ncs; k++) { - vector_fp x = m_crossSections[k][0]; - vector_fp y = m_crossSections[k][1]; - vector_fp eps1(m_points + 1); - for (size_t i = 0; i < m_points + 1; i++) { - eps1[i] = m_shiftFactor[k] * m_gridB[i] + m_thresholds[k]; - eps1[i] = std::max(eps1[i], m_gridB[0] + 1e-9); - eps1[i] = std::min(eps1[i], m_gridB[m_points] - 1e-9); - } - - vector_fp nodes = eps1; - for (size_t i = 0; i < m_points + 1; i++) { - if (m_gridB[i] >= eps1[0] && m_gridB[i] <= eps1[m_points]) { - nodes.push_back(m_gridB[i]); - } - } - for (size_t i = 0; i < x.size(); i++) { - if (x[i] >= eps1[0] && x[i] <= eps1[m_points]) { - nodes.push_back(x[i]); - } - } - - std::sort(nodes.begin(), nodes.end()); - vector_fp::iterator last = std::unique(nodes.begin(), nodes.end()); - nodes.resize(std::distance(nodes.begin(), last)); - vector_fp sigma0(nodes.size()); - for (size_t i = 0; i < nodes.size(); i++) { - sigma0[i] = linearInterp(nodes[i], x, y); - } - - // search position of cell j - for (size_t i = 1; i < nodes.size(); i++) { - vector_fp::iterator low; - low = std::lower_bound(m_gridB.begin(), m_gridB.end(), nodes[i]); - m_j[k].push_back(low - m_gridB.begin() - 1); - } - - // search position of cell i - for (size_t i = 1; i < nodes.size(); i++) { - vector_fp::iterator low; - low = std::lower_bound(eps1.begin(), eps1.end(), nodes[i]); - m_i[k].push_back(low - eps1.begin() - 1); - } - - // construct sigma - for (size_t i = 0; i < nodes.size() - 1; i++) { - vector_fp sigma{sigma0[i], sigma0[i+1]}; - m_sigma[k].push_back(sigma); - } - - // construct eps - for (size_t i = 0; i < nodes.size() - 1; i++) { - vector_fp eps{nodes[i], nodes[i+1]}; - m_eps[k].push_back(eps); - } - } -} - void WeakIonGasElectron::calculateTotalElasticCrossSection() { m_sigmaElastic.clear(); @@ -139,7 +71,6 @@ void WeakIonGasElectron::calculateDistributionFunction() calculateTotalCrossSection(); calculateTotalElasticCrossSection(); - setGridCache(); double kT = m_kT; if (m_init_kTe != 0.0) { From 7da899bef01e8b2a6fa1d1c4f627cd82934d9f95 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 24 May 2019 13:50:27 -0400 Subject: [PATCH 030/139] [interface] add ecs product and process --- interfaces/cython/cantera/_cantera.pxd | 1 + interfaces/cython/cantera/electron.pyx | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 2d60deffa3b..ce222d53f65 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -147,6 +147,7 @@ cdef extern from "cantera/electron/ElectronCrossSection.h" namespace "Cantera": string kind string target double mass_ratio + string product vector[vector[double]] data cdef shared_ptr[CxxElectronCrossSection] CxxNewElectronCrossSection "newElectronCrossSection" (CxxAnyMap&) except +translate_exception diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/electron.pyx index db91c93b5e0..43bd4730c88 100644 --- a/interfaces/cython/cantera/electron.pyx +++ b/interfaces/cython/cantera/electron.pyx @@ -187,6 +187,16 @@ cdef class ElectronCrossSection: def __get__(self): return self.electron_cross_section.mass_ratio + property product: + """ The product of the collision. """ + def __get__(self): + return pystr(self.electron_cross_section.product) + + property process: + """ The process of the collision. """ + def __get__(self): + return self.target + " => " + self.product + property data: """ The mass ratio of electron to molecule. """ def __get__(self): From 52795e92b23c0117084cb7530964459cf0311a25 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 24 May 2019 23:19:57 -0400 Subject: [PATCH 031/139] [electron] fix elastic and effective cs --- src/electron/Electron.cpp | 53 ++++++++--------------------- src/electron/WeakIonGasElectron.cpp | 16 +-------- 2 files changed, 16 insertions(+), 53 deletions(-) diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index 35d291d98be..1fa443c9321 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -193,7 +193,7 @@ bool Electron::addElectronCrossSection(shared_ptr ecs) m_inFactor.push_back(1); } - if (ecs->kind == "EFFECTIVE") { + if (ecs->kind == "EFFECTIVE" || ecs->kind == "ELASTIC") { for (size_t k = 0; k < m_ncs; k++) { if (m_targets[k] == ecs->target) if (m_kinds[k] == "ELASTIC" || m_kinds[k] == "EFFECTIVE") { @@ -202,35 +202,8 @@ bool Electron::addElectronCrossSection(shared_ptr ecs) ecs->target); } } - // list effective - m_kEffective.push_back(m_ncs); - // add elastic cross section - m_targets.push_back(ecs->target); - m_kinds.push_back("ELASTIC"); - m_products.push_back(ecs->product); - m_massRatios.push_back(ecs->mass_ratio); - m_thresholds.push_back(ecs->threshold); - m_crossSections.push_back(transdata); - m_shiftFactor.push_back(1); - m_inFactor.push_back(1); - m_ncs++; - // list elastic m_kElastic.push_back(m_ncs); - } else if (ecs->kind == "ELASTIC") { - for (size_t k = 0; k < m_ncs; k++) { - if (m_targets[k] == ecs->target) - if (m_kinds[k] == "ELASTIC" || m_kinds[k] == "EFFECTIVE") { - throw CanteraError("Electron::addElectronCrossSection", - "Already contains a data of EFFECTIVE/ELASTIC cross section for '{}'.", - ecs->target); - } - } - // list elastic - m_kElastic.push_back(m_ncs); - // list solo elastic - m_kSoloElastic.push_back(m_ncs); } else { - // list inelastic m_kInelastic.push_back(m_ncs); } @@ -245,18 +218,22 @@ bool Electron::addElectronCrossSection(shared_ptr ecs) void Electron::calculateElasticCrossSection() { for (size_t ke : m_kElastic) { - for (size_t k : m_kInelastic) { - if (m_targets[k] == m_targets[ke]) { - vector_fp x = m_crossSections[k][0]; - vector_fp y = m_crossSections[k][1]; - for (size_t i = 0; i < m_crossSections[ke][0].size(); i++) { - m_crossSections[ke][1][i] -= linearInterp(m_crossSections[ke][0][i], x, y); + if (m_kinds[ke] == "EFFECTIVE") { + // replace effective with elastic + m_kinds[ke] = "ELASTIC"; + for (size_t k : m_kInelastic) { + if (m_targets[k] == m_targets[ke]) { + vector_fp x = m_crossSections[k][0]; + vector_fp y = m_crossSections[k][1]; + for (size_t i = 0; i < m_crossSections[ke][0].size(); i++) { + m_crossSections[ke][1][i] -= linearInterp(m_crossSections[ke][0][i], x, y); + } } } - } - // replace negative values with zero. - for (size_t i = 0; i < m_crossSections[ke][0].size(); i++) { - m_crossSections[ke][1][i] = std::max(0.0, m_crossSections[ke][1][i]); + // replace negative values with zero. + for (size_t i = 0; i < m_crossSections[ke][0].size(); i++) { + m_crossSections[ke][1][i] = std::max(0.0, m_crossSections[ke][1][i]); + } } } } diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index 217e6f43df2..c71df861b32 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -20,7 +20,7 @@ void WeakIonGasElectron::calculateTotalCrossSection() m_totalCrossSectionC.resize(m_points, 0.0); m_totalCrossSectionB.clear(); m_totalCrossSectionB.resize(m_points + 1, 0.0); - for (size_t k : m_kEffective) { + for (size_t k = 0; k < m_ncs; k++) { vector_fp x = m_crossSections[k][0]; vector_fp y = m_crossSections[k][1]; for (size_t i = 0; i < m_points; i++) { @@ -30,20 +30,6 @@ void WeakIonGasElectron::calculateTotalCrossSection() m_totalCrossSectionB[i] += m_moleFractions[k] * linearInterp(m_gridB[i], x, y); } } - for (size_t ke : m_kSoloElastic) { - for (size_t k = 0; k < m_ncs; k++) { - if (m_targets[k] == m_targets[ke]) { - vector_fp x = m_crossSections[k][0]; - vector_fp y = m_crossSections[k][1]; - for (size_t i = 0; i < m_points; i++) { - m_totalCrossSectionC[i] += m_moleFractions[k] * linearInterp(m_gridC[i], x, y); - } - for (size_t i = 0; i < m_points + 1; i++) { - m_totalCrossSectionB[i] += m_moleFractions[k] * linearInterp(m_gridB[i], x, y); - } - } - } - } } void WeakIonGasElectron::calculateTotalElasticCrossSection() From 5986687958fb254e5cf0e5c1ba25f524c92384b3 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Wed, 3 Apr 2019 16:56:42 +0800 Subject: [PATCH 032/139] [Transport] enable IonGasTransport to use Electron --- include/cantera/transport/IonGasTransport.h | 11 +++++++++++ include/cantera/transport/TransportBase.h | 6 ++++++ interfaces/cython/cantera/_cantera.pxd | 2 ++ interfaces/cython/cantera/base.pyx | 2 ++ interfaces/cython/cantera/transport.pyx | 3 ++- src/transport/IonGasTransport.cpp | 21 ++++++++++++++++++--- 6 files changed, 41 insertions(+), 4 deletions(-) diff --git a/include/cantera/transport/IonGasTransport.h b/include/cantera/transport/IonGasTransport.h index e208002b096..425f4a3b5b7 100644 --- a/include/cantera/transport/IonGasTransport.h +++ b/include/cantera/transport/IonGasTransport.h @@ -57,6 +57,8 @@ class IonGasTransport : public MixTransport virtual void init(thermo_t* thermo, int mode, int log_level); + virtual void initElectron(Electron* electron); + //! Viscosity of the mixture (kg/m/s). //! Only Neutral species contribute to Viscosity. virtual double viscosity(); @@ -80,6 +82,10 @@ class IonGasTransport : public MixTransport */ virtual double electricalConductivity(); + virtual void enableElectron(bool enable) { + m_do_electron = enable; + } + protected: //! setup parameters for n64 model void setupN64(); @@ -114,6 +120,11 @@ class IonGasTransport : public MixTransport //! polynomial of the collision integral for O2/O2- vector_fp m_om11_O2; + + //! electron class + Electron* m_electron; + + bool m_do_electron; }; } diff --git a/include/cantera/transport/TransportBase.h b/include/cantera/transport/TransportBase.h index 1726c2ea195..b0e988fffb6 100644 --- a/include/cantera/transport/TransportBase.h +++ b/include/cantera/transport/TransportBase.h @@ -20,6 +20,7 @@ #define CT_TRANSPORTBASE_H #include "cantera/thermo/ThermoPhase.h" +#include "cantera/electron/Electron.h" namespace Cantera { @@ -659,6 +660,11 @@ class Transport m_root = root; } + //! initialize the Electron object. This method is overloaded in IonGasTtransport. + virtual void initElectron(Electron* electron) {} + + virtual void enableElectron(bool enable) {} + protected: //! Enable the transport object for use. /*! diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index ce222d53f65..5cade24d13f 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -498,6 +498,8 @@ cdef extern from "cantera/transport/TransportBase.h" namespace "Cantera": double thermalConductivity() except +translate_exception double electricalConductivity() except +translate_exception void getSpeciesViscosities(double*) except +translate_exception + void initElectron(CxxElectron*) except +translate_exception + void enableElectron(cbool) except +translate_exception cdef extern from "cantera/transport/DustyGasTransport.h" namespace "Cantera": diff --git a/interfaces/cython/cantera/base.pyx b/interfaces/cython/cantera/base.pyx index 137fcdfa2ce..3d0faf3613c 100644 --- a/interfaces/cython/cantera/base.pyx +++ b/interfaces/cython/cantera/base.pyx @@ -257,6 +257,8 @@ cdef class _SolutionBase: self.electron.init(self.thermo) for ecs in electron_cross_sections: self.electron.addElectronCrossSection(ecs._electron_cross_section) + else: + self.electron = NULL def __getitem__(self, selection): copy = self.__class__(origin=self) diff --git a/interfaces/cython/cantera/transport.pyx b/interfaces/cython/cantera/transport.pyx index b9b0bb24e81..69375207c75 100644 --- a/interfaces/cython/cantera/transport.pyx +++ b/interfaces/cython/cantera/transport.pyx @@ -144,7 +144,8 @@ cdef class Transport(_SolutionBase): model = 'None' self.transport = newTransportMgr(stringify(model), self.thermo) self._transport.reset(self.transport) - + if self.electron != NULL: + self.transport.initElectron(self.electron) super().__init__(*args, **kwargs) self.base.setTransport(self._transport) diff --git a/src/transport/IonGasTransport.cpp b/src/transport/IonGasTransport.cpp index 48dbe5479d6..f32bab8af4b 100644 --- a/src/transport/IonGasTransport.cpp +++ b/src/transport/IonGasTransport.cpp @@ -11,7 +11,9 @@ namespace Cantera { IonGasTransport::IonGasTransport() : - m_kElectron(npos) + m_kElectron(npos), + m_electron(NULL), + m_do_electron(false) { } @@ -84,6 +86,11 @@ void IonGasTransport::init(thermo_t* thermo, int mode, int log_level) } } +void IonGasTransport::initElectron(Electron* electron) +{ + m_electron = electron; +} + double IonGasTransport::viscosity() { update_T(); @@ -352,7 +359,11 @@ void IonGasTransport::getMixDiffCoeffs(double* const d) } else { for (size_t k = 0; k < m_nsp; k++) { if (k == m_kElectron) { - d[k] = 0.4 * m_kbt / ElectronCharge; + if (m_electron && m_do_electron) { + d[m_kElectron] = m_electron->electronDiffusivity(); + } else { + d[k] = 0.4 * m_kbt / ElectronCharge; + } } else { double sum2 = 0.0; for (size_t j : m_kNeutral) { @@ -382,7 +393,11 @@ void IonGasTransport::getMobilities(double* const mobi) double p = m_thermo->pressure(); for (size_t k = 0; k < m_nsp; k++) { if (k == m_kElectron) { - mobi[k] = 0.4; + if (m_electron && m_do_electron) { + mobi[k] = m_electron->electronMobility(); + } else { + mobi[k] = 0.4; + } } else { mobi[k] = 0.0; } From 390eb180aae75edea78628fb62e9720c376d8f2c Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 22 Jun 2019 16:58:45 -0400 Subject: [PATCH 033/139] [Transport] add getMixDiffCoeffsMass/Mole for IonGasTransport --- include/cantera/transport/IonGasTransport.h | 4 ++ src/transport/IonGasTransport.cpp | 79 +++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/include/cantera/transport/IonGasTransport.h b/include/cantera/transport/IonGasTransport.h index 425f4a3b5b7..224ab10e26b 100644 --- a/include/cantera/transport/IonGasTransport.h +++ b/include/cantera/transport/IonGasTransport.h @@ -75,6 +75,10 @@ class IonGasTransport : public MixTransport //! The binary transport between two charged species is neglected. virtual void getMixDiffCoeffs(double* const d); + virtual void getMixDiffCoeffsMass(double* const d); + + virtual void getMixDiffCoeffsMole(double* const d); + /*! The electrical conductivity (Siemens/m). * \f[ * \sigma = \sum_k{\left|C_k\right| \mu_k \frac{X_k P}{k_b T}} diff --git a/src/transport/IonGasTransport.cpp b/src/transport/IonGasTransport.cpp index f32bab8af4b..f27073a8f5a 100644 --- a/src/transport/IonGasTransport.cpp +++ b/src/transport/IonGasTransport.cpp @@ -381,6 +381,85 @@ void IonGasTransport::getMixDiffCoeffs(double* const d) } } +void IonGasTransport::getMixDiffCoeffsMass(double* const d) +{ + update_T(); + update_C(); + + // update the binary diffusion coefficients if necessary + if (!m_bindiff_ok) { + updateDiff_T(); + } + + doublereal mmw = m_thermo->meanMolecularWeight(); + doublereal p = m_thermo->pressure(); + + if (m_nsp == 1) { + d[0] = m_bdiff(0,0) / p; + } else { + for (size_t k=0; kelectronDiffusivity(); + } else { + d[k] = 0.4 * m_kbt / ElectronCharge; + } + } else { + double sum1 = 0.0; + double sum2 = 0.0; + for (size_t i : m_kNeutral) { + if (i==k) { + continue; + } + sum1 += m_molefracs[i] / m_bdiff(k,i); + sum2 += m_molefracs[i] * m_mw[i] / m_bdiff(k,i); + } + sum1 *= p; + sum2 *= p * m_molefracs[k] / (mmw - m_mw[k]*m_molefracs[k]); + d[k] = 1.0 / (sum1 + sum2); + } + } + } +} + +void IonGasTransport::getMixDiffCoeffsMole(double* const d) +{ + update_T(); + update_C(); + + // update the binary diffusion coefficients if necessary + if (!m_bindiff_ok) { + updateDiff_T(); + } + + double p = m_thermo->pressure(); + if (m_nsp == 1) { + d[0] = m_bdiff(0,0) / p; + } else { + for (size_t k = 0; k < m_nsp; k++) { + if (k == m_kElectron) { + if (m_electron && m_do_electron) { + d[m_kElectron] = m_electron->electronDiffusivity(); + } else { + d[k] = 0.4 * m_kbt / ElectronCharge; + } + } else { + double sum2 = 0.0; + for (size_t j : m_kNeutral) { + if (j != k) { + sum2 += m_molefracs[j] / m_bdiff(j,k); + } + } + if (sum2 <= 0.0) { + d[k] = m_bdiff(k,k) / p; + } else { + d[k] = (1 - m_molefracs[k]) / (p * sum2); + } + } + } + } +} + void IonGasTransport::getMobilities(double* const mobi) { update_T(); From 8cfd5b25fa3355dbcca7aee0a53607b30742120f Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 28 Apr 2019 18:26:14 -0400 Subject: [PATCH 034/139] [kinetics] add ElectronReaction --- include/cantera/kinetics/BulkKinetics.h | 1 + include/cantera/kinetics/GasKinetics.h | 5 ++++ include/cantera/kinetics/Kinetics.h | 6 +++++ include/cantera/kinetics/Reaction.h | 8 ++++++ include/cantera/kinetics/reaction_defs.h | 6 +++++ interfaces/cython/cantera/_cantera.pxd | 4 +++ interfaces/cython/cantera/base.pyx | 2 ++ interfaces/cython/cantera/reaction.pyx | 15 +++++++++++ src/kinetics/GasKinetics.cpp | 31 +++++++++++++++++++++++ src/kinetics/Kinetics.cpp | 6 +++++ src/kinetics/Reaction.cpp | 32 ++++++++++++++++++++++++ 11 files changed, 116 insertions(+) diff --git a/include/cantera/kinetics/BulkKinetics.h b/include/cantera/kinetics/BulkKinetics.h index 17d490cc110..574b945e41b 100644 --- a/include/cantera/kinetics/BulkKinetics.h +++ b/include/cantera/kinetics/BulkKinetics.h @@ -60,6 +60,7 @@ class BulkKinetics : public Kinetics bool m_ROP_ok; doublereal m_temp; + double m_temp_e; }; } diff --git a/include/cantera/kinetics/GasKinetics.h b/include/cantera/kinetics/GasKinetics.h index 3e9c413670c..cb04879f30f 100644 --- a/include/cantera/kinetics/GasKinetics.h +++ b/include/cantera/kinetics/GasKinetics.h @@ -81,6 +81,9 @@ class GasKinetics : public BulkKinetics //! Rate expressions for falloff reactions at the high-pressure limit Rate1 m_falloff_high_rates; + //! Rate expressions for electron reactions + Rate1 m_electron_rates; + FalloffMgr m_falloffn; ThirdBodyCalc m_3b_concm; @@ -105,11 +108,13 @@ class GasKinetics : public BulkKinetics void processFalloffReactions(); + void addElectronReaction(ElectronReaction& r); void addThreeBodyReaction(ThreeBodyReaction& r); void addFalloffReaction(FalloffReaction& r); void addPlogReaction(PlogReaction& r); void addChebyshevReaction(ChebyshevReaction& r); + void modifyElectronReaction(size_t i, ElectronReaction& r); void modifyThreeBodyReaction(size_t i, ThreeBodyReaction& r); void modifyFalloffReaction(size_t i, FalloffReaction& r); void modifyPlogReaction(size_t i, PlogReaction& r); diff --git a/include/cantera/kinetics/Kinetics.h b/include/cantera/kinetics/Kinetics.h index 6f59438a2f3..a4576340ebe 100644 --- a/include/cantera/kinetics/Kinetics.h +++ b/include/cantera/kinetics/Kinetics.h @@ -15,6 +15,7 @@ #include "StoichManager.h" #include "cantera/kinetics/Reaction.h" #include "cantera/base/global.h" +#include "cantera/electron/Electron.h" namespace Cantera { @@ -689,6 +690,8 @@ class Kinetics */ virtual void addPhase(thermo_t& thermo); + virtual void addElectron(Electron* electron); + /** * Prepare the class for the addition of reactions, after all phases have * been added. This method is called automatically when the first reaction @@ -893,6 +896,9 @@ class Kinetics */ std::vector m_thermo; + //! electron class + Electron* m_electron; + /** * m_start is a vector of integers specifying the beginning position for the * species vector for the n'th phase in the kinetics class. diff --git a/include/cantera/kinetics/Reaction.h b/include/cantera/kinetics/Reaction.h index ff8280c2a15..d245bdb2a50 100644 --- a/include/cantera/kinetics/Reaction.h +++ b/include/cantera/kinetics/Reaction.h @@ -92,6 +92,14 @@ class ElementaryReaction : public Reaction bool allow_negative_pre_exponential_factor; }; +class ElectronReaction : public ElementaryReaction +{ +public: + ElectronReaction(); + ElectronReaction(const Composition& reactants, const Composition products, + const Arrhenius& rate); +}; + //! A class for managing third-body efficiencies, including default values class ThirdBody { diff --git a/include/cantera/kinetics/reaction_defs.h b/include/cantera/kinetics/reaction_defs.h index 2487b2cbbaf..ac9e4c6df7a 100644 --- a/include/cantera/kinetics/reaction_defs.h +++ b/include/cantera/kinetics/reaction_defs.h @@ -65,6 +65,11 @@ const int CHEBYSHEV_RXN = 6; */ const int CHEMACT_RXN = 8; +/** + * A gas-phase reaction that depends on electron temperature. + */ +const int ELECTRON_RXN = 9; + /** * A reaction occurring on a surface. * NOTE: This is a bit ambiguous, and will be taken out in the future @@ -134,6 +139,7 @@ const int ARRHENIUS_SUM_REACTION_RATECOEFF_TYPE = 5; const int EXCHANGE_CURRENT_REACTION_RATECOEFF_TYPE = 6; const int PLOG_REACTION_RATECOEFF_TYPE = 7; const int CHEBYSHEV_REACTION_RATECOEFF_TYPE = 8; +const int ELECTRON_REACTION_RATECOEEFF_TYPE = 9; //@} diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 5cade24d13f..39e826ea446 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -384,6 +384,9 @@ cdef extern from "cantera/kinetics/Reaction.h" namespace "Cantera": Composition efficiencies double default_efficiency + cdef cppclass CxxElectronReaction "Cantera::ElectronReaction" (CxxElementaryReaction): + CxxElectronReaction() + cdef cppclass CxxThreeBodyReaction "Cantera::ThreeBodyReaction" (CxxElementaryReaction): CxxThreeBodyReaction() CxxThirdBody third_body @@ -465,6 +468,7 @@ cdef extern from "cantera/kinetics/Kinetics.h" namespace "Cantera": CxxThermoPhase& thermo(int) void addPhase(CxxThermoPhase&) except +translate_exception + void addElectron(CxxElectron*) except +translate_exception void init() except +translate_exception void skipUndeclaredThirdBodies(cbool) void addReaction(shared_ptr[CxxReaction]) except +translate_exception diff --git a/interfaces/cython/cantera/base.pyx b/interfaces/cython/cantera/base.pyx index 3d0faf3613c..6124c3b662f 100644 --- a/interfaces/cython/cantera/base.pyx +++ b/interfaces/cython/cantera/base.pyx @@ -243,6 +243,7 @@ cdef class _SolutionBase: if isinstance(self, Electron): self._electron = newElectron(root, self.thermo) self.electron = self._electron.get() + self.kinetics.addElectron(self.electron) else: self.electron = NULL @@ -257,6 +258,7 @@ cdef class _SolutionBase: self.electron.init(self.thermo) for ecs in electron_cross_sections: self.electron.addElectronCrossSection(ecs._electron_cross_section) + self.kinetics.addElectron(self.electron) else: self.electron = NULL diff --git a/interfaces/cython/cantera/reaction.pyx b/interfaces/cython/cantera/reaction.pyx index 0f7bfa6de5b..d2f09cf6ab6 100644 --- a/interfaces/cython/cantera/reaction.pyx +++ b/interfaces/cython/cantera/reaction.pyx @@ -3,6 +3,7 @@ cdef extern from "cantera/kinetics/reaction_defs.h" namespace "Cantera": cdef int ELEMENTARY_RXN + cdef int ELECTRON_RXN cdef int THREE_BODY_RXN cdef int FALLOFF_RXN cdef int PLOG_RXN @@ -404,6 +405,16 @@ cdef class ElementaryReaction(Reaction): r.allow_negative_pre_exponential_factor = allow +cdef class ElectronReaction(ElementaryReaction): + """ + A reaction with electron as reactant + """ + reaction_type = ELECTRON_RXN + + cdef CxxElectronReaction* tbr(self): + return self.reaction + + cdef class ThreeBodyReaction(ElementaryReaction): """ A reaction with a non-reacting third body "M" that acts to add or remove @@ -819,6 +830,8 @@ cdef Reaction wrapReaction(shared_ptr[CxxReaction] reaction): if reaction_type == ELEMENTARY_RXN: R = ElementaryReaction(init=False) + elif reaction_type == ELECTRON_RXN: + R = ElectronReaction(init=False) elif reaction_type == THREE_BODY_RXN: R = ThreeBodyReaction(init=False) elif reaction_type == FALLOFF_RXN: @@ -843,6 +856,8 @@ cdef CxxReaction* newReaction(int reaction_type): """ if reaction_type == ELEMENTARY_RXN: return new CxxElementaryReaction() + elif reaction_type == ELECTRON_RXN: + return new CxxElectronReaction() elif reaction_type == THREE_BODY_RXN: return new CxxThreeBodyReaction() elif reaction_type == FALLOFF_RXN: diff --git a/src/kinetics/GasKinetics.cpp b/src/kinetics/GasKinetics.cpp index 154fc1aafcf..d805a9a344a 100644 --- a/src/kinetics/GasKinetics.cpp +++ b/src/kinetics/GasKinetics.cpp @@ -23,6 +23,11 @@ GasKinetics::GasKinetics(thermo_t* thermo) : void GasKinetics::update_rates_T() { doublereal T = thermo().temperature(); + double Te = T; + if (m_electron) { + Te = m_electron->electronTemperature(); + } + double logTe = log(Te); doublereal P = thermo().pressure(); m_logStandConc = log(thermo().standardConcentration()); doublereal logT = log(T); @@ -43,6 +48,13 @@ void GasKinetics::update_rates_T() m_ROP_ok = false; } + if (T != m_temp || Te != m_temp_e) { + if (m_electron_rates.nReactions()) { + m_electron_rates.update(Te, logTe, m_rfn.data()); + m_ROP_ok = false; + } + } + if (T != m_temp || P != m_pres) { if (m_plog_rates.nReactions()) { m_plog_rates.update(T, logT, m_rfn.data()); @@ -56,6 +68,7 @@ void GasKinetics::update_rates_T() } m_pres = P; m_temp = T; + m_temp_e = Te; } void GasKinetics::update_rates_C() @@ -125,6 +138,7 @@ void GasKinetics::getEquilibriumConstants(doublereal* kc) // force an update of T-dependent properties, so that m_rkcn will // be updated before it is used next. m_temp = 0.0; + m_temp_e = 0.0; } void GasKinetics::processFalloffReactions() @@ -234,6 +248,9 @@ bool GasKinetics::addReaction(shared_ptr r) case ELEMENTARY_RXN: addElementaryReaction(dynamic_cast(*r)); break; + case ELECTRON_RXN: + addElectronReaction(dynamic_cast(*r)); + break; case THREE_BODY_RXN: addThreeBodyReaction(dynamic_cast(*r)); break; @@ -254,6 +271,11 @@ bool GasKinetics::addReaction(shared_ptr r) return true; } +void GasKinetics::addElectronReaction(ElectronReaction& r) +{ + m_electron_rates.install(nReactions()-1, r.rate); +} + void GasKinetics::addFalloffReaction(FalloffReaction& r) { // install high and low rate coeff calculators and extend the high and low @@ -330,6 +352,9 @@ void GasKinetics::modifyReaction(size_t i, shared_ptr rNew) case THREE_BODY_RXN: modifyThreeBodyReaction(i, dynamic_cast(*rNew)); break; + case ELECTRON_RXN: + modifyElectronReaction(i, dynamic_cast(*rNew)); + break; case FALLOFF_RXN: case CHEMACT_RXN: modifyFalloffReaction(i, dynamic_cast(*rNew)); @@ -348,9 +373,15 @@ void GasKinetics::modifyReaction(size_t i, shared_ptr rNew) // invalidate all cached data m_ROP_ok = false; m_temp += 0.1234; + m_temp_e += 0.1234; m_pres += 0.1234; } +void GasKinetics::modifyElectronReaction(size_t i, ElectronReaction& r) +{ + m_rates.replace(i, r.rate); +} + void GasKinetics::modifyThreeBodyReaction(size_t i, ThreeBodyReaction& r) { m_rates.replace(i, r.rate); diff --git a/src/kinetics/Kinetics.cpp b/src/kinetics/Kinetics.cpp index a9f04c7d125..b5e0b0fd4f1 100644 --- a/src/kinetics/Kinetics.cpp +++ b/src/kinetics/Kinetics.cpp @@ -21,6 +21,7 @@ namespace Cantera Kinetics::Kinetics() : m_kk(0), m_thermo(0), + m_electron(0), m_surfphase(npos), m_rxnphase(npos), m_mindim(4), @@ -461,6 +462,11 @@ void Kinetics::addPhase(thermo_t& thermo) resizeSpecies(); } +void Kinetics::addElectron(Electron* electron) +{ + m_electron = electron; +} + void Kinetics::resizeSpecies() { m_kk = 0; diff --git a/src/kinetics/Reaction.cpp b/src/kinetics/Reaction.cpp index b6374ee2199..eb4d3d5ebb9 100644 --- a/src/kinetics/Reaction.cpp +++ b/src/kinetics/Reaction.cpp @@ -128,6 +128,19 @@ void ElementaryReaction::validate() } } +ElectronReaction::ElectronReaction(const Composition& reactants_, + const Composition products_, + const Arrhenius& rate_) + : ElementaryReaction(reactants_, products_, rate_) +{ + reaction_type = ELECTRON_RXN; +} + +ElectronReaction::ElectronReaction() +{ + reaction_type = ELECTRON_RXN; +} + ThirdBody::ThirdBody(double default_eff) : default_efficiency(default_eff) { @@ -578,6 +591,17 @@ void setupElementaryReaction(ElementaryReaction& R, const AnyMap& node, R.rate = readArrhenius(R, node["rate-constant"], kin, node.units()); } +void setupElectronReaction(ElectronReaction& R, const XML_Node& rxn_node) +{ + setupElementaryReaction(R, rxn_node); +} + +void setupElectronReaction(ElectronReaction& R, const AnyMap& node, + const Kinetics& kin) +{ + setupElementaryReaction(R, node, kin); +} + void setupThreeBodyReaction(ThreeBodyReaction& R, const XML_Node& rxn_node) { readEfficiencies(R.third_body, rxn_node.child("rateCoeff")); @@ -1023,6 +1047,10 @@ shared_ptr newReaction(const XML_Node& rxn_node) auto R = make_shared(); setupElementaryReaction(*R, rxn_node); return R; + } else if (type == "electron") { + auto R = make_shared(); + setupElectronReaction(*R, rxn_node); + return R; } else if (type == "threebody" || type == "three_body") { auto R = make_shared(); setupThreeBodyReaction(*R, rxn_node); @@ -1087,6 +1115,10 @@ unique_ptr newReaction(const AnyMap& node, const Kinetics& kin) unique_ptr R(new ElementaryReaction()); setupElementaryReaction(*R, node, kin); return unique_ptr(move(R)); + } else if (type == "electron") { + unique_ptr R(new ElectronReaction()); + setupElectronReaction(*R, node, kin); + return unique_ptr(move(R)); } else if (type == "three-body") { unique_ptr R(new ThreeBodyReaction()); setupThreeBodyReaction(*R, node, kin); From 459b7686c1d45d1e26ba72663860254adf9d4cae Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Wed, 17 Jul 2019 20:14:40 -0400 Subject: [PATCH 035/139] [kinetics] enable electron --- include/cantera/kinetics/GasKinetics.h | 8 ++++++++ include/cantera/kinetics/Kinetics.h | 3 +++ src/kinetics/GasKinetics.cpp | 5 +++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/cantera/kinetics/GasKinetics.h b/include/cantera/kinetics/GasKinetics.h index cb04879f30f..0711611f324 100644 --- a/include/cantera/kinetics/GasKinetics.h +++ b/include/cantera/kinetics/GasKinetics.h @@ -67,6 +67,11 @@ class GasKinetics : public BulkKinetics //! reactions. virtual void update_rates_C(); + //! enable kinetics to use class Electron + virtual void enableElectron(bool enable) { + m_do_electron = enable; + } + protected: //! Reaction index of each falloff reaction std::vector m_fallindx; @@ -106,6 +111,9 @@ class GasKinetics : public BulkKinetics vector_fp concm_falloff_values; //!@} + //! flag of enabling electrons + bool m_do_electron; + void processFalloffReactions(); void addElectronReaction(ElectronReaction& r); diff --git a/include/cantera/kinetics/Kinetics.h b/include/cantera/kinetics/Kinetics.h index a4576340ebe..7da135a1a14 100644 --- a/include/cantera/kinetics/Kinetics.h +++ b/include/cantera/kinetics/Kinetics.h @@ -822,6 +822,9 @@ class Kinetics m_root = root; } + //! enable kinetics to use class Electron + virtual void enableElectron(bool enable) {} + protected: //! Cache for saved calculations within each Kinetics object. ValueCache m_cache; diff --git a/src/kinetics/GasKinetics.cpp b/src/kinetics/GasKinetics.cpp index d805a9a344a..7ea83e2300c 100644 --- a/src/kinetics/GasKinetics.cpp +++ b/src/kinetics/GasKinetics.cpp @@ -16,7 +16,8 @@ GasKinetics::GasKinetics(thermo_t* thermo) : m_logp_ref(0.0), m_logc_ref(0.0), m_logStandConc(0.0), - m_pres(0.0) + m_pres(0.0), + m_do_electron(false) { } @@ -24,7 +25,7 @@ void GasKinetics::update_rates_T() { doublereal T = thermo().temperature(); double Te = T; - if (m_electron) { + if (m_electron && m_do_electron) { Te = m_electron->electronTemperature(); } double logTe = log(Te); From bd06127c02b68034d9575251d33308a27f3f343f Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 2 May 2019 17:18:31 -0400 Subject: [PATCH 036/139] [kinetics] add setElectronTempearture --- include/cantera/kinetics/GasKinetics.h | 7 +++++++ include/cantera/kinetics/Kinetics.h | 3 +++ include/cantera/oneD/StFlow.h | 2 +- src/kinetics/GasKinetics.cpp | 6 +++++- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/include/cantera/kinetics/GasKinetics.h b/include/cantera/kinetics/GasKinetics.h index 0711611f324..f0f3525a860 100644 --- a/include/cantera/kinetics/GasKinetics.h +++ b/include/cantera/kinetics/GasKinetics.h @@ -72,6 +72,10 @@ class GasKinetics : public BulkKinetics m_do_electron = enable; } + virtual void setElectronTemperature(double Te) { + m_Te_fix = Te; + } + protected: //! Reaction index of each falloff reaction std::vector m_fallindx; @@ -114,6 +118,9 @@ class GasKinetics : public BulkKinetics //! flag of enabling electrons bool m_do_electron; + //! fixed value of electron temperature + double m_Te_fix; + void processFalloffReactions(); void addElectronReaction(ElectronReaction& r); diff --git a/include/cantera/kinetics/Kinetics.h b/include/cantera/kinetics/Kinetics.h index 7da135a1a14..cff34099185 100644 --- a/include/cantera/kinetics/Kinetics.h +++ b/include/cantera/kinetics/Kinetics.h @@ -825,6 +825,9 @@ class Kinetics //! enable kinetics to use class Electron virtual void enableElectron(bool enable) {} + //! set electron temperature + virtual void setElectronTemperature(double Te) {} + protected: //! Cache for saved calculations within each Kinetics object. ValueCache m_cache; diff --git a/include/cantera/oneD/StFlow.h b/include/cantera/oneD/StFlow.h index bfae2394f36..1a3f66d50f9 100644 --- a/include/cantera/oneD/StFlow.h +++ b/include/cantera/oneD/StFlow.h @@ -291,7 +291,7 @@ class StFlow : public Domain1D } //! Write the net production rates at point `j` into array `m_wdot` - void getWdot(doublereal* x, size_t j) { + virtual void getWdot(doublereal* x, size_t j) { setGas(x,j); m_kin->getNetProductionRates(&m_wdot(0,j)); } diff --git a/src/kinetics/GasKinetics.cpp b/src/kinetics/GasKinetics.cpp index 7ea83e2300c..015fc9000db 100644 --- a/src/kinetics/GasKinetics.cpp +++ b/src/kinetics/GasKinetics.cpp @@ -17,7 +17,8 @@ GasKinetics::GasKinetics(thermo_t* thermo) : m_logc_ref(0.0), m_logStandConc(0.0), m_pres(0.0), - m_do_electron(false) + m_do_electron(false), + m_Te_fix(Undef) { } @@ -25,6 +26,9 @@ void GasKinetics::update_rates_T() { doublereal T = thermo().temperature(); double Te = T; + if (m_Te_fix != Undef) { + Te = m_Te_fix; + } if (m_electron && m_do_electron) { Te = m_electron->electronTemperature(); } From bfe1abfe14e765a6efb94a1448beb7f26c7cfc7f Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 16 Jul 2019 23:30:33 -0400 Subject: [PATCH 037/139] [kinetics] update electron reaction expression --- include/cantera/kinetics/GasKinetics.h | 2 +- include/cantera/kinetics/RateCoeffMgr.h | 8 +++ include/cantera/kinetics/Reaction.h | 5 +- include/cantera/kinetics/RxnRates.h | 68 +++++++++++++++++++++ include/cantera/kinetics/reaction_defs.h | 2 +- interfaces/cython/cantera/ctml_writer.py | 78 ++++++++++++++++++++++++ src/electron/Electron.cpp | 2 +- src/electron/WeakIonGasElectron.cpp | 2 +- src/kinetics/GasKinetics.cpp | 4 +- src/kinetics/Reaction.cpp | 34 ++++++----- src/kinetics/RxnRates.cpp | 22 +++++++ 11 files changed, 204 insertions(+), 23 deletions(-) diff --git a/include/cantera/kinetics/GasKinetics.h b/include/cantera/kinetics/GasKinetics.h index f0f3525a860..d6a500445c2 100644 --- a/include/cantera/kinetics/GasKinetics.h +++ b/include/cantera/kinetics/GasKinetics.h @@ -91,7 +91,7 @@ class GasKinetics : public BulkKinetics Rate1 m_falloff_high_rates; //! Rate expressions for electron reactions - Rate1 m_electron_rates; + Rate1 m_electron_rates; FalloffMgr m_falloffn; diff --git a/include/cantera/kinetics/RateCoeffMgr.h b/include/cantera/kinetics/RateCoeffMgr.h index 4f89f464a74..83847ca6106 100644 --- a/include/cantera/kinetics/RateCoeffMgr.h +++ b/include/cantera/kinetics/RateCoeffMgr.h @@ -69,6 +69,14 @@ class Rate1 } } + void update(double T, double Te, double logTe, double* values) { + double recipT = 1.0/T; + double recipTe = 1.0/Te; + for (size_t i = 0; i != m_rates.size(); i++) { + values[m_rxn[i]] = m_rates[i].updateRC(logTe, recipT, recipTe); + } + } + size_t nReactions() const { return m_rates.size(); } diff --git a/include/cantera/kinetics/Reaction.h b/include/cantera/kinetics/Reaction.h index d245bdb2a50..5dd614ddb3b 100644 --- a/include/cantera/kinetics/Reaction.h +++ b/include/cantera/kinetics/Reaction.h @@ -92,12 +92,13 @@ class ElementaryReaction : public Reaction bool allow_negative_pre_exponential_factor; }; -class ElectronReaction : public ElementaryReaction +class ElectronReaction : public Reaction { public: ElectronReaction(); ElectronReaction(const Composition& reactants, const Composition products, - const Arrhenius& rate); + const ElectronArrhenius& rate); + ElectronArrhenius rate; }; //! A class for managing third-body efficiencies, including default values diff --git a/include/cantera/kinetics/RxnRates.h b/include/cantera/kinetics/RxnRates.h index a4ada5fbd11..bb9706678b5 100644 --- a/include/cantera/kinetics/RxnRates.h +++ b/include/cantera/kinetics/RxnRates.h @@ -98,6 +98,74 @@ class Arrhenius doublereal m_logA, m_b, m_E, m_A; }; +class ElectronArrhenius +{ +public: + //! return the rate coefficient type. + static int type() { + return ELECTRON_ARRHENIUS_REACTION_RATECOEEFF_TYPE; + } + + //! Default constructor. + ElectronArrhenius(); + + /// Constructor. + /// @param A pre-exponential. The unit system is + /// (kmol, m, s). The actual units depend on the reaction + /// order and the dimensionality (surface or bulk). + /// @param b Temperature exponent. Non-dimensional. + /// @param E Activation energy in temperature units. Kelvin. + ElectronArrhenius(double A, double b, double E1, double E2); + + //! Update concentration-dependent parts of the rate coefficient. + /*! + * For this class, there are no concentration-dependent parts, so this + * method does nothing. + */ + void update_C(const double* c) { + } + + /** + * Update the value of the natural logarithm of the rate constant. + */ + double updateLog(double logTe, double recipT, double recipTe) const { + return m_logA + m_b*logTe - m_E1*recipT - m_E1*recipTe; + } + + /** + * Update the value the rate constant. + * + * This function returns the actual value of the rate constant. It can be + * safely called for negative values of the pre-exponential factor. + */ + double updateRC(double logTe, double recipT, double recipTe) const { + return m_A * std::exp(m_b*logTe - m_E1*recipT - m_E2*recipTe); + } + + //! Return the pre-exponential factor *A* (in m, kmol, s to powers depending + //! on the reaction order) + double preExponentialFactor() const { + return m_A; + } + + //! Return the temperature exponent *b* + double temperatureExponent() const { + return m_b; + } + + //! Return the activation energy divided by the gas constant (i.e. the + //! activation temperature) [K] + double activationEnergy_R() const { + return m_E1; + } + + double activationElectronEnergy_R() const { + return m_E2; + } + +protected: + double m_logA, m_b, m_E1, m_E2, m_A; +}; /** * An Arrhenius rate with coverage-dependent terms. diff --git a/include/cantera/kinetics/reaction_defs.h b/include/cantera/kinetics/reaction_defs.h index ac9e4c6df7a..0cd7aa1ea1a 100644 --- a/include/cantera/kinetics/reaction_defs.h +++ b/include/cantera/kinetics/reaction_defs.h @@ -139,7 +139,7 @@ const int ARRHENIUS_SUM_REACTION_RATECOEFF_TYPE = 5; const int EXCHANGE_CURRENT_REACTION_RATECOEFF_TYPE = 6; const int PLOG_REACTION_RATECOEFF_TYPE = 7; const int CHEBYSHEV_REACTION_RATECOEFF_TYPE = 8; -const int ELECTRON_REACTION_RATECOEEFF_TYPE = 9; +const int ELECTRON_ARRHENIUS_REACTION_RATECOEEFF_TYPE = 9; //@} diff --git a/interfaces/cython/cantera/ctml_writer.py b/interfaces/cython/cantera/ctml_writer.py index 52cc8c6abf4..73742f1db1b 100644 --- a/interfaces/cython/cantera/ctml_writer.py +++ b/interfaces/cython/cantera/ctml_writer.py @@ -1088,6 +1088,79 @@ def build(self, p, name='', a=None): c.addChild('m', repr(cov[2])) addFloat(c, 'e', cov[3], fmt = '%f', defunits = _ue) +class ElectronArrhenius(rate_expression): + def __init__(self, + A = 0.0, + b = 0.0, + E1 = 0.0, + E2 = 0.0, + coverage = []): + """ + :param A: + The pre-exponential coefficient. Required input. If entered without + units, the units will be computed considering all factors that + affect the units. The resulting units string is written to the CTML + file individually for each reaction pre-exponential coefficient. + :param b: + The temperature exponent. Dimensionless. Default: 0.0. + :param E: + Activation energy. Default: 0.0. + :param coverage: For a single coverage dependency, a list with four + elements: the species name followed by the three coverage + parameters. For multiple coverage dependencies, a list of lists + containing the individual sets of coverage parameters. Only used for + surface and edge reactions. + """ + + self._c = [A, b, E1, E2] + + if coverage: + if isinstance(coverage[0], basestring): + self._cov = [coverage] + else: + self._cov = coverage + for cov in self._cov: + if len(cov) != 4: + raise CTI_Error("Incorrect number of coverage parameters") + else: + self._cov = None + + + def build(self, p, name='', a=None): + if a is None: + a = p.addChild('ElectronArrhenius') + if name: + a['name'] = name + + # if a pure number is entered for A, multiply by the conversion + # factor to SI and write it to CTML as a pure number. Otherwise, + # pass it as-is through to CTML with the unit string. + if isnum(self._c[0]): + addFloat(a,'A',self._c[0]*self.unit_factor, fmt = '%14.6E') + elif len(self._c[0]) == 2 and self._c[0][1] == '/site': + addFloat(a,'A',self._c[0][0]/self.rxn_phase._sitedens, + fmt = '%14.6E') + else: + addFloat(a,'A',self._c[0], fmt = '%14.6E') + + # The b coefficient should be dimensionless, so there is no + # need to use 'addFloat' + a.addChild('b', repr(self._c[1])) + + # If a pure number is entered for the activation energy, + # add the default units, otherwise use the supplied units. + addFloat(a,'E1', self._c[2], fmt = '%f', defunits = _ue) + addFloat(a,'E2', self._c[3], fmt = '%f', defunits = _ue) + + # for surface reactions, a coverage dependence may be specified. + if self._cov: + for cov in self._cov: + c = a.addChild('coverage') + c['species'] = cov[0] + addFloat(c, 'a', cov[1], fmt = '%f') + c.addChild('m', repr(cov[2])) + addFloat(c, 'e', cov[3], fmt = '%f', defunits = _ue) + class stick(Arrhenius): """ A rate expression for a surface reaction given as a sticking probability, @@ -1328,6 +1401,11 @@ def build(self, p): for kf in self._kf: if isinstance(kf, rate_expression): k = kf + elif self._type == 'electron': + if len(kf) == 4: + k = ElectronArrhenius(A = kf[0], b = kf[1], E1 = kf[2], E2 = kf[3]) + else: + k = ElectronArrhenius(A = kf[0], b = kf[1], E1 = kf[2]) else: k = Arrhenius(A = kf[0], b = kf[1], E = kf[2]) if isinstance(kf, stick): diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index 1fa443c9321..afdb4891e5e 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -16,7 +16,7 @@ Electron::Electron() : m_ncs(0) , m_points(200) , m_kT(Undef) - , m_E(Undef) + , m_E(0.0) , m_F(0.0) , m_f0_ok(false) , m_maxn(100) diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index c71df861b32..3d3d80dd393 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -68,7 +68,7 @@ void WeakIonGasElectron::calculateDistributionFunction() std::exp(-m_gridC[j]/kT); } - if (m_E != Undef) { + if (m_E != 0.0) { m_f0 = converge(m_f0); double Te = electronTemperature(m_f0); if (Te < m_thermo->temperature()) { diff --git a/src/kinetics/GasKinetics.cpp b/src/kinetics/GasKinetics.cpp index 015fc9000db..dc608ac1c1d 100644 --- a/src/kinetics/GasKinetics.cpp +++ b/src/kinetics/GasKinetics.cpp @@ -55,7 +55,7 @@ void GasKinetics::update_rates_T() if (T != m_temp || Te != m_temp_e) { if (m_electron_rates.nReactions()) { - m_electron_rates.update(Te, logTe, m_rfn.data()); + m_electron_rates.update(T, Te, logTe, m_rfn.data()); m_ROP_ok = false; } } @@ -384,7 +384,7 @@ void GasKinetics::modifyReaction(size_t i, shared_ptr rNew) void GasKinetics::modifyElectronReaction(size_t i, ElectronReaction& r) { - m_rates.replace(i, r.rate); + m_electron_rates.replace(i, r.rate); } void GasKinetics::modifyThreeBodyReaction(size_t i, ThreeBodyReaction& r) diff --git a/src/kinetics/Reaction.cpp b/src/kinetics/Reaction.cpp index eb4d3d5ebb9..e1e925d3a56 100644 --- a/src/kinetics/Reaction.cpp +++ b/src/kinetics/Reaction.cpp @@ -130,15 +130,15 @@ void ElementaryReaction::validate() ElectronReaction::ElectronReaction(const Composition& reactants_, const Composition products_, - const Arrhenius& rate_) - : ElementaryReaction(reactants_, products_, rate_) + const ElectronArrhenius& rate_) + : Reaction(ELECTRON_RXN, reactants_, products_) + , rate(rate_) { - reaction_type = ELECTRON_RXN; } ElectronReaction::ElectronReaction() + : Reaction(ELECTRON_RXN) { - reaction_type = ELECTRON_RXN; } ThirdBody::ThirdBody(double default_eff) @@ -297,6 +297,14 @@ ElectrochemicalReaction::ElectrochemicalReaction(const Composition& reactants_, { } +ElectronArrhenius readElectronArrhenius(const XML_Node& arrhenius_node) +{ + return ElectronArrhenius(getFloat(arrhenius_node, "A", "toSI"), + getFloat(arrhenius_node, "b"), + getFloat(arrhenius_node, "E1", "actEnergy") / GasConstant, + getFloat(arrhenius_node, "E2", "actEnergy") / GasConstant); +} + Arrhenius readArrhenius(const XML_Node& arrhenius_node) { return Arrhenius(getFloat(arrhenius_node, "A", "toSI"), @@ -593,13 +601,13 @@ void setupElementaryReaction(ElementaryReaction& R, const AnyMap& node, void setupElectronReaction(ElectronReaction& R, const XML_Node& rxn_node) { - setupElementaryReaction(R, rxn_node); -} - -void setupElectronReaction(ElectronReaction& R, const AnyMap& node, - const Kinetics& kin) -{ - setupElementaryReaction(R, node, kin); + XML_Node& rc_node = rxn_node.child("rateCoeff"); + if (rc_node.hasChild("ElectronArrhenius")) { + R.rate = readElectronArrhenius(rc_node.child("ElectronArrhenius")); + } else { + throw CanteraError("setupElementaryReaction", "Couldn't find Arrhenius node"); + } + setupReaction(R, rxn_node); } void setupThreeBodyReaction(ThreeBodyReaction& R, const XML_Node& rxn_node) @@ -1115,10 +1123,6 @@ unique_ptr newReaction(const AnyMap& node, const Kinetics& kin) unique_ptr R(new ElementaryReaction()); setupElementaryReaction(*R, node, kin); return unique_ptr(move(R)); - } else if (type == "electron") { - unique_ptr R(new ElectronReaction()); - setupElectronReaction(*R, node, kin); - return unique_ptr(move(R)); } else if (type == "three-body") { unique_ptr R(new ThreeBodyReaction()); setupThreeBodyReaction(*R, node, kin); diff --git a/src/kinetics/RxnRates.cpp b/src/kinetics/RxnRates.cpp index a127985c262..ec06cac898b 100644 --- a/src/kinetics/RxnRates.cpp +++ b/src/kinetics/RxnRates.cpp @@ -28,6 +28,28 @@ Arrhenius::Arrhenius(doublereal A, doublereal b, doublereal E) } } +ElectronArrhenius::ElectronArrhenius() + : m_logA(-1.0E300) + , m_b(0.0) + , m_E1(0.0) + , m_E2(0.0) + , m_A(0.0) +{ +} + +ElectronArrhenius::ElectronArrhenius(double A, double b, double E1, double E2) + : m_b(b) + , m_E1(E1) + , m_E2(E2) + , m_A(A) +{ + if (m_A <= 0.0) { + m_logA = -1.0E300; + } else { + m_logA = std::log(m_A); + } +} + SurfaceArrhenius::SurfaceArrhenius() : m_b(0.0) , m_E(0.0) From 84af117ebb5c91c749c2601fcbb28f205a49f97b Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 1 Aug 2019 22:40:31 -0400 Subject: [PATCH 038/139] [interface] add set_electron_temperature --- interfaces/cython/cantera/_cantera.pxd | 1 + interfaces/cython/cantera/kinetics.pyx | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 39e826ea446..3eaee1d8fe8 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -486,6 +486,7 @@ cdef extern from "cantera/kinetics/Kinetics.h" namespace "Cantera": double multiplier(int) void setMultiplier(int, double) + void setElectronTemperature(double) cdef extern from "cantera/kinetics/InterfaceKinetics.h": diff --git a/interfaces/cython/cantera/kinetics.pyx b/interfaces/cython/cantera/kinetics.pyx index d8a3f53e07a..0359492caa8 100644 --- a/interfaces/cython/cantera/kinetics.pyx +++ b/interfaces/cython/cantera/kinetics.pyx @@ -253,6 +253,10 @@ cdef class Kinetics(_SolutionBase): data[k,i] = self.kinetics.productStoichCoeff(k,i) return data + def set_electron_temperature(self, Te): + self.kinetics.setElectronTemperature(Te) + + property forward_rates_of_progress: """ Forward rates of progress for the reactions. [kmol/m^3/s] for bulk From e2234127715f5fa8e2eac7654275cdda24abfa58 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 8 Aug 2019 23:55:34 -0400 Subject: [PATCH 039/139] [interface-test] add test_electron --- .../cython/cantera/test/test_electron.py | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 interfaces/cython/cantera/test/test_electron.py diff --git a/interfaces/cython/cantera/test/test_electron.py b/interfaces/cython/cantera/test/test_electron.py new file mode 100644 index 00000000000..4aa2812346f --- /dev/null +++ b/interfaces/cython/cantera/test/test_electron.py @@ -0,0 +1,65 @@ +import numpy as np + +import cantera as ct +from . import utilities +import copy + + +class TestElectron(utilities.CanteraTest): + def setUp(self): + self.gas = ct.Solution(infile='ch4_plasma.cti', efile='lxcat.yaml') + + def test_electron_properties(self): + self.gas.TPX = 1000, ct.one_atm, 'O2:1.0, E:1e-10' + self.gas.electric_field = 1e5 + self.gas.electric_field_freq = 0.0 + self.assertNear(self.gas.electron_temperature, 15273, 1e-3) + self.assertNear(self.gas.electron_mobility, 0.3981, 1e-4) + self.assertNear(self.gas.electron_diffusivity, 0.5652, 1e-4) + rate = self.gas.electron_rate_coefficient(19) + self.assertNear(self.gas.net_plasma_production_rates[24] * 1e-10, rate, 1e-4) + self.assertNear(self.gas.net_plasma_production_rates[24], 0.001877, 1e-3) + self.assertNear(self.gas.electron_total_collision_frequency, 3.6957e11, 1e-3) + self.assertNear(self.gas.electron_power_gain, 3.9811e9, 1e-3) + self.assertNear(self.gas.electron_elastic_power_loss, 2.8671e7, 1e-3) + self.assertNear(self.gas.mean_electron_energy, 1.9742, 1e-3) + self.assertNear(self.gas.electric_field, 1e5, 1e-3) + + def test_change_electric_field_freq(self): + self.gas.TPX = 1000, ct.one_atm, 'O2:1.0' + self.gas.electric_field = 1e5 + self.gas.electric_field_freq = 0.0 + Te0 = self.gas.electron_temperature + self.gas.electric_field_freq = 1e9 + Te = self.gas.electron_temperature + self.gas.electric_field_freq = 2e9 + self.assertLess(Te, Te0) + self.assertLess(self.gas.electron_temperature, Te) + self.assertNear(Te, Te0, 1e-3) + self.assertNear(self.gas.electron_temperature, Te, 1e-3) + + def test_change_gas_temperature(self): + self.gas.TPX = 1000, ct.one_atm, 'O2:1.0' + self.gas.electric_field = 1e5 + self.gas.electric_field_freq = 0.0 + Te0 = self.gas.electron_temperature + self.gas.TP = 1100, ct.one_atm * 1.1 + # The gas temperature is important only when E/N is small + self.assertNotEqual(self.gas.electron_temperature, Te0) + self.assertNear(self.gas.electron_temperature, Te0, 1e-4) + self.gas.electric_field = 1.0 + Te = self.gas.electron_temperature + self.gas.TP = 1000, ct.one_atm + self.assertLess(0.05, abs(self.gas.electron_temperature - Te) / Te) + self.gas.electric_field = 1e5 + + def test_change_electric_field_strength(self): + self.gas.TPX = 1000, ct.one_atm, 'O2:1.0' + self.gas.electric_field = 1e5 + self.gas.electric_field_freq = 0.0 + grid = np.linspace(0.0, 2.0, num=1000) + self.gas.set_electron_energy_grid(grid) + self.gas.electric_field = 1.0 + # The electron temperature approach gas temperature when E is small + self.assertNear(self.gas.electron_temperature, self.gas.T, 1e-3) + From 3f9970992ac7dd742b69a4498ff85c9cef9cebb4 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 9 Aug 2019 16:26:11 -0400 Subject: [PATCH 040/139] [data] add ch4_plasma and gri_plasma --- data/inputs/gri30_plasma.cti | 262 +++++++++++++++++++++++++ interfaces/cython/cantera/cti2yaml.py | 28 +++ test/data/ch4_plasma.cti | 268 ++++++++++++++++++++++++++ 3 files changed, 558 insertions(+) create mode 100644 data/inputs/gri30_plasma.cti create mode 100644 test/data/ch4_plasma.cti diff --git a/data/inputs/gri30_plasma.cti b/data/inputs/gri30_plasma.cti new file mode 100644 index 00000000000..b66105e48ae --- /dev/null +++ b/data/inputs/gri30_plasma.cti @@ -0,0 +1,262 @@ +units(length='cm', time='s', quantity='mol', act_energy='cal/mol') + +ideal_gas(name='gas', + elements=' O H C N Ar E', + species=['H2 O2 H2O CH4 CO CO2 N2', + '''gri30: H O OH HO2 H2O2 C CH + CH2 CH2(S) CH3 HCO CH2O CH2OH CH3O + CH3OH C2H C2H2 C2H3 C2H4 C2H5 C2H6 HCCO CH2CO HCCOH + N NH NH2 NH3 NNH NO NO2 N2O HNO CN + HCN H2CN HCNN HCNO HOCN HNCO NCO AR C3H7 + C3H8 CH2CHO CH3CHO''', + 'HCO+ H3O+ E O2(0.98)'], + reactions=['gri30: all', 'all'], + transport='Ion', + options=['skip_undeclared_species', 'skip_undeclared_third_bodies'], + initial_state=state(temperature=300.0, pressure=OneAtm)) + +#------------------------------------------------------------------------------- +# Species data +#------------------------------------------------------------------------------- +# The values of polarizability of H2, O2, H2O, CH4, CO, CO2, and N2 are from +# the supplementary material of Han, Jie, et al. "Numerical modelling of ion +# transport in flames." Combustion Theory and Modelling 19.6 (2015): 744-772. +# DOI: 10.1080/13647830.2015.1090018 + +species(name = "H2", + atoms = " H:2 ", + thermo = ( + NASA( [ 200.00, 1000.00], [ 2.344331120E+00, 7.980520750E-03, + -1.947815100E-05, 2.015720940E-08, -7.376117610E-12, + -9.179351730E+02, 6.830102380E-01] ), + NASA( [ 1000.00, 3500.00], [ 3.337279200E+00, -4.940247310E-05, + 4.994567780E-07, -1.795663940E-10, 2.002553760E-14, + -9.501589220E+02, -3.205023310E+00] ) + ), + transport = gas_transport( + geom = "linear", + diam = 2.92, + well_depth = 38.00, + polar = 0.455, + rot_relax = 280.00), + note = '''The value of polarizability is from the supplementary + material of Han, Jie, et al. "Numerical modelling of ion + transport in flames." Combustion Theory and Modelling + 19.6 (2015): 744-772. DOI: 10.1080/13647830.2015.1090018''' + ) + +species(name = "O2", + atoms = " O:2 ", + thermo = ( + NASA( [ 200.00, 1000.00], [ 3.782456360E+00, -2.996734160E-03, + 9.847302010E-06, -9.681295090E-09, 3.243728370E-12, + -1.063943560E+03, 3.657675730E+00] ), + NASA( [ 1000.00, 3500.00], [ 3.282537840E+00, 1.483087540E-03, + -7.579666690E-07, 2.094705550E-10, -2.167177940E-14, + -1.088457720E+03, 5.453231290E+00] ) + ), + transport = gas_transport( + geom = "linear", + diam = 3.458, + well_depth = 107.40, + polar = 1.131, + rot_relax = 3.80), + note = "TPIS89" + ) + +species(name = "H2O", + atoms = " H:2 O:1 ", + thermo = ( + NASA( [ 200.00, 1000.00], [ 4.198640560E+00, -2.036434100E-03, + 6.520402110E-06, -5.487970620E-09, 1.771978170E-12, + -3.029372670E+04, -8.490322080E-01] ), + NASA( [ 1000.00, 3500.00], [ 3.033992490E+00, 2.176918040E-03, + -1.640725180E-07, -9.704198700E-11, 1.682009920E-14, + -3.000429710E+04, 4.966770100E+00] ) + ), + transport = gas_transport( + geom = "nonlinear", + diam = 2.605, + well_depth = 572.40, + dipole = 1.844, + polar = 1.053, + rot_relax = 4.00), + note = "L 8/89" + ) + +species(name = "CH4", + atoms = " C:1 H:4 ", + thermo = ( + NASA( [ 200.00, 1000.00], [ 5.149876130E+00, -1.367097880E-02, + 4.918005990E-05, -4.847430260E-08, 1.666939560E-11, + -1.024664760E+04, -4.641303760E+00] ), + NASA( [ 1000.00, 3500.00], [ 7.485149500E-02, 1.339094670E-02, + -5.732858090E-06, 1.222925350E-09, -1.018152300E-13, + -9.468344590E+03, 1.843731800E+01] ) + ), + transport = gas_transport( + geom = "nonlinear", + diam = 3.746, + well_depth = 141.40, + polar = 2.60, + rot_relax = 13.00), + note = "L 8/88" + ) + +species(name = "CO", + atoms = " C:1 O:1 ", + thermo = ( + NASA( [ 200.00, 1000.00], [ 3.579533470E+00, -6.103536800E-04, + 1.016814330E-06, 9.070058840E-10, -9.044244990E-13, + -1.434408600E+04, 3.508409280E+00] ), + NASA( [ 1000.00, 3500.00], [ 2.715185610E+00, 2.062527430E-03, + -9.988257710E-07, 2.300530080E-10, -2.036477160E-14, + -1.415187240E+04, 7.818687720E+00] ) + ), + transport = gas_transport( + geom = "linear", + diam = 3.65, + well_depth = 98.10, + polar = 1.95, + rot_relax = 1.80), + note = "TPIS79" + ) + +species(name = "CO2", + atoms = " C:1 O:2 ", + thermo = ( + NASA( [ 200.00, 1000.00], [ 2.356773520E+00, 8.984596770E-03, + -7.123562690E-06, 2.459190220E-09, -1.436995480E-13, + -4.837196970E+04, 9.901052220E+00] ), + NASA( [ 1000.00, 3500.00], [ 3.857460290E+00, 4.414370260E-03, + -2.214814040E-06, 5.234901880E-10, -4.720841640E-14, + -4.875916600E+04, 2.271638060E+00] ) + ), + transport = gas_transport( + geom = "linear", + diam = 3.763, + well_depth = 244.00, + polar = 2.65, + rot_relax = 2.10), + note = "L 7/88" + ) + +species(name = "N2", + atoms = " N:2 ", + thermo = ( + NASA( [ 300.00, 1000.00], [ 3.298677000E+00, 1.408240400E-03, + -3.963222000E-06, 5.641515000E-09, -2.444854000E-12, + -1.020899900E+03, 3.950372000E+00] ), + NASA( [ 1000.00, 5000.00], [ 2.926640000E+00, 1.487976800E-03, + -5.684760000E-07, 1.009703800E-10, -6.753351000E-15, + -9.227977000E+02, 5.980528000E+00] ) + ), + transport = gas_transport( + geom = "linear", + diam = 3.621, + well_depth = 97.53, + polar = 1.76, + rot_relax = 4.00), + note = "121286" + ) + +species(name = 'HCO+', + atoms = ' H:1 C:1 O:1 E:-1 ', + thermo = ( + NASA( [ 300.00, 1000.00], [ 2.473973600E+00, 8.671559000E-03, + -1.003150000E-05, 6.717052700E-09, -1.787267400E-12, + 9.914660800E+04, 8.175711870E+00] ), + NASA( [ 1000.00, 5000.00], [ 3.741188000E+00, 3.344151700E-03, + -1.239712100E-06, 2.118938800E-10, -1.370415000E-14, + 9.888407800E+04, 2.078613570E+00] ) + ), + transport=gas_transport(geom='linear', + diam=3.59, + well_depth=498.0, + polar=1.356), + note = '''The polarizability is from Han, Jie, et al. + "Numerical modelling of ion transport in flames." + ,and the rest of the parameters are from its neutral + counterpart HCO''') + +species(name = 'H3O+', + atoms = ' H:3 O:1 E:-1 ', + thermo = ( + NASA( [ 298.15, 1000.00], [ 3.792952700E+00, -9.108540000E-04, + 1.163635490E-05, -1.213648870E-08, 4.261596630E-12, + 7.075124010E+04, 1.471568560E+00] ), + NASA( [ 1000.00, 6000.00], [ 2.496477160E+00, 5.728449200E-03, + -1.839532810E-06, 2.735774390E-10, -1.540939850E-14, + 7.097291130E+04, 7.458507790E+00] ) + ), + transport=gas_transport(geom='nonlinear', + diam=3.15, + well_depth=106.2, + dipole=1.417, + polar=0.897), + note = '''The transport parameters are from Han, Jie, et al. + "Numerical modelling of ion transport in flames."''') + +species(name = 'E', + atoms = ' E:1 ', + thermo = ( + NASA( [ 200.00, 1000.00], [ 2.500000000E+00, 0.000000000E+00, + 0.000000000E+00, 0.000000000E+00, 0.000000000E+00, + -7.453750000E+02, -1.172469020E+01] ), + NASA( [ 1000.00, 6000.00], [ 2.500000000E+00, 0.000000000E+00, + 0.000000000E+00, 0.000000000E+00, 0.000000000E+00, + -7.453750000E+02, -1.172469020E+01] ) + ), + transport=gas_transport(geom='atom', + diam=2.05, + well_depth=145.0, + polar=0.667), + note = 'The transport parameters are not used in IonGasTransport') + +species(name = "O2(0.98)", + atoms = " O:2 ", + thermo = ( + NASA( [ 200.00, 1000.00], [ 3.782456360E+00, -2.996734160E-03, + 9.847302010E-06, -9.681295090E-09, 3.243728370E-12, + -1.063943560E+03, 3.657675730E+00] ), + NASA( [ 1000.00, 3500.00], [ 3.282537840E+00, 1.483087540E-03, + -7.579666690E-07, 2.094705550E-10, -2.167177940E-14, + -1.088457720E+03, 5.453231290E+00] ) + ), + transport = gas_transport( + geom = "linear", + diam = 3.46, + well_depth = 107.40, + polar = 1.131, + rot_relax = 3.80), + note = "Assume same transport and thermo as O2" + ) +#------------------------------------------------------------------------------- +# Reaction data +#------------------------------------------------------------------------------- + +reaction('CH + O => HCO+ + E', [2.51E+11, 0.0, 1700]) + +reaction('HCO+ + H2O => H3O+ + CO', [1.51E+15, 0.0, 0.0]) + +# DeFilippo, Anthony C., and Jyh-Yuan Chen. "Modeling plasma-assisted methane–air ignition using pre-calculated electron impact reaction rates." Combustion and Flame 172 (2016): 38-48. + +electron_reaction('H3O+ + E => H2O + H', [6.060000e+19, -1.1, 0.0]) + +electron_reaction('H3O+ + E => OH + H + H', [2.250000e+20, -1.1, 0.0]) + +electron_reaction('H3O+ + E => OH + H2', [3.700000e+19, -1.1, 0.0]) + +electron_reaction('H3O+ + E => O + H2 + H', [1.350000e+19, -1.1, 0.0]) + +three_body_reaction('O2(0.98) + M => O2 + M', [1.000000e+06, 0.0, 0.0], + efficiencies='CO:2.0 H:0.0 H2O:1.24 HO2:11100.0 N2:0.000667 O:160.0 O2:0.37 O3:890.0') + +reaction('O2(0.98) => O2', [2.600000e-04, 0.0, 0.0]) + +reaction('CH3 + O2(0.98) => CH3O + O', [2.110000e+13, 0.0, 14374]) + +reaction('CH3 + O2(0.98) => CH2O + OH', [6.620000e+11, 0.0, 10876]) + +reaction('CH4 + O2(0.98) <=> CH3 + HO2', [7.060000e+07, 1.97, 33523]) + diff --git a/interfaces/cython/cantera/cti2yaml.py b/interfaces/cython/cantera/cti2yaml.py index 20252a98545..7c493bac915 100644 --- a/interfaces/cython/cantera/cti2yaml.py +++ b/interfaces/cython/cantera/cti2yaml.py @@ -687,6 +687,34 @@ def get_yaml(self, out): out['nonreactant-orders'] = True +class electron_reaction(reaction): + """ + A electron reaction. + """ + def __init__(self, equation, kf, id='', order='', options=()): + r""" + :param equation: + A string specifying the chemical equation. + :param kf: + The rate coefficient for the forward direction. If a sequence of + three numbers is given, these will be interpreted as [A, b, E1, E2] in + the modified Arrhenius function :math:`A T^b exp(-E1/\hat{R}T) exp(-E2/\hat{R}Te)`. + :param id: + An optional identification string. + :param order: + Override the default reaction orders implied by the reactant + stoichiometric coefficients. Given as a string of key:value pairs, + e.g., ``"CH4:0.25 O2:1.5"``. + :param options: + Processing options, as described in + `Options `__. + May be one or more (as a list) of the following: ``'duplicate'``, + ``'negative_A'``,`` 'negative_orders'``, ``'nonreactant_orders'``. + """ + super().__init__(equation, kf, id, '', options) + self.type = 'electron' + + class three_body_reaction(reaction): """ A three-body reaction. diff --git a/test/data/ch4_plasma.cti b/test/data/ch4_plasma.cti new file mode 100644 index 00000000000..146dbfe4099 --- /dev/null +++ b/test/data/ch4_plasma.cti @@ -0,0 +1,268 @@ +units(length='cm', time='s', quantity='mol', act_energy='cal/mol') + +ideal_gas(name='gas', + elements='O H C N E', + species=['''gri30: H O OH HO2 H2O2 C CH + CH2 CH2(S) CH3 HCO CH2O CH3O''', + '''H2 O2 H2O CH4 CO CO2 N2 + HCO+ H3O+ E O2- O2(0.98)'''], + reactions=['gri30: all', 'all'], + transport='Ion', + options=['skip_undeclared_species', 'skip_undeclared_third_bodies'], + initial_state=state(temperature=300.0, pressure=OneAtm)) + +#------------------------------------------------------------------------------- +# Species data +#------------------------------------------------------------------------------- +species(name = "H2", + atoms = " H:2 ", + thermo = ( + NASA( [ 200.00, 1000.00], [ 2.344331120E+00, 7.980520750E-03, + -1.947815100E-05, 2.015720940E-08, -7.376117610E-12, + -9.179351730E+02, 6.830102380E-01] ), + NASA( [ 1000.00, 3500.00], [ 3.337279200E+00, -4.940247310E-05, + 4.994567780E-07, -1.795663940E-10, 2.002553760E-14, + -9.501589220E+02, -3.205023310E+00] ) + ), + transport = gas_transport( + geom = "linear", + diam = 2.92, + well_depth = 38.00, + polar = 0.455, + rot_relax = 280.00), + note = "TPIS78" + ) + +species(name = "O2", + atoms = " O:2 ", + thermo = ( + NASA( [ 200.00, 1000.00], [ 3.782456360E+00, -2.996734160E-03, + 9.847302010E-06, -9.681295090E-09, 3.243728370E-12, + -1.063943560E+03, 3.657675730E+00] ), + NASA( [ 1000.00, 3500.00], [ 3.282537840E+00, 1.483087540E-03, + -7.579666690E-07, 2.094705550E-10, -2.167177940E-14, + -1.088457720E+03, 5.453231290E+00] ) + ), + transport = gas_transport( + geom = "linear", + diam = 3.46, + well_depth = 107.40, + polar = 1.131, + rot_relax = 3.80), + note = "TPIS89" + ) + +species(name = "H2O", + atoms = " H:2 O:1 ", + thermo = ( + NASA( [ 200.00, 1000.00], [ 4.198640560E+00, -2.036434100E-03, + 6.520402110E-06, -5.487970620E-09, 1.771978170E-12, + -3.029372670E+04, -8.490322080E-01] ), + NASA( [ 1000.00, 3500.00], [ 3.033992490E+00, 2.176918040E-03, + -1.640725180E-07, -9.704198700E-11, 1.682009920E-14, + -3.000429710E+04, 4.966770100E+00] ) + ), + transport = gas_transport( + geom = "nonlinear", + diam = 2.60, + well_depth = 572.40, + dipole = 1.84, + polar = 1.053, + rot_relax = 4.00), + note = "L 8/89" + ) + +species(name = "CH4", + atoms = " C:1 H:4 ", + thermo = ( + NASA( [ 200.00, 1000.00], [ 5.149876130E+00, -1.367097880E-02, + 4.918005990E-05, -4.847430260E-08, 1.666939560E-11, + -1.024664760E+04, -4.641303760E+00] ), + NASA( [ 1000.00, 3500.00], [ 7.485149500E-02, 1.339094670E-02, + -5.732858090E-06, 1.222925350E-09, -1.018152300E-13, + -9.468344590E+03, 1.843731800E+01] ) + ), + transport = gas_transport( + geom = "nonlinear", + diam = 3.75, + well_depth = 141.40, + polar = 2.60, + rot_relax = 13.00), + note = "L 8/88" + ) + +species(name = "CO", + atoms = " C:1 O:1 ", + thermo = ( + NASA( [ 200.00, 1000.00], [ 3.579533470E+00, -6.103536800E-04, + 1.016814330E-06, 9.070058840E-10, -9.044244990E-13, + -1.434408600E+04, 3.508409280E+00] ), + NASA( [ 1000.00, 3500.00], [ 2.715185610E+00, 2.062527430E-03, + -9.988257710E-07, 2.300530080E-10, -2.036477160E-14, + -1.415187240E+04, 7.818687720E+00] ) + ), + transport = gas_transport( + geom = "linear", + diam = 3.65, + well_depth = 98.10, + polar = 1.95, + rot_relax = 1.80), + note = "TPIS79" + ) + +species(name = "CO2", + atoms = " C:1 O:2 ", + thermo = ( + NASA( [ 200.00, 1000.00], [ 2.356773520E+00, 8.984596770E-03, + -7.123562690E-06, 2.459190220E-09, -1.436995480E-13, + -4.837196970E+04, 9.901052220E+00] ), + NASA( [ 1000.00, 3500.00], [ 3.857460290E+00, 4.414370260E-03, + -2.214814040E-06, 5.234901880E-10, -4.720841640E-14, + -4.875916600E+04, 2.271638060E+00] ) + ), + transport = gas_transport( + geom = "linear", + diam = 3.76, + well_depth = 244.00, + polar = 2.65, + rot_relax = 2.10), + note = "L 7/88" + ) + +species(name = "N2", + atoms = " N:2 ", + thermo = ( + NASA( [ 300.00, 1000.00], [ 3.298677000E+00, 1.408240400E-03, + -3.963222000E-06, 5.641515000E-09, -2.444854000E-12, + -1.020899900E+03, 3.950372000E+00] ), + NASA( [ 1000.00, 5000.00], [ 2.926640000E+00, 1.487976800E-03, + -5.684760000E-07, 1.009703800E-10, -6.753351000E-15, + -9.227977000E+02, 5.980528000E+00] ) + ), + transport = gas_transport( + geom = "linear", + diam = 3.62, + well_depth = 97.53, + polar = 1.76, + rot_relax = 4.00, + disp_coeff = 2.995, + quad_polar = 3.602), + note = "121286" + ) + +species(name = 'HCO+', + atoms = ' H:1 C:1 O:1 E:-1 ', + thermo = ( + NASA( [ 300.00, 1000.00], [ 2.473973600E+00, 8.671559000E-03, + -1.003150000E-05, 6.717052700E-09, -1.787267400E-12, + 9.914660800E+04, 8.175711870E+00] ), + NASA( [ 1000.00, 5000.00], [ 3.741188000E+00, 3.344151700E-03, + -1.239712100E-06, 2.118938800E-10, -1.370415000E-14, + 9.888407800E+04, 2.078613570E+00] ) + ), + transport=gas_transport(geom='linear', + diam=3.59, + well_depth=498.0, + polar=1.356, + rot_relax=0.0, + disp_coeff = 0.416), + note = 'J12/70') + +species(name = 'H3O+', + atoms = ' H:3 O:1 E:-1 ', + thermo = ( + NASA( [ 298.15, 1000.00], [ 3.792952700E+00, -9.108540000E-04, + 1.163635490E-05, -1.213648870E-08, 4.261596630E-12, + 7.075124010E+04, 1.471568560E+00] ), + NASA( [ 1000.00, 6000.00], [ 2.496477160E+00, 5.728449200E-03, + -1.839532810E-06, 2.735774390E-10, -1.540939850E-14, + 7.097291130E+04, 7.458507790E+00] ) + ), + transport=gas_transport(geom='nonlinear', + diam=3.15, + well_depth=106.2, + dipole=1.417, + polar=0.897, + rot_relax=0.0), + note = 'TPIS89') + +species(name='O2-', + atoms='E:1 O:2', + thermo=(NASA([298.15, 1000.00], + [ 3.66442522E+00, -9.28741138E-04, 6.45477082E-06, + -7.74703380E-09, 2.93332662E-12, -6.87076983E+03, + 4.35140681E+00]), + NASA([1000.00, 6000.00], + [ 3.95666294E+00, 5.98141823E-04, -2.12133905E-07, + 3.63267581E-11, -2.24989228E-15, -7.06287229E+03, + 2.27871017E+00])), + transport=gas_transport(geom='linear', + diam=3.33, + well_depth=136.5, + polar=1.424), + note='L4/89') + +species(name = 'E', + atoms = ' E:1 ', + thermo = ( + NASA( [ 200.00, 1000.00], [ 2.500000000E+00, 0.000000000E+00, + 0.000000000E+00, 0.000000000E+00, 0.000000000E+00, + -7.453750000E+02, -1.172469020E+01] ), + NASA( [ 1000.00, 6000.00], [ 2.500000000E+00, 0.000000000E+00, + 0.000000000E+00, 0.000000000E+00, 0.000000000E+00, + -7.453750000E+02, -1.172469020E+01] ) + ), + transport=gas_transport(geom='atom', + diam=2.05, + well_depth=145.0, + polar=0.667, + rot_relax=0.0), + note = 'gas L10/92') + +species(name = "O2(0.98)", + atoms = " O:2 ", + thermo = ( + NASA( [ 200.00, 1000.00], [ 3.782456360E+00, -2.996734160E-03, + 9.847302010E-06, -9.681295090E-09, 3.243728370E-12, + -1.063943560E+03, 3.657675730E+00] ), + NASA( [ 1000.00, 3500.00], [ 3.282537840E+00, 1.483087540E-03, + -7.579666690E-07, 2.094705550E-10, -2.167177940E-14, + -1.088457720E+03, 5.453231290E+00] ) + ), + transport = gas_transport( + geom = "linear", + diam = 3.46, + well_depth = 107.40, + polar = 1.131, + rot_relax = 3.80), + note = "TPIS89" + ) +#------------------------------------------------------------------------------- +# Reaction data +#------------------------------------------------------------------------------- + +reaction('CH + O => HCO+ + E', [2.51E+11, 0.0, 1700]) + +reaction('HCO+ + H2O => H3O+ + CO', [1.51E+15, 0.0, 0.0]) + +# DeFilippo, Anthony C., and Jyh-Yuan Chen. "Modeling plasma-assisted methane–air ignition using pre-calculated electron impact reaction rates." Combustion and Flame 172 (2016): 38-48. + +electron_reaction('H3O+ + E => H2O + H', [6.060000e+19, -1.1, 0.0]) + +electron_reaction('H3O+ + E => OH + H + H', [2.250000e+20, -1.1, 0.0]) + +electron_reaction('H3O+ + E => OH + H2', [3.700000e+19, -1.1, 0.0]) + +electron_reaction('H3O+ + E => O + H2 + H', [1.350000e+19, -1.1, 0.0]) + +three_body_reaction('O2(0.98) + M => O2 + M', [1.000000e+06, 0.0, 0.0], + efficiencies='CO:2.0 H:0.0 H2O:1.24 HO2:11100.0 N2:0.000667 O:160.0 O2:0.37 O3:890.0') + +reaction('O2(0.98) => O2', [2.600000e-04, 0.0, 0.0]) + +reaction('CH3 + O2(0.98) => CH3O + O', [2.110000e+13, 0.0, 14374]) + +reaction('CH3 + O2(0.98) => CH2O + OH', [6.620000e+11, 0.0, 10876]) + +reaction('CH4 + O2(0.98) <=> CH3 + HO2', [7.060000e+07, 1.97, 33523]) + From 0c97235e34395250f329a10f4254c5d9a7dc96fa Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 9 Aug 2019 17:10:13 -0400 Subject: [PATCH 041/139] [kinetics] fix ElectronArrhenius --- include/cantera/kinetics/RxnRates.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/cantera/kinetics/RxnRates.h b/include/cantera/kinetics/RxnRates.h index bb9706678b5..edc43311c91 100644 --- a/include/cantera/kinetics/RxnRates.h +++ b/include/cantera/kinetics/RxnRates.h @@ -129,7 +129,7 @@ class ElectronArrhenius * Update the value of the natural logarithm of the rate constant. */ double updateLog(double logTe, double recipT, double recipTe) const { - return m_logA + m_b*logTe - m_E1*recipT - m_E1*recipTe; + return m_logA + m_b*logTe - m_E1*recipT - m_E2*recipTe; } /** From 5f1bf9e8e27f34066a0bb722ff810da90e7dfd23 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 9 Aug 2019 17:16:50 -0400 Subject: [PATCH 042/139] [interface] update ctml_writer doc for electron_reaction --- interfaces/cython/cantera/ctml_writer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interfaces/cython/cantera/ctml_writer.py b/interfaces/cython/cantera/ctml_writer.py index 73742f1db1b..90b2add3864 100644 --- a/interfaces/cython/cantera/ctml_writer.py +++ b/interfaces/cython/cantera/ctml_writer.py @@ -1445,15 +1445,15 @@ def __init__(self, id = '', order = '', options = []): - """ + r""" :param equation: A string specifying the chemical equation. The reaction can be written in either the association or dissociation directions, and may be reversible or irreversible. :param kf: The rate coefficient for the forward direction. If a sequence of - three numbers is given, these will be interpreted as [A, b, E] in - the modified Arrhenius function. + three numbers is given, these will be interpreted as [A, b, E1, E2] in + the modified Arrhenius function :math:`A T^b exp(-E1/\hat{R}T) exp(-E2/\hat{R}Te)`. :param id: An optional identification string. If omitted, it defaults to a four-digit numeric string beginning with 0001 for the first From 4d480efee679a5a514c7b54370a2d68c80519046 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 10 Aug 2019 19:18:52 -0400 Subject: [PATCH 043/139] [electron] fix validate --- src/electron/ElectronCrossSection.cpp | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/electron/ElectronCrossSection.cpp b/src/electron/ElectronCrossSection.cpp index 2f10a0b9d05..e10e832381d 100644 --- a/src/electron/ElectronCrossSection.cpp +++ b/src/electron/ElectronCrossSection.cpp @@ -46,25 +46,7 @@ void ElectronCrossSection::validate() "Invalid mass ratio of type '{}' for '{}'. " "Mass ratio of electron to target must be in the range of 0 to 1.", kind, target); } - } else if (kind == "IONIZATION") { - if (data[0][1] != 0.0) { - throw CanteraError("ElectronCrossSection::validate", - "Invalid cross section value of type '{}' for '{}'. " - "Cross section must starts at zero.", kind, target); - } - } else if (kind == "ATTACHMENT") { - if (data[0][1] != 0.0) { - throw CanteraError("ElectronCrossSection::validate", - "Invalid cross section value of type '{}' for '{}'. " - "Cross section must starts at zero.", kind, target); - } - } else if (kind == "EXCITATION") { - if (data[0][1] != 0.0) { - throw CanteraError("ElectronCrossSection::validate", - "Invalid cross section value of type '{}' for '{}'. " - "Cross section must starts at zero.", kind, target); - } - } else { + } else if (kind != "IONIZATION" && kind != "ATTACHMENT" && kind != "EXCITATION"){ throw CanteraError("ElectronCrossSection::validate", "'{}' is an unknown type of cross section data.", kind); } From 4aba8fc06ed57bb16aa86b9c0edcb5b84d91fd5f Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 11 Aug 2019 08:01:52 -0400 Subject: [PATCH 044/139] [interface] fix _init_electron move init after addElectronCrossSection --- interfaces/cython/cantera/base.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interfaces/cython/cantera/base.pyx b/interfaces/cython/cantera/base.pyx index 6124c3b662f..1cd680878a5 100644 --- a/interfaces/cython/cantera/base.pyx +++ b/interfaces/cython/cantera/base.pyx @@ -255,9 +255,9 @@ cdef class _SolutionBase: if isinstance(self, Electron): self.electron = newElectron(stringify(electron)) self._electron.reset(self.electron) - self.electron.init(self.thermo) for ecs in electron_cross_sections: self.electron.addElectronCrossSection(ecs._electron_cross_section) + self.electron.init(self.thermo) self.kinetics.addElectron(self.electron) else: self.electron = NULL From dd59749c2214c582eea19e9db668dd442ca8cac5 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 11 Aug 2019 12:44:54 -0400 Subject: [PATCH 045/139] [example] add electron_properties --- .../examples/electron/electron_properties.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 interfaces/cython/cantera/examples/electron/electron_properties.py diff --git a/interfaces/cython/cantera/examples/electron/electron_properties.py b/interfaces/cython/cantera/examples/electron/electron_properties.py new file mode 100644 index 00000000000..537c7f48b77 --- /dev/null +++ b/interfaces/cython/cantera/examples/electron/electron_properties.py @@ -0,0 +1,47 @@ +import cantera as ct +import numpy as np +import scipy.constants as co + +# Simulation parameters +p = ct.one_atm # pressure [Pa] +T = 2000.0 # temperature [K] +reactants = 'N2:3.76, O2:1' # air composition + +air = ct.Solution(infile='gri30_ion.cti', efile='lxcat.yaml') +air.TPX = T, p, reactants +air.electric_field = 1e5 + +# set up proper grid for the electric field +grid = np.linspace(0.0, 30, num=500) +air.set_electron_energy_grid(grid) + +print('electron diffusivity = {0:7f} [m^2/s]'.format(air.electron_diffusivity)) +print('electron mobility = {0:7f} [m^2/V/s]'.format(air.electron_mobility)) +print('electron total collision frequency = {0:7f} [Hz]'.format(air.electron_total_collision_frequency)) +print('electron power gain = {0:7f} [eV/s]'.format(air.electron_power_gain)) +print('electron elastic power loss = {0:7f} [eV/s]'.format(air.electron_elastic_power_loss)) +print('electron inelastic power loss = {0:7f} [eV/s]'.format(air.electron_inelastic_power_loss)) +print('mean electron energy = {0:7f} [eV]'.format(air.mean_electron_energy)) + +# Here, we demonstrate another way to initiate the gas for electron properties. +# This method enable we to use multiple files +ecs = ct.ElectronCrossSection.listFromFile('lxcat.yaml') +gas = ct.Solution('gri30_plasma.cti', electron='WeaklyIonizedGas', electron_cross_sections=ecs) +gas.TPX = T, p, reactants +gas.electric_field = 1e5 + +# set up proper grid for the electric field +grid = np.linspace(0.0, 30, num=500) +gas.set_electron_energy_grid(grid) + +# We can also use species index to find electron transport properties +gas.electron_transport_enabled = True +i = gas.species_index('E') +print('electron diffusivity = {0:7f} [m^2/s]'.format(gas.mix_diff_coeffs[i])) +print('electron mobility = {0:7f} [m^2/V/s]'.format(gas.mobilities[i])) + +# and reaction rate of electron reaction which depends on electron temperature +gas.electron_temperature_reactions_enabled = True +print(gas.reaction_equation(331)) +print('rate coefficient = {0:7f} [m^3/kmol/s]'.format(gas.forward_rate_constants[331])) + From 718261d7a9fb79d580e5ce9f22f1d99477be39a6 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 12 Aug 2019 11:59:16 -0400 Subject: [PATCH 046/139] [data] update gri30_plasma --- data/inputs/gri30_plasma.cti | 39 +++++++++--------------------------- 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/data/inputs/gri30_plasma.cti b/data/inputs/gri30_plasma.cti index b66105e48ae..f121e01cec3 100644 --- a/data/inputs/gri30_plasma.cti +++ b/data/inputs/gri30_plasma.cti @@ -9,7 +9,7 @@ ideal_gas(name='gas', N NH NH2 NH3 NNH NO NO2 N2O HNO CN HCN H2CN HCNN HCNO HOCN HNCO NCO AR C3H7 C3H8 CH2CHO CH3CHO''', - 'HCO+ H3O+ E O2(0.98)'], + 'HCO+ H3O+ E'], reactions=['gri30: all', 'all'], transport='Ion', options=['skip_undeclared_species', 'skip_undeclared_third_bodies'], @@ -213,24 +213,6 @@ species(name = 'E', polar=0.667), note = 'The transport parameters are not used in IonGasTransport') -species(name = "O2(0.98)", - atoms = " O:2 ", - thermo = ( - NASA( [ 200.00, 1000.00], [ 3.782456360E+00, -2.996734160E-03, - 9.847302010E-06, -9.681295090E-09, 3.243728370E-12, - -1.063943560E+03, 3.657675730E+00] ), - NASA( [ 1000.00, 3500.00], [ 3.282537840E+00, 1.483087540E-03, - -7.579666690E-07, 2.094705550E-10, -2.167177940E-14, - -1.088457720E+03, 5.453231290E+00] ) - ), - transport = gas_transport( - geom = "linear", - diam = 3.46, - well_depth = 107.40, - polar = 1.131, - rot_relax = 3.80), - note = "Assume same transport and thermo as O2" - ) #------------------------------------------------------------------------------- # Reaction data #------------------------------------------------------------------------------- @@ -239,6 +221,14 @@ reaction('CH + O => HCO+ + E', [2.51E+11, 0.0, 1700]) reaction('HCO+ + H2O => H3O+ + CO', [1.51E+15, 0.0, 0.0]) +reaction('H3O+ + E => H2O + H', [2.29E+18, -0.5, 0.0]) + +reaction('H3O+ + E => OH + H + H', [7.95E+21, -1.4, 0.0]) + +reaction('H3O+ + E => H2 + OH', [1.25E+19, -0.5, 0.0]) + +reaction('H3O+ + E => O + H2 + H', [6.0E+17, -0.3, 0.0]) + # DeFilippo, Anthony C., and Jyh-Yuan Chen. "Modeling plasma-assisted methane–air ignition using pre-calculated electron impact reaction rates." Combustion and Flame 172 (2016): 38-48. electron_reaction('H3O+ + E => H2O + H', [6.060000e+19, -1.1, 0.0]) @@ -249,14 +239,3 @@ electron_reaction('H3O+ + E => OH + H2', [3.700000e+19, -1.1, 0.0]) electron_reaction('H3O+ + E => O + H2 + H', [1.350000e+19, -1.1, 0.0]) -three_body_reaction('O2(0.98) + M => O2 + M', [1.000000e+06, 0.0, 0.0], - efficiencies='CO:2.0 H:0.0 H2O:1.24 HO2:11100.0 N2:0.000667 O:160.0 O2:0.37 O3:890.0') - -reaction('O2(0.98) => O2', [2.600000e-04, 0.0, 0.0]) - -reaction('CH3 + O2(0.98) => CH3O + O', [2.110000e+13, 0.0, 14374]) - -reaction('CH3 + O2(0.98) => CH2O + OH', [6.620000e+11, 0.0, 10876]) - -reaction('CH4 + O2(0.98) <=> CH3 + HO2', [7.060000e+07, 1.97, 33523]) - From 534fdf5a76440b8efd9d5e86a7bc263cf5ea4865 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 12 Aug 2019 13:02:43 -0400 Subject: [PATCH 047/139] [interface-transport] add electron_transport_enabled --- interfaces/cython/cantera/transport.pyx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/interfaces/cython/cantera/transport.pyx b/interfaces/cython/cantera/transport.pyx index 69375207c75..67095d950f9 100644 --- a/interfaces/cython/cantera/transport.pyx +++ b/interfaces/cython/cantera/transport.pyx @@ -233,6 +233,13 @@ cdef class Transport(_SolutionBase): def __get__(self): return get_transport_1d(self, tran_getMobilities) + property electron_transport_enabled: + """ + enable calculation of electron transport by solving Boltzmann equation + """ + def __set__(self, enable): + self.transport.enableElectron(enable) + cdef class DustyGasTransport(Transport): """ From 202ce0672a65ccbc7d76b7d5da054850b593361b Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 12 Aug 2019 13:22:41 -0400 Subject: [PATCH 048/139] [interface-kinetics] add electron_temperature_reactions_enabled --- interfaces/cython/cantera/_cantera.pxd | 1 + interfaces/cython/cantera/kinetics.pyx | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 3eaee1d8fe8..fa1f09e55dc 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -487,6 +487,7 @@ cdef extern from "cantera/kinetics/Kinetics.h" namespace "Cantera": double multiplier(int) void setMultiplier(int, double) void setElectronTemperature(double) + void enableElectron(cbool) except +translate_exception cdef extern from "cantera/kinetics/InterfaceKinetics.h": diff --git a/interfaces/cython/cantera/kinetics.pyx b/interfaces/cython/cantera/kinetics.pyx index 0359492caa8..92b0967569a 100644 --- a/interfaces/cython/cantera/kinetics.pyx +++ b/interfaces/cython/cantera/kinetics.pyx @@ -389,6 +389,13 @@ cdef class Kinetics(_SolutionBase): def __get__(self): return - self.net_rates_of_progress * self.delta_enthalpy + property electron_temperature_reactions_enabled: + """ + enable calculation of electron temperature by solving Boltzmann equation + """ + def __set__(self, enable): + self.kinetics.enableElectron(enable) + cdef class InterfaceKinetics(Kinetics): """ From 9bff4e043de79aa6ce77d6fc38be162e164cfa53 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 12 Aug 2019 14:17:11 -0400 Subject: [PATCH 049/139] [date] update ch4_plasma --- test/data/ch4_plasma.cti | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/test/data/ch4_plasma.cti b/test/data/ch4_plasma.cti index 146dbfe4099..1b7792aa5f0 100644 --- a/test/data/ch4_plasma.cti +++ b/test/data/ch4_plasma.cti @@ -245,6 +245,14 @@ reaction('CH + O => HCO+ + E', [2.51E+11, 0.0, 1700]) reaction('HCO+ + H2O => H3O+ + CO', [1.51E+15, 0.0, 0.0]) +reaction('H3O+ + E => H2O + H', [2.29E+18, -0.5, 0.0]) + +reaction('H3O+ + E => OH + H + H', [7.95E+21, -1.4, 0.0]) + +reaction('H3O+ + E => H2 + OH', [1.25E+19, -0.5, 0.0]) + +reaction('H3O+ + E => O + H2 + H', [6.0E+17, -0.3, 0.0]) + # DeFilippo, Anthony C., and Jyh-Yuan Chen. "Modeling plasma-assisted methane–air ignition using pre-calculated electron impact reaction rates." Combustion and Flame 172 (2016): 38-48. electron_reaction('H3O+ + E => H2O + H', [6.060000e+19, -1.1, 0.0]) @@ -255,14 +263,3 @@ electron_reaction('H3O+ + E => OH + H2', [3.700000e+19, -1.1, 0.0]) electron_reaction('H3O+ + E => O + H2 + H', [1.350000e+19, -1.1, 0.0]) -three_body_reaction('O2(0.98) + M => O2 + M', [1.000000e+06, 0.0, 0.0], - efficiencies='CO:2.0 H:0.0 H2O:1.24 HO2:11100.0 N2:0.000667 O:160.0 O2:0.37 O3:890.0') - -reaction('O2(0.98) => O2', [2.600000e-04, 0.0, 0.0]) - -reaction('CH3 + O2(0.98) => CH3O + O', [2.110000e+13, 0.0, 14374]) - -reaction('CH3 + O2(0.98) => CH2O + OH', [6.620000e+11, 0.0, 10876]) - -reaction('CH4 + O2(0.98) <=> CH3 + HO2', [7.060000e+07, 1.97, 33523]) - From 609a3127daa683ec135c320a38ca49fba2bce33b Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 12 Aug 2019 18:50:20 -0400 Subject: [PATCH 050/139] [electron] add functions and move member functions to protected --- include/cantera/electron/Electron.h | 82 ++++++++++++++++++++++------- src/electron/Electron.cpp | 21 ++++++++ src/electron/WeakIonGasElectron.cpp | 14 +++-- 3 files changed, 91 insertions(+), 26 deletions(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index b366279c0d5..5669322042f 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -132,6 +132,46 @@ class Electron } } + //! target of a specific process + std::string target(size_t k) { + return m_targets[k]; + } + + //! index of target + size_t targetIndex(size_t k) { + return m_kTargets[k]; + } + + //! kind of a specific process + std::string kind(size_t k) { + return m_kinds[k]; + } + + //! product of a specific process + std::string product(size_t k) { + return m_products[k]; + } + + //! index of the first product + size_t firstProductIndex(size_t k) { + return m_kProducts[k][0]; + } + + //! index of the second product + size_t secondProductIndex(size_t k) { + return m_kProducts[k][1]; + } + + //! threshold of a specific process + double threshold(size_t k) { + return m_thresholds[k]; + } + + //! scattering-in factor + int inFactor(size_t k) { + return m_inFactor[k]; + } + /** * Set the parameters for the Boltzmann solver * @param maxn Maximum number of iterations @@ -173,24 +213,6 @@ class Electron //! which take an array pointer. void checkSpeciesArraySize(size_t k) const; - //! list of targets of electron collision - std::vector m_targets; - - //! list of kinds of electron collision - std::vector m_kinds; - - //! list of products of electron collision - std::vector m_products; - - //! list of mass ratio of electron to target species - vector_fp m_massRatios; - - //! list of thresholds of electron collision - vector_fp m_thresholds; - - //! cross sections - std::vector>> m_crossSections; - protected: //! Cached for saved calculations within each Electron. /*! @@ -298,6 +320,30 @@ class Electron //! The energy boundaries of the overlap of cell i and j std::vector> m_eps; + + //! list of targets of electron collision + std::vector m_targets; + + //! list of kinds of electron collision + std::vector m_kinds; + + //! list of products of electron collision + std::vector m_products; + + //! list of mass ratio of electron to target species + vector_fp m_massRatios; + + //! list of thresholds of electron collision + vector_fp m_thresholds; + + //! cross sections + std::vector>> m_crossSections; + + //! list of target index + std::vector m_kTargets; + + //! list of product index + std::vector> m_kProducts; }; } diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index afdb4891e5e..4fe390389df 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -48,6 +48,27 @@ void Electron::init(thermo_t* thermo) m_f0_ok = false; calculateElasticCrossSection(); setGridCache(); + // set up target index + m_kTargets.resize(m_ncs); + for (size_t k = 0; k < m_ncs; k++) { + m_kTargets[k] = m_thermo->speciesIndex(m_targets[k]); + } + m_kProducts.clear(); + m_kProducts.resize(m_ncs); + for (size_t k = 0; k < m_ncs; k++) { + std::string prdct = m_products[k]; + size_t dp = prdct.find(" + "); + if (dp != npos) { + size_t kp0 = m_thermo->speciesIndex(prdct.substr(0, dp)); + prdct.erase(0, dp + 3); + size_t kp1 = m_thermo->speciesIndex(prdct); + m_kProducts[k].push_back(kp0); + m_kProducts[k].push_back(kp1); + } else { + size_t kp0 = m_thermo->speciesIndex(prdct); + m_kProducts[k].push_back(kp0); + } + } } void Electron::setGridCache() diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index 3d3d80dd393..21f48dc84e5 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -490,20 +490,18 @@ void WeakIonGasElectron::getNetPlasmaProductionRates(double* wdot) if (kr != npos) { double rate = m_N * m_N * m_moleFractions[k] * X_E * rateCoefficient(k) / Avogadro; - std::string prdct = m_products[k]; - size_t dp = prdct.find(" + "); - if (dp != npos) { - size_t kp0 = m_thermo->speciesIndex(prdct.substr(0, dp)); - prdct.erase(0, dp + 3); - size_t kp1 = m_thermo->speciesIndex(prdct); + + if (m_kProducts[k].size() == 2) { + size_t kp0 = m_kProducts[k][0]; + size_t kp1 = m_kProducts[k][1]; if (kp0 != npos && kp1 != npos) { wdot[kp0] += rate; wdot[kp1] += rate; wdot[kr] -= rate; wdot[k_E] += (m_inFactor[k] - 1) * rate; } - } else { - size_t kp0 = m_thermo->speciesIndex(prdct); + } else if (m_kProducts[k].size() == 1) { + size_t kp0 = m_kProducts[k][0]; if (kp0 != npos) { wdot[kp0] += rate; wdot[kr] -= rate; From 8bc197631c4748331c30586b286798510f2c2d5d Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 12 Aug 2019 19:04:43 -0400 Subject: [PATCH 051/139] [interface-electron] add target kind product threshold --- interfaces/cython/cantera/_cantera.pxd | 4 ++++ interfaces/cython/cantera/electron.pyx | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index fa1f09e55dc..9285143acb1 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -176,6 +176,10 @@ cdef extern from "cantera/electron/Electron.h" namespace "Cantera": double electronTemperature() void setChemionScatRate(double) void setBoltzmannSolver(size_t, double, double, double, double, cbool) + string target(size_t) + string kind(size_t) + string product(size_t) + double threshold(size_t) # initialization cbool addElectronCrossSection(shared_ptr[CxxElectronCrossSection]) except +translate_exception diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/electron.pyx index 43bd4730c88..38c76ed208e 100644 --- a/interfaces/cython/cantera/electron.pyx +++ b/interfaces/cython/cantera/electron.pyx @@ -110,6 +110,18 @@ cdef class Electron(_SolutionBase): def __set__(self, F): self.electron.setElectricFieldFreq(F) + def electron_collision_target(self, k): + return pystr(self.electron.target(k)) + + def electron_collision_kind(self, k): + return pystr(self.electron.kind(k)) + + def electron_collision_product(self,k): + return pystr(self.electron.product(k)) + + def electron_collision_threshold(self, k): + return self.electron.threshold(k) + cdef class ElectronCrossSection: """ From 3ff2f3b096ca0c7b29bd0099f0fc06a3333d51b4 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 13 Aug 2019 14:52:53 -0400 Subject: [PATCH 052/139] [electron] update getNetPlasmaProductionRates and init --- src/electron/Electron.cpp | 1 + src/electron/WeakIonGasElectron.cpp | 26 ++++++++------------------ 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index 4fe390389df..52a7f57a44e 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -67,6 +67,7 @@ void Electron::init(thermo_t* thermo) } else { size_t kp0 = m_thermo->speciesIndex(prdct); m_kProducts[k].push_back(kp0); + m_kProducts[k].push_back(9999); } } } diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index 21f48dc84e5..ae9dde6e034 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -487,27 +487,17 @@ void WeakIonGasElectron::getNetPlasmaProductionRates(double* wdot) double X_E = m_thermo->moleFraction("E"); for (size_t k : m_kInelastic) { size_t kr = m_thermo->speciesIndex(m_targets[k]); - if (kr != npos) { + size_t kp0 = m_kProducts[k][0]; + size_t kp1 = m_kProducts[k][1]; + if (kr != npos && kp0 != npos && kp1 != npos) { double rate = m_N * m_N * m_moleFractions[k] * X_E * rateCoefficient(k) / Avogadro; - - if (m_kProducts[k].size() == 2) { - size_t kp0 = m_kProducts[k][0]; - size_t kp1 = m_kProducts[k][1]; - if (kp0 != npos && kp1 != npos) { - wdot[kp0] += rate; - wdot[kp1] += rate; - wdot[kr] -= rate; - wdot[k_E] += (m_inFactor[k] - 1) * rate; - } - } else if (m_kProducts[k].size() == 1) { - size_t kp0 = m_kProducts[k][0]; - if (kp0 != npos) { - wdot[kp0] += rate; - wdot[kr] -= rate; - wdot[k_E] += (m_inFactor[k] - 1) * rate; - } + wdot[kp0] += rate; + if (kp1 != 9999) { + wdot[kp1] += rate; } + wdot[kr] -= rate; + wdot[k_E] += (m_inFactor[k] - 1) * rate; } } } From 25fd75c3be483df46c9bdeaf7b0ba9a8d668c517 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 19 Aug 2019 16:52:46 -0400 Subject: [PATCH 053/139] [administration] change http to https for class electron --- include/cantera/electron/Electron.h | 2 +- include/cantera/electron/ElectronCrossSection.h | 2 +- include/cantera/electron/ElectronFactory.h | 2 +- include/cantera/electron/WeakIonGasElectron.h | 2 +- interfaces/cython/cantera/electron.pyx | 2 +- src/electron/Electron.cpp | 2 +- src/electron/ElectronCrossSection.cpp | 2 +- src/electron/ElectronFactory.cpp | 2 +- src/electron/WeakIonGasElectron.cpp | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index 5669322042f..3b3936089a0 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -4,7 +4,7 @@ */ // This file is part of Cantera. See License.txt in the top-level directory or -// at http://www.cantera.org/license.txt for license and copyright information. +// at https://www.cantera.org/license.txt for license and copyright information. #ifndef CT_ELECTRON_H #define CT_ELECTRON_H diff --git a/include/cantera/electron/ElectronCrossSection.h b/include/cantera/electron/ElectronCrossSection.h index 8537a8d79e0..1fb328186b4 100644 --- a/include/cantera/electron/ElectronCrossSection.h +++ b/include/cantera/electron/ElectronCrossSection.h @@ -1,7 +1,7 @@ //! @file Species.h Declaration for class Cantera::Species. // This file is part of Cantera. See License.txt in the top-level directory or -// at http://www.cantera.org/license.txt for license and copyright information. +// at https://www.cantera.org/license.txt for license and copyright information. #ifndef CT_ELECTRONCROSSSECTION_H #define CT_ELECTRONCROSSSECTION_H diff --git a/include/cantera/electron/ElectronFactory.h b/include/cantera/electron/ElectronFactory.h index c8f7a2b4d67..c2c79e45a97 100644 --- a/include/cantera/electron/ElectronFactory.h +++ b/include/cantera/electron/ElectronFactory.h @@ -4,7 +4,7 @@ */ // This file is part of Cantera. See License.txt in the top-level directory or -// at http://www.cantera.org/license.txt for license and copyright information. +// at https://www.cantera.org/license.txt for license and copyright information. #ifndef ELECTRON_FACTORY_H #define ELECTRON_FACTORY_H diff --git a/include/cantera/electron/WeakIonGasElectron.h b/include/cantera/electron/WeakIonGasElectron.h index ac6a0b0a516..fcc39abbabb 100644 --- a/include/cantera/electron/WeakIonGasElectron.h +++ b/include/cantera/electron/WeakIonGasElectron.h @@ -4,7 +4,7 @@ */ // This file is part of Cantera. See License.txt in the top-level directory or -// at http://www.cantera.org/license.txt for license and copyright information. +// at https://www.cantera.org/license.txt for license and copyright information. #ifndef CT_WEAKIONGASELECTRON_H #define CT_WEAKIONGASELECTRON_H diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/electron.pyx index 38c76ed208e..4b29fd7aa23 100644 --- a/interfaces/cython/cantera/electron.pyx +++ b/interfaces/cython/cantera/electron.pyx @@ -1,5 +1,5 @@ # This file is part of Cantera. See License.txt in the top-level directory or -# at http://www.cantera.org/license.txt for license and copyright information. +# at https://www.cantera.org/license.txt for license and copyright information. import warnings import weakref diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index 52a7f57a44e..8d72db4bb72 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -1,5 +1,5 @@ // This file is part of Cantera. See License.txt in the top-level directory or -// at http://www.cantera.org/license.txt for license and copyright information. +// at https://www.cantera.org/license.txt for license and copyright information. #include "cantera/electron/Electron.h" #include "cantera/base/stringUtils.h" diff --git a/src/electron/ElectronCrossSection.cpp b/src/electron/ElectronCrossSection.cpp index e10e832381d..a0df64c5d68 100644 --- a/src/electron/ElectronCrossSection.cpp +++ b/src/electron/ElectronCrossSection.cpp @@ -1,5 +1,5 @@ // This file is part of Cantera. See License.txt in the top-level directory or -// at http://www.cantera.org/license.txt for license and copyright information. +// at https://www.cantera.org/license.txt for license and copyright information. #include "cantera/electron/ElectronCrossSection.h" #include "cantera/base/stringUtils.h" diff --git a/src/electron/ElectronFactory.cpp b/src/electron/ElectronFactory.cpp index c50958e9c35..5f705662121 100644 --- a/src/electron/ElectronFactory.cpp +++ b/src/electron/ElectronFactory.cpp @@ -4,7 +4,7 @@ */ // This file is part of Cantera. See License.txt in the top-level directory or -// at http://www.cantera.org/license.txt for license and copyright information. +// at https://www.cantera.org/license.txt for license and copyright information. #include "cantera/electron/ElectronFactory.h" #include "cantera/electron/Electron.h" diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index ae9dde6e034..612b7f7018f 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -1,5 +1,5 @@ // This file is part of Cantera. See License.txt in the top-level directory or -// at http://www.cantera.org/license.txt for license and copyright information. +// at https://www.cantera.org/license.txt for license and copyright information. #include "cantera/electron/WeakIonGasElectron.h" #include "cantera/electron/ElectronFactory.h" From 0e0e85ff84a69e4075ecb5fd8d555f8814433611 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 7 Oct 2019 13:47:32 -0400 Subject: [PATCH 054/139] [Transport] add m_electronMobility --- include/cantera/transport/IonGasTransport.h | 2 ++ src/transport/IonGasTransport.cpp | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/cantera/transport/IonGasTransport.h b/include/cantera/transport/IonGasTransport.h index 224ab10e26b..2b6ae718b6f 100644 --- a/include/cantera/transport/IonGasTransport.h +++ b/include/cantera/transport/IonGasTransport.h @@ -128,6 +128,8 @@ class IonGasTransport : public MixTransport //! electron class Electron* m_electron; + double m_electronMobility; + bool m_do_electron; }; diff --git a/src/transport/IonGasTransport.cpp b/src/transport/IonGasTransport.cpp index f27073a8f5a..a2d4230f4c3 100644 --- a/src/transport/IonGasTransport.cpp +++ b/src/transport/IonGasTransport.cpp @@ -13,6 +13,7 @@ namespace Cantera IonGasTransport::IonGasTransport() : m_kElectron(npos), m_electron(NULL), + m_electronMobility(0.4), m_do_electron(false) { } @@ -362,7 +363,7 @@ void IonGasTransport::getMixDiffCoeffs(double* const d) if (m_electron && m_do_electron) { d[m_kElectron] = m_electron->electronDiffusivity(); } else { - d[k] = 0.4 * m_kbt / ElectronCharge; + d[k] = m_electronMobility * m_kbt / ElectronCharge; } } else { double sum2 = 0.0; @@ -402,7 +403,7 @@ void IonGasTransport::getMixDiffCoeffsMass(double* const d) if (m_electron && m_do_electron) { d[m_kElectron] = m_electron->electronDiffusivity(); } else { - d[k] = 0.4 * m_kbt / ElectronCharge; + d[k] = m_electronMobility * m_kbt / ElectronCharge; } } else { double sum1 = 0.0; @@ -441,7 +442,7 @@ void IonGasTransport::getMixDiffCoeffsMole(double* const d) if (m_electron && m_do_electron) { d[m_kElectron] = m_electron->electronDiffusivity(); } else { - d[k] = 0.4 * m_kbt / ElectronCharge; + d[k] = m_electronMobility * m_kbt / ElectronCharge; } } else { double sum2 = 0.0; @@ -475,7 +476,7 @@ void IonGasTransport::getMobilities(double* const mobi) if (m_electron && m_do_electron) { mobi[k] = m_electron->electronMobility(); } else { - mobi[k] = 0.4; + mobi[k] = m_electronMobility; } } else { mobi[k] = 0.0; From 5d1066f39615ec1daf801c7a03048abcc9c3d9d7 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 8 Nov 2019 11:43:07 -0500 Subject: [PATCH 055/139] [oneD] fix left b.c. for ions --- src/oneD/IonFlow.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/oneD/IonFlow.cpp b/src/oneD/IonFlow.cpp index 0f894eb17cd..5d0d11bbfa7 100644 --- a/src/oneD/IonFlow.cpp +++ b/src/oneD/IonFlow.cpp @@ -180,9 +180,6 @@ void IonFlow::evalResidual(double* x, double* rsd, int* diag, // enforcing the flux for charged species is difficult // since charged species are also affected by electric // force, so Neumann boundary condition is used. - for (size_t k : m_kCharge) { - rsd[index(c_offset_Y + k, 0)] = Y(x,k,0) - Y(x,k,1); - } rsd[index(c_offset_E, j)] = E(x,0); diag[index(c_offset_E, j)] = 0; } else if (j == m_points - 1) { From c99d892ec4e6e402747668a924340bfc3d7145ad Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 15 Dec 2019 08:25:42 -0500 Subject: [PATCH 056/139] [kinetics] add document --- include/cantera/kinetics/RateCoeffMgr.h | 6 ++++++ include/cantera/kinetics/Reaction.h | 2 ++ include/cantera/kinetics/RxnRates.h | 15 +++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/cantera/kinetics/RateCoeffMgr.h b/include/cantera/kinetics/RateCoeffMgr.h index 83847ca6106..468884763c7 100644 --- a/include/cantera/kinetics/RateCoeffMgr.h +++ b/include/cantera/kinetics/RateCoeffMgr.h @@ -69,6 +69,12 @@ class Rate1 } } + /** + * Similar as update(double, double, double*) but with an extra argument + * (second argument) of electron temperature, and change logT to logTe. + * This is used for plasma reactions where the electrons have a different + * temperature. + */ void update(double T, double Te, double logTe, double* values) { double recipT = 1.0/T; double recipTe = 1.0/Te; diff --git a/include/cantera/kinetics/Reaction.h b/include/cantera/kinetics/Reaction.h index 5dd614ddb3b..8761eed1cdb 100644 --- a/include/cantera/kinetics/Reaction.h +++ b/include/cantera/kinetics/Reaction.h @@ -92,6 +92,8 @@ class ElementaryReaction : public Reaction bool allow_negative_pre_exponential_factor; }; +//! A reaction which depends on electron temperature, usually including +//! electron as a reactant species. class ElectronReaction : public Reaction { public: diff --git a/include/cantera/kinetics/RxnRates.h b/include/cantera/kinetics/RxnRates.h index edc43311c91..6ac77d83053 100644 --- a/include/cantera/kinetics/RxnRates.h +++ b/include/cantera/kinetics/RxnRates.h @@ -98,6 +98,14 @@ class Arrhenius doublereal m_logA, m_b, m_E, m_A; }; +//! An Arrhenius rate depends on gas and electron temperature +/** + * A reaction rate coefficient of the following form. + * + * \f[ + * k_f = A Te^b \exp (-E1/RTg) \exp (-E2/RTe) + * \f] + */ class ElectronArrhenius { public: @@ -113,8 +121,9 @@ class ElectronArrhenius /// @param A pre-exponential. The unit system is /// (kmol, m, s). The actual units depend on the reaction /// order and the dimensionality (surface or bulk). - /// @param b Temperature exponent. Non-dimensional. - /// @param E Activation energy in temperature units. Kelvin. + /// @param b Temperature exponent (electron temperature). Non-dimensional. + /// @param E1 Activation energy in temperature units for gas temperature. Kelvin. + /// @param E2 Activation energy in temperature units for electron temperature. Kelvin. ElectronArrhenius(double A, double b, double E1, double E2); //! Update concentration-dependent parts of the rate coefficient. @@ -159,6 +168,8 @@ class ElectronArrhenius return m_E1; } + //! Return the activation electron energy divid by the gas constant + //! (i.e. the activation electron temperature) [K] double activationElectronEnergy_R() const { return m_E2; } From b1b6470c5e2c4eb170034f8edc2bb3d132c70b45 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 16 Dec 2019 07:38:07 -0500 Subject: [PATCH 057/139] [numerics] add comment --- include/cantera/numerics/funcs.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/cantera/numerics/funcs.h b/include/cantera/numerics/funcs.h index cbb8e4ecafd..5b6b38b30b5 100644 --- a/include/cantera/numerics/funcs.h +++ b/include/cantera/numerics/funcs.h @@ -30,6 +30,12 @@ namespace Cantera doublereal linearInterp(doublereal x, const vector_fp& xpts, const vector_fp& fpts); +//! Calculate the quadrature of a discrete function by simpson's 1/3 rule. +/*! + * @param x coordinate vector + * @param y function vector + * @returns the value of the quadrature. + */ double simpsonQuadrature(const vector_fp& x, const vector_fp& y); } From 93b5c56134106baac6cd9628e2cd1eac97205e09 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 20 Dec 2019 02:05:53 -0500 Subject: [PATCH 058/139] [electron, interface] change inverseReaction to reverseReaction --- include/cantera/electron/Electron.h | 6 +++--- include/cantera/electron/WeakIonGasElectron.h | 2 +- interfaces/cython/cantera/_cantera.pxd | 2 +- interfaces/cython/cantera/electron.pyx | 6 +++--- src/electron/WeakIonGasElectron.cpp | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index 3b3936089a0..2a0b002e8db 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -93,9 +93,9 @@ class Electron throw NotImplementedError("Electron::rateCoefficient"); } - //! inverse rate coefficient. [m^3/s] - virtual double inverseRateCoefficient(size_t k) { - throw NotImplementedError("Electron::inverseRateCoefficient"); + //! reverse rate coefficient. [m^3/s] + virtual double reverseRateCoefficient(size_t k) { + throw NotImplementedError("Electron::reverseRateCoefficient"); } //! net plasma production rates diff --git a/include/cantera/electron/WeakIonGasElectron.h b/include/cantera/electron/WeakIonGasElectron.h index fcc39abbabb..1317abcc48a 100644 --- a/include/cantera/electron/WeakIonGasElectron.h +++ b/include/cantera/electron/WeakIonGasElectron.h @@ -48,7 +48,7 @@ class WeakIonGasElectron: public Electron virtual double elasticPowerLoss(); virtual double inelasticPowerLoss(); virtual double totalCollisionFreq(); - virtual double inverseRateCoefficient(size_t k); + virtual double reverseRateCoefficient(size_t k); virtual double rateCoefficient(size_t k); virtual void getNetPlasmaProductionRates(double* wdot); diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 9285143acb1..d0ecf6f9c42 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -165,7 +165,7 @@ cdef extern from "cantera/electron/Electron.h" namespace "Cantera": double meanElectronEnergy() double totalCollisionFreq() double rateCoefficient(size_t) - double inverseRateCoefficient(size_t) + double reverseRateCoefficient(size_t) double powerGain() double elasticPowerLoss() double inelasticPowerLoss() diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/electron.pyx index 4b29fd7aa23..1a78bb8c0cc 100644 --- a/interfaces/cython/cantera/electron.pyx +++ b/interfaces/cython/cantera/electron.pyx @@ -49,9 +49,9 @@ cdef class Electron(_SolutionBase): """rate coefficient of process k""" return self.electron.rateCoefficient(k) - def electron_inverse_rate_coefficient(self, k): - """inverse rate coefficient of process k""" - return self.electron.inverseRateCoefficient(k) + def electron_reverse_rate_coefficient(self, k): + """reverse rate coefficient of process k""" + return self.electron.reverseRateCoefficient(k) property electron_power_gain: """ diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index 612b7f7018f..3b29df079e4 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -413,7 +413,7 @@ double WeakIonGasElectron::inelasticPowerLoss() double y_up = 1.0 - y_low; sum += m_thresholds[k] * m_moleFractions[k] * (y_low * rateCoefficient(k) - - y_up * inverseRateCoefficient(k)); + y_up * reverseRateCoefficient(k)); } } return sum * m_N; @@ -432,7 +432,7 @@ double WeakIonGasElectron::rateCoefficient(size_t k) return sum; } -double WeakIonGasElectron::inverseRateCoefficient(size_t k) +double WeakIonGasElectron::reverseRateCoefficient(size_t k) { calculateDistributionFunction(); vector_fp g = vector_g(m_f0); From 8200a527488ac0d6d42a12f110cf50fc857bb017 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 20 Dec 2019 22:12:06 -0500 Subject: [PATCH 059/139] [electron] update Electron.cpp Electron.h --- include/cantera/electron/Electron.h | 71 ++++++------ .../cantera/electron/ElectronCrossSection.h | 5 +- src/electron/Electron.cpp | 101 +++++++++--------- 3 files changed, 86 insertions(+), 91 deletions(-) diff --git a/include/cantera/electron/Electron.h b/include/cantera/electron/Electron.h index 2a0b002e8db..a023769248b 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/electron/Electron.h @@ -18,7 +18,17 @@ namespace Cantera { /** - * This class calculates the properties of electron in a gas. + * @defgroup electron + * This class calculates the electron energy distribution function (EEDF) in a gas + * by modeling collisions between electrons and other species represented by the + * class ElectronCrossSection. EEDF is used to calculate reaction rate coefficient + * for plasma reaction and electron temperature for electron-temperature reaction + * used in kinetics, and diffusivity/mobility of electron in transport. + */ + +/*! + * Class Electron is the base class which manages the grid and grid cache, + * cross-section data, and updating temperature and gas composition. * @ingroup electron */ class Electron @@ -32,7 +42,7 @@ class Electron Electron(const Electron&) = delete; Electron& operator=(const Electron&) = delete; - //! Add a electron corss section to this Electron. Returns `true` if the electron cross section was + //! Add an electron cross section to this Electron. Returns `true` if the electron cross section was //! successfully added, or `false` if the electron cross section was ignored. virtual bool addElectronCrossSection(shared_ptr ecs); @@ -48,10 +58,11 @@ class Electron //! energy grid double grid(size_t i) const { - return m_gridC[i]; + return m_gridCenter[i]; } - //! Setup grid of electron energy. + //! Setup grid of electron energy. n is the dimension of grid. + //! eps is the vector of electron energy [eV]. void setupGrid(size_t n, const double* eps); //! electron diffusivity @@ -85,15 +96,15 @@ class Electron //! total collision frequency virtual double totalCollisionFreq() { - throw NotImplementedError("Electron::inelasticPowerLoss"); + throw NotImplementedError("Electron::totalCollisionFreq"); } - //! rate coefficient. [m^3/s] + //! rate coefficient for the electron collision process. [m^3/s] virtual double rateCoefficient(size_t k) { throw NotImplementedError("Electron::rateCoefficient"); } - //! reverse rate coefficient. [m^3/s] + //! reverse rate coefficient for the electron collision process. [m^3/s] virtual double reverseRateCoefficient(size_t k) { throw NotImplementedError("Electron::reverseRateCoefficient"); } @@ -208,26 +219,14 @@ class Electron throw NotImplementedError("Electron::setChemionScatRate"); } - //! Check that an array size is at least nSpecies() - //! Throws an exception if kk is less than nSpecies(). Used before calls - //! which take an array pointer. - void checkSpeciesArraySize(size_t k) const; - protected: - //! Cached for saved calculations within each Electron. - /*! - * For more information on how to use this, see examples within the source - * code and documentation for this within ValueCache class itself. - */ - mutable ValueCache m_cache; - // set grid cache void setGridCache(); - //! Update temperature + //! update temperature-dependent properties void update_T(); - //! Update composition + //! update composition-dependent properties void update_C(); //! Calculate elastic cross section @@ -237,10 +236,10 @@ class Electron size_t m_ncs; //! Grid of electron energy (cell center) [eV] - vector_fp m_gridC; + vector_fp m_gridCenter; //! Grid of electron energy (cell boundary i-1/2) [eV] - vector_fp m_gridB; + vector_fp m_gridEdge; //! number of points for energy grid size_t m_points; @@ -260,38 +259,33 @@ class Electron //! constant gamma double m_gamma; - //! mole fractions of target + //! Mole fractions of target species of each collision process vector_fp m_moleFractions; //! shift factor std::vector m_shiftFactor; std::vector m_inFactor; - //! list elastic + //! Indices of elastic collisions in m_crossSections std::vector m_kElastic; - //! list inelastic + //! Indices of inelastic collisions in m_crossSections std::vector m_kInelastic; - //! list effective + //! Indices of effective collisions in m_crossSections std::vector m_kEffective; - //! list solo elastic - std::vector m_kSoloElastic; - //! flag of electron energy distribution function bool m_f0_ok; //! pointer to the object representing the phase thermo_t* m_thermo; - //! local gas composition - compositionMap m_gasComposition; - //! Maximum number of iterations size_t m_maxn; - //! Relative tolerance + //! Relative tolerance of electron energy distribution function + //! for solving Boltzmann equation double m_rtol; //! Initial value of the iteration parameter @@ -336,12 +330,17 @@ class Electron //! list of thresholds of electron collision vector_fp m_thresholds; - //! cross sections + //! cross section data. m_crossSections[i][j][k] where i is the specific process, + //! j=0 is the vector of electron energy [eV], j=1 is the vector of cross section, and + // k is the index of vector. std::vector>> m_crossSections; - //! list of target index + //! list of target species indices std::vector m_kTargets; + //! Indices of species which has no cross-section data + std::vector m_kOthers; + //! list of product index std::vector> m_kProducts; }; diff --git a/include/cantera/electron/ElectronCrossSection.h b/include/cantera/electron/ElectronCrossSection.h index 1fb328186b4..45556bc3a86 100644 --- a/include/cantera/electron/ElectronCrossSection.h +++ b/include/cantera/electron/ElectronCrossSection.h @@ -1,4 +1,4 @@ -//! @file Species.h Declaration for class Cantera::Species. +//! @file ElectronCrossSection.h Declaration for class Cantera::Species. // This file is part of Cantera. See License.txt in the top-level directory or // at https://www.cantera.org/license.txt for license and copyright information. @@ -37,7 +37,8 @@ class ElectronCrossSection //! The product of electron collision std::string product; - //! Data + //! Data of cross section. data[i][j] where i is the index of a data point, + //! j=0 is the electron energy [eV], and j=1 is the cross section [m^2]. std::vector data; //! The mass ratio of molecule to electron diff --git a/src/electron/Electron.cpp b/src/electron/Electron.cpp index 8d72db4bb72..ff8544bc65f 100644 --- a/src/electron/Electron.cpp +++ b/src/electron/Electron.cpp @@ -27,14 +27,14 @@ Electron::Electron() , m_warn(true) { // default energy grid - m_gridC.resize(m_points); - m_gridB.resize(m_points + 1); + m_gridCenter.resize(m_points); + m_gridEdge.resize(m_points + 1); m_f0.resize(m_points); for (size_t j = 0; j < m_points; j++) { - m_gridC[j] = j / 20.0 + 1.0 / 40.0; - m_gridB[j] = j / 20.0; + m_gridCenter[j] = j / 20.0 + 1.0 / 40.0; + m_gridEdge[j] = j / 20.0; } - m_gridB[m_points] = 10.0; + m_gridEdge[m_points] = 10.0; m_gamma = pow(2.0 * ElectronCharge / ElectronMass, 0.5); } @@ -53,6 +53,13 @@ void Electron::init(thermo_t* thermo) for (size_t k = 0; k < m_ncs; k++) { m_kTargets[k] = m_thermo->speciesIndex(m_targets[k]); } + // set up indices of species which has no cross-section data + for (size_t k = 0; k < m_thermo->nSpecies(); k++) { + auto it = std::find(m_kTargets.begin(), m_kTargets.end(), k); + if (it == m_kTargets.end()) { + m_kOthers.push_back(k); + } + } m_kProducts.clear(); m_kProducts.resize(m_ncs); for (size_t k = 0; k < m_ncs; k++) { @@ -70,6 +77,7 @@ void Electron::init(thermo_t* thermo) m_kProducts[k].push_back(9999); } } + m_moleFractions.resize(m_ncs, 0.0); } void Electron::setGridCache() @@ -83,19 +91,18 @@ void Electron::setGridCache() m_i.clear(); m_i.resize(m_ncs); for (size_t k = 0; k < m_ncs; k++) { - vector_fp x = m_crossSections[k][0]; - vector_fp y = m_crossSections[k][1]; + vector_fp& x = m_crossSections[k][0]; + vector_fp& y = m_crossSections[k][1]; vector_fp eps1(m_points + 1); for (size_t i = 0; i < m_points + 1; i++) { - eps1[i] = m_shiftFactor[k] * m_gridB[i] + m_thresholds[k]; - eps1[i] = std::max(eps1[i], m_gridB[0] + 1e-9); - eps1[i] = std::min(eps1[i], m_gridB[m_points] - 1e-9); + eps1[i] = clip(m_shiftFactor[k] * m_gridEdge[i] + m_thresholds[k], + m_gridEdge[0] + 1e-9, m_gridEdge[m_points] - 1e-9); } vector_fp nodes = eps1; for (size_t i = 0; i < m_points + 1; i++) { - if (m_gridB[i] >= eps1[0] && m_gridB[i] <= eps1[m_points]) { - nodes.push_back(m_gridB[i]); + if (m_gridEdge[i] >= eps1[0] && m_gridEdge[i] <= eps1[m_points]) { + nodes.push_back(m_gridEdge[i]); } } for (size_t i = 0; i < x.size(); i++) { @@ -105,7 +112,7 @@ void Electron::setGridCache() } std::sort(nodes.begin(), nodes.end()); - vector_fp::iterator last = std::unique(nodes.begin(), nodes.end()); + auto last = std::unique(nodes.begin(), nodes.end()); nodes.resize(std::distance(nodes.begin(), last)); vector_fp sigma0(nodes.size()); for (size_t i = 0; i < nodes.size(); i++) { @@ -114,15 +121,13 @@ void Electron::setGridCache() // search position of cell j for (size_t i = 1; i < nodes.size(); i++) { - vector_fp::iterator low; - low = std::lower_bound(m_gridB.begin(), m_gridB.end(), nodes[i]); - m_j[k].push_back(low - m_gridB.begin() - 1); + auto low = std::lower_bound(m_gridEdge.begin(), m_gridEdge.end(), nodes[i]); + m_j[k].push_back(low - m_gridEdge.begin() - 1); } // search position of cell i for (size_t i = 1; i < nodes.size(); i++) { - vector_fp::iterator low; - low = std::lower_bound(eps1.begin(), eps1.end(), nodes[i]); + auto low = std::lower_bound(eps1.begin(), eps1.end(), nodes[i]); m_i[k].push_back(low - eps1.begin() - 1); } @@ -156,27 +161,24 @@ void Electron::update_C() { // signal that concentration-dependent quantities will need to be recomputed // before use, and update the local mole fractions. - compositionMap gas_composition = m_thermo->getMoleFractionsByName(0.0); - m_moleFractions.resize(m_ncs, 0.0); - for (auto const& x : gas_composition) { - bool not_found = true; - for (size_t k = 0; k < m_ncs; k++) { - if (m_targets[k] == x.first) { - if (m_moleFractions[k] != x.second) { - m_moleFractions[k] = x.second; - m_f0_ok = false; - } - not_found = false; - } + vector_fp X(m_thermo->nSpecies()); + m_thermo->getMoleFractions(&X[0]); + for (size_t k = 0; k < m_ncs; k++) { + size_t kk = m_kTargets[k]; + if (m_moleFractions[k] != X[kk]) { + m_moleFractions[k] = X[kk]; + m_f0_ok = false; } - if (not_found) { - if (x.second > 0.01 && m_warn) { - writelog("Cantera::Electron::update_C"); - writelog("\n"); - writelog("Warning: The mole fraction of species {} is more than 0.01", x.first); - writelog(" but it has no data of cross section."); - writelog("\n"); - } + } + // warn that a specific species needs cross-section data. + for (size_t k : m_kOthers) { + if (X[k] > 0.01) { + writelog("Cantera::Electron::update_C"); + writelog("\n"); + writelog("Warning: The mole fraction of species {} is more than 0.01", + m_thermo->speciesName(k)); + writelog(" but it has no data of cross section."); + writelog("\n"); } } } @@ -191,7 +193,7 @@ bool Electron::addElectronCrossSection(shared_ptr ecs) m_thresholds.push_back(ecs->threshold); // transpose data - std::vector> transdata(2, std::vector(ecs->data.size())); + std::vector transdata(2, vector_fp(ecs->data.size())); for (size_t i = 0; i < ecs->data.size(); i++) { for (size_t j = 0; j < 2; j++) { transdata[j][i] = ecs->data[i][j]; @@ -245,8 +247,8 @@ void Electron::calculateElasticCrossSection() m_kinds[ke] = "ELASTIC"; for (size_t k : m_kInelastic) { if (m_targets[k] == m_targets[ke]) { - vector_fp x = m_crossSections[k][0]; - vector_fp y = m_crossSections[k][1]; + vector_fp& x = m_crossSections[k][0]; + vector_fp& y = m_crossSections[k][1]; for (size_t i = 0; i < m_crossSections[ke][0].size(); i++) { m_crossSections[ke][1][i] -= linearInterp(m_crossSections[ke][0][i], x, y); } @@ -263,23 +265,16 @@ void Electron::calculateElasticCrossSection() void Electron::setupGrid(size_t n, const double* eps) { m_points = n-1; - m_gridC.resize(n-1); - m_gridB.resize(n); + m_gridCenter.resize(n-1); + m_gridEdge.resize(n); m_f0.resize(m_points); - m_gridB[n-1] = eps[n-1]; + m_gridEdge[n-1] = eps[n-1]; for (size_t i = 0; i < m_points; i++) { - m_gridB[i] = eps[i]; - m_gridC[i] = 0.5 * (eps[i] + eps[i+1]); + m_gridEdge[i] = eps[i]; + m_gridCenter[i] = 0.5 * (eps[i] + eps[i+1]); } setGridCache(); m_f0_ok = false; } -void Electron::checkSpeciesArraySize(size_t k) const -{ - if (m_thermo->nSpecies() > k) { - throw ArraySizeError("checkSpeciesArraySize", k, m_thermo->nSpecies()); - } -} - } From b8929f5c42140bbc722edd1a8b024180c6866b31 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Wed, 25 Dec 2019 09:25:44 -0500 Subject: [PATCH 060/139] [electron] update WeakIonGasElectron --- include/cantera/electron/WeakIonGasElectron.h | 142 +++++++++--- src/electron/WeakIonGasElectron.cpp | 204 ++++++++---------- 2 files changed, 205 insertions(+), 141 deletions(-) diff --git a/include/cantera/electron/WeakIonGasElectron.h b/include/cantera/electron/WeakIonGasElectron.h index 1317abcc48a..9c78fbc495f 100644 --- a/include/cantera/electron/WeakIonGasElectron.h +++ b/include/cantera/electron/WeakIonGasElectron.h @@ -12,15 +12,59 @@ #include "cantera/electron/Electron.h" #include -typedef Eigen::SparseMatrix SpMat; -typedef Eigen::Triplet T; - namespace Cantera { +typedef Eigen::SparseMatrix SparseMat; + /** * This class calculates the properties of electron in a weakly ionized gas. * Only electron-neutral collisions are considered for calculating the - * electron energy distribution function (EEDF). + * electron energy distribution function (EEDF). Equation of EEDF becomes, + * \f[ + * \frac{d}{d \epsilon}\left(\tilde{W} F_0 - \tilde{D} \frac{d F_0}{d \epsilon}\right) + * = \tilde{S} + * \f] + * where + * \f[ + * \tilde{W} = -\gamma\epsilon^2\sigma_{\epsilon}, + * \f] + * \f[ + * \tilde{D} = \frac{\gamma}{3} \left(\frac{E}{N} \right)^2 \frac{\epsilon}{\tilde{\sigma}_m} + + * \frac{\gamma k_B T}{e} \epsilon^2 \sigma_{\epsilon}, + * \f] + * \f[ + * \tilde{S} = \sum_{k=inelastic} \tilde{C}_{0,k} + G + * \f] + * where \f$ \gamma = (\frac{2 e}{m})^{1/2} \f$, \f$ \epsilon \f$ is the electron energy, + * \f$ \sigma_{\epsilon} \f$ is the total elastic collision cross section, + * \f$ E \f$ is electric field strength, \f$ N \f$ is gas number density, + * \f$ \tilde{\sigma}_m \f$ is the effective total momentum-transfer cross section, + * \f$ k_B \f$ is Boltzmann constant, \f$ e \f$ is the elementary charge, + * \f$ \tilde{C}_{0,k} \f$ represents the rate of change in EEDF due to collisions, + * and \f$ F_0 \f$ is the normalized EEDF. + * + * The collision terms are, + * \f[ + * \tilde{C}_{0,k=elastic} = \gamma X_k \frac{2 m}{M_k} \frac{d}{d \epsilon} + * \left[\epsilon^2 \sigma_k \left( F_0 + \frac{k_B T}{e} \frac{d F_0}{\epsilon} \right) \right], + * \f] + * \f[ + * \tilde{C}_{0,k=inelastic} = -\gamma X_k \epsilon \sigma_k F_0 + * \big|^{\epsilon=\epsilon}_{\epsilon=\epsilon + u_k} + * \f] + * \f[ + * \tilde{C}_{0,k=ionization} = -\gamma X_k \epsilon \sigma_k F_0 + * \big|^{\epsilon=\epsilon}_{\epsilon=2\epsilon + u_k} + * \f] + * \f[ + * \tilde{C}_{0,k=attachment} = -\gamma X_k \epsilon \sigma_k F_0 + * \f] + * For exponential temporal growth model, + * \f[ + * G = \left[ \int_0^\infty \left(\sum_{k=ionization} X_k \sigma_k - \sum_{k=attachment} X_k \sigma_k \right) + * \epsilon F_0 d \epsilon \right] \epsilon^{1/2} F_0 + * \f] + * where \f$ X_k \f$ is the mole fraction of the target species, and \f$ \sigma_k \f$ is the cross section. * * Reference: * [1] G. J. M. Hagelaar and L. C. Pitchford @@ -56,7 +100,7 @@ class WeakIonGasElectron: public Electron double realMobility(); //! electron temperature - //! If the reduced electric field is set, electron tempeature is calculated + //! If the reduced electric field is set, electron temperature is calculated //! from EEDF. virtual double electronTemperature(); @@ -67,52 +111,92 @@ class WeakIonGasElectron: public Electron } protected: - //! Calculate distribution function + //! Calculate distribution function by solving Boltzmann equation + //! with two-term approximate method. void calculateDistributionFunction(); - //! Calculate total cross section + //! Calculate total cross section. The total cross section is defined as the summation + //! of weighted (by mole fractions) cross sections of all coliision processes. void calculateTotalCrossSection(); - //! Calculate total elastic cross section + //! Calculate total elastic cross section \f$ \sigma_{\epsilon} \f$. + /** + * \f[ + * \sigma_{\epsilon} = \sum_{k=elastic} \frac{2 m}{M_k} X_k \sigma_k, + * \f] + * where \f$ m \f$ is the mass of electron, \f$ M_k \f$ is the mass of the target species, + * \f$ X_k \f$ is the mole fraction of the target species, \f$ \sigma_k \f$ is the cross section. + */ void calculateTotalElasticCrossSection(); - //! The integral in [a, b] of x * u(x) exp[g * (x0 - x)] + //! The integral in [a, b] of \f$x u(x) \exp[g (x_0 - x)]\f$ //! assuming that u is linear with u(a) = u0 and u(b) = u1 double integralPQ(double a, double b, double u0, double u1, double g, double x0); - //! Norm of electron energy distribution function - double norm(Eigen::VectorXd f); - //! Vector g is used by matrix_PQ. - vector_fp vector_g(Eigen::VectorXd f0); - - //! The matrix of scattering-out and scattering-in - SpMat matrix_PQ(vector_fp g, size_t k); - - //! The matrix of scattering-out - SpMat matrix_P(vector_fp g, size_t k); + /** + * \f[ + * g_i = \frac{1}{\epsilon_{i+1} - \epsilon_{i-1}} \ln(\frac{F_{0, i+1}}{F_{0, i-1}}) + * \f] + */ + vector_fp vector_g(Eigen::VectorXd& f0); + + //! The matrix of scattering-out. + /** + * \f[ + * P_i = \sum_{k=inelastic} \gamma X_k \int_{\epsilon_i - 1/2}^{\epsilon_i + 1/2} + * \epsilon \sigma_k exp[(\epsilon_i - \epsilon)g_i] d \epsilon + * \f] + */ + SparseMat matrix_P(vector_fp& g, size_t k); //! The matrix of scattering-in - SpMat matrix_Q(vector_fp g, size_t k); - - //! matrix A represents equation (45) of ref. [1] - SpMat matrix_A(Eigen::VectorXd f0); + /** + * \f[ + * Q_{i,j} = \sum_{k=inelastic} \gamma X_k \int_{\epsilon_1}^{\epsilon_2} + * \epsilon \sigma_k exp[(\epsilon_j - \epsilon)g_j] d \epsilon + * \f] + */ + //! where the interval \f$[\epsilon_1, \epsilon_2]\f$ is the overlap of cell j, + //! and cell i shifted by the threshold energy u_k: + /** + * \f[ + * \epsilon_1 = \min(\max(\epsilon_{i-1/2}+u_k, \epsilon_{j-1/2}),\epsilon_{j+1/2}), + * \f] + * \f[ + * \epsilon_2 = \min(\max(\epsilon_{i+1/2}+u_k, \epsilon_{j-1/2}),\epsilon_{j+1/2}) + * \f] + */ + SparseMat matrix_Q(vector_fp& g, size_t k); + + //! Matrix A (Ax = b) of the equation of EEDF, which is discretized by the exponential scheme + //! of Scharfetter and Gummel, + /** + * \f[ + * \left[ \tilde{W} F_0 - \tilde{D} \frac{d F_0}{\epsilon} \right]_{i+1/2} = + * \frac{\tilde{W}_{i+1/2} F_{0,i}}{1 - \exp[-z_{i+1/2}]} + + * \frac{\tilde{W}_{i+1/2} F_{0,i+1}}{1 - \exp[z_{i+1/2}]} + * \f] + * where \f$ z_{i+1/2} = \tilde{w}_{i+1/2} / \tilde{D}_{i+1/2} \f$ (Peclet number). + */ + SparseMat matrix_A(Eigen::VectorXd& f0); //! An iteration of solving electron energy distribution function - Eigen::VectorXd iterate(Eigen::VectorXd f0, double delta = 1e14); + Eigen::VectorXd iterate(Eigen::VectorXd& f0, double delta = 1e14); //! Iterate until convergence and obtain EEDF - Eigen::VectorXd converge(Eigen::VectorXd f0); + Eigen::VectorXd converge(Eigen::VectorXd& f0); //! Reduced net production frequency. Equation (10) of ref. [1] //! divided by N. //! @param f0 EEDF //! @param chem_rate Chemionization rate. This is an optional source of //! electron. - double netProductionFreq(Eigen::VectorXd f0); + double netProductionFreq(Eigen::VectorXd& f0); - //! electron temperature. For internal use only. + //! electron temperature. For internal use only. This function is used to evaluate EEDF by + //! comparing the resulting electron temeprature to gas temperature. double electronTemperature(Eigen::VectorXd f0); //! bi-Maxwellian Boltzmann factor. Assume that the excitation @@ -120,11 +204,11 @@ class WeakIonGasElectron: public Electron double biMaxwellFraction(size_t k); //! Total electron cross section on the cell center of energy grid - vector_fp m_totalCrossSectionC; + vector_fp m_totalCrossSectionCenter; //! Total electron cross section on the cell boundary (i-1/2) of //! energy grid - vector_fp m_totalCrossSectionB; + vector_fp m_totalCrossSectionEdge; //! vector of total elastic cross section weighted with mass ratio vector_fp m_sigmaElastic; diff --git a/src/electron/WeakIonGasElectron.cpp b/src/electron/WeakIonGasElectron.cpp index 3b29df079e4..0c61115d12d 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/electron/WeakIonGasElectron.cpp @@ -9,6 +9,18 @@ namespace Cantera { +typedef Eigen::Triplet Triplet; + +//! Calculate the norm of EEDF +double norm(const Eigen::VectorXd& f, const vector_fp& grid) +{ + vector_fp p(f.size()); + for (int i = 0; i < f.size(); i++) { + p[i] = f(i) * pow(grid[i], 0.5); + } + return simpsonQuadrature(grid, p); +} + WeakIonGasElectron::WeakIonGasElectron() : m_chemionScatRate(0.0) { @@ -16,18 +28,16 @@ WeakIonGasElectron::WeakIonGasElectron() void WeakIonGasElectron::calculateTotalCrossSection() { - m_totalCrossSectionC.clear(); - m_totalCrossSectionC.resize(m_points, 0.0); - m_totalCrossSectionB.clear(); - m_totalCrossSectionB.resize(m_points + 1, 0.0); + m_totalCrossSectionCenter.assign(m_points, 0.0); + m_totalCrossSectionEdge.assign(m_points + 1, 0.0); for (size_t k = 0; k < m_ncs; k++) { - vector_fp x = m_crossSections[k][0]; - vector_fp y = m_crossSections[k][1]; + vector_fp& x = m_crossSections[k][0]; + vector_fp& y = m_crossSections[k][1]; for (size_t i = 0; i < m_points; i++) { - m_totalCrossSectionC[i] += m_moleFractions[k] * linearInterp(m_gridC[i], x, y); + m_totalCrossSectionCenter[i] += m_moleFractions[k] * linearInterp(m_gridCenter[i], x, y); } for (size_t i = 0; i < m_points + 1; i++) { - m_totalCrossSectionB[i] += m_moleFractions[k] * linearInterp(m_gridB[i], x, y); + m_totalCrossSectionEdge[i] += m_moleFractions[k] * linearInterp(m_gridEdge[i], x, y); } } } @@ -37,11 +47,12 @@ void WeakIonGasElectron::calculateTotalElasticCrossSection() m_sigmaElastic.clear(); m_sigmaElastic.resize(m_points, 0.0); for (size_t k : m_kElastic) { - vector_fp x = m_crossSections[k][0]; - vector_fp y = m_crossSections[k][1]; + vector_fp& x = m_crossSections[k][0]; + vector_fp& y = m_crossSections[k][1]; for (size_t i = 0; i < m_points; i++) { - m_sigmaElastic[i] += 2.0 * m_massRatios[k] * m_moleFractions[k] * - linearInterp(m_gridB[i], x, y); + double mass_ratio = ElectronMass / (Dalton * m_thermo->molecularWeight(m_kTargets[k])); + m_sigmaElastic[i] += 2.0 * mass_ratio * m_moleFractions[k] * + linearInterp(m_gridEdge[i], x, y); } } } @@ -51,7 +62,7 @@ void WeakIonGasElectron::calculateDistributionFunction() // check if T or C is changed update_T(); update_C(); - if (m_f0_ok == true) { + if (m_f0_ok) { return; } @@ -65,31 +76,24 @@ void WeakIonGasElectron::calculateDistributionFunction() for (size_t j = 0; j < m_points; j++) { m_f0(j) = 2.0 * pow(1.0/Pi, 0.5) * pow(kT, -3./2.) * - std::exp(-m_gridC[j]/kT); + std::exp(-m_gridCenter[j]/kT); } if (m_E != 0.0) { m_f0 = converge(m_f0); double Te = electronTemperature(m_f0); + // Evaluate the EEDF by comparing electron temperature to gas temperature, + // and replace the EEDF with a Maxwellian distribution at gas temperature. if (Te < m_thermo->temperature()) { for (size_t j = 0; j < m_points; j++) { m_f0(j) = 2.0 * pow(1.0/Pi, 0.5) * pow(m_kT, -3./2.) * - std::exp(-m_gridC[j]/m_kT); + std::exp(-m_gridCenter[j]/m_kT); } } } m_f0_ok = true; } -double WeakIonGasElectron::norm(Eigen::VectorXd f) -{ - vector_fp p(f.size()); - for (int i = 0; i < f.size(); i++) { - p[i] = f(i) * pow(m_gridC[i], 0.5); - } - return simpsonQuadrature(m_gridC, p); -} - double WeakIonGasElectron::integralPQ(double a, double b, double u0, double u1, double g, double x0) { @@ -117,60 +121,39 @@ double WeakIonGasElectron::integralPQ(double a, double b, double u0, double u1, return c0 * A1 + c1 * A2; } -vector_fp WeakIonGasElectron::vector_g(Eigen::VectorXd f0) +vector_fp WeakIonGasElectron::vector_g(Eigen::VectorXd& f0) { vector_fp g(m_points, 0.0); - g[0] = std::log(f0(1)/f0(0)) / (m_gridC[1] - m_gridC[0]); + g[0] = std::log(f0(1)/f0(0)) / (m_gridCenter[1] - m_gridCenter[0]); double N = m_points - 1; - g[N] = std::log(f0(N)/f0(N-1)) / (m_gridC[N] - m_gridC[N-1]); + g[N] = std::log(f0(N)/f0(N-1)) / (m_gridCenter[N] - m_gridCenter[N-1]); for (size_t i = 1; i < m_points - 1; i++) { - g[i] = std::log(f0(i+1)/f0(i-1)) / (m_gridC[i+1] - m_gridC[i-1]); + g[i] = std::log(f0(i+1)/f0(i-1)) / (m_gridCenter[i+1] - m_gridCenter[i-1]); } return g; } -SpMat WeakIonGasElectron::matrix_PQ(vector_fp g, size_t k) -{ - std::vector tripletList; - for (size_t n = 0; n < m_eps[k].size(); n++) { - double eps_a = m_eps[k][n][0]; - double eps_b = m_eps[k][n][1]; - double sigma_a = m_sigma[k][n][0]; - double sigma_b = m_sigma[k][n][1]; - double i = m_i[k][n]; - double j = m_j[k][n]; - double r = integralPQ(eps_a, eps_b, sigma_a, sigma_b, g[j], m_gridC[j]); - double q = m_inFactor[k] * m_gamma * m_moleFractions[k] * r; - double p = - m_gamma * m_moleFractions[k] * r; - tripletList.push_back(T(i, j, q)); - tripletList.push_back(T(j, j, p)); - } - SpMat PQ(m_points, m_points); - PQ.setFromTriplets(tripletList.begin(), tripletList.end()); - return PQ; -} - -SpMat WeakIonGasElectron::matrix_P(vector_fp g, size_t k) +SparseMat WeakIonGasElectron::matrix_P(vector_fp& g, size_t k) { - std::vector tripletList; + std::vector tripletList; for (size_t n = 0; n < m_eps[k].size(); n++) { double eps_a = m_eps[k][n][0]; double eps_b = m_eps[k][n][1]; double sigma_a = m_sigma[k][n][0]; double sigma_b = m_sigma[k][n][1]; double j = m_j[k][n]; - double r = integralPQ(eps_a, eps_b, sigma_a, sigma_b, g[j], m_gridC[j]); + double r = integralPQ(eps_a, eps_b, sigma_a, sigma_b, g[j], m_gridCenter[j]); double p = m_gamma * r; - tripletList.push_back(T(j, j, p)); + tripletList.push_back(Triplet(j, j, p)); } - SpMat P(m_points, m_points); + SparseMat P(m_points, m_points); P.setFromTriplets(tripletList.begin(), tripletList.end()); return P; } -SpMat WeakIonGasElectron::matrix_Q(vector_fp g, size_t k) +SparseMat WeakIonGasElectron::matrix_Q(vector_fp& g, size_t k) { - std::vector tripletList; + std::vector tripletList; for (size_t n = 0; n < m_eps[k].size(); n++) { double eps_a = m_eps[k][n][0]; double eps_b = m_eps[k][n][1]; @@ -178,16 +161,16 @@ SpMat WeakIonGasElectron::matrix_Q(vector_fp g, size_t k) double sigma_b = m_sigma[k][n][1]; double i = m_i[k][n]; double j = m_j[k][n]; - double r = integralPQ(eps_a, eps_b, sigma_a, sigma_b, g[j], m_gridC[j]); + double r = integralPQ(eps_a, eps_b, sigma_a, sigma_b, g[j], m_gridCenter[j]); double q = m_inFactor[k] * m_gamma * r; - tripletList.push_back(T(i, j, q)); + tripletList.push_back(Triplet(i, j, q)); } - SpMat Q(m_points, m_points); + SparseMat Q(m_points, m_points); Q.setFromTriplets(tripletList.begin(), tripletList.end()); return Q; } -SpMat WeakIonGasElectron::matrix_A(Eigen::VectorXd f0) +SparseMat WeakIonGasElectron::matrix_A(Eigen::VectorXd& f0) { vector_fp a0(m_points + 1); vector_fp a1(m_points + 1); @@ -199,61 +182,61 @@ SpMat WeakIonGasElectron::matrix_A(Eigen::VectorXd f0) a0[N+1] = NAN; a1[N+1] = NAN; for (size_t j = 1; j < m_points; j++) { - double sigma_tilde = m_totalCrossSectionB[j] + nu / pow(m_gridB[j], 0.5) / m_gamma; + double sigma_tilde = m_totalCrossSectionEdge[j] + nu / pow(m_gridEdge[j], 0.5) / m_gamma; double omega = 2 * Pi * m_F; - double q = omega / (m_N * m_gamma * pow(m_gridB[j], 0.5)); - double W = -m_gamma * m_gridB[j] * m_gridB[j] * m_sigmaElastic[j]; + double q = omega / (m_N * m_gamma * pow(m_gridEdge[j], 0.5)); + double W = -m_gamma * m_gridEdge[j] * m_gridEdge[j] * m_sigmaElastic[j]; double F = sigma_tilde * sigma_tilde / (sigma_tilde * sigma_tilde + q * q); - double DA = m_gamma / 3.0 * pow(m_E / m_N, 2.0) * m_gridB[j]; - double DB = m_gamma * m_kT * m_gridB[j] * m_gridB[j] * m_sigmaElastic[j]; + double DA = m_gamma / 3.0 * pow(m_E / m_N, 2.0) * m_gridEdge[j]; + double DB = m_gamma * m_kT * m_gridEdge[j] * m_gridEdge[j] * m_sigmaElastic[j]; double D = DA / sigma_tilde * F + DB; - double z = W * (m_gridC[j] - m_gridC[j-1]) / D; + double z = W * (m_gridCenter[j] - m_gridCenter[j-1]) / D; a0[j] = W / (1 - std::exp(-z)); a1[j] = W / (1 - std::exp(z)); } - std::vector tripletList; + std::vector tripletList; // center diagonal // zero flux b.c. at energy = 0 - tripletList.push_back(T(0, 0, a0[1])); + tripletList.push_back(Triplet(0, 0, a0[1])); for (size_t j = 1; j < m_points - 1; j++) { - tripletList.push_back(T(j, j, a0[j+1] - a1[j])); + tripletList.push_back(Triplet(j, j, a0[j+1] - a1[j])); } // upper diagonal for (size_t j = 0; j < m_points - 1; j++) { - tripletList.push_back(T(j, j+1, a1[j+1])); + tripletList.push_back(Triplet(j, j+1, a1[j+1])); } // lower diagonal for (size_t j = 1; j < m_points; j++) { - tripletList.push_back(T(j, j-1, -a0[j])); + tripletList.push_back(Triplet(j, j-1, -a0[j])); } // zero flux b.c. - tripletList.push_back(T(N, N, -a1[N])); + tripletList.push_back(Triplet(N, N, -a1[N])); - SpMat A(m_points, m_points); + SparseMat A(m_points, m_points); A.setFromTriplets(tripletList.begin(), tripletList.end()); //plus G - SpMat G(m_points, m_points); + SparseMat G(m_points, m_points); for (size_t i = 0; i < m_points; i++) { - G.insert(i,i) = 2.0 / 3.0 * (pow(m_gridB[i+1], 1.5) - pow(m_gridB[i], 1.5)) * nu; + G.insert(i,i) = 2.0 / 3.0 * (pow(m_gridEdge[i+1], 1.5) - pow(m_gridEdge[i], 1.5)) * nu; } return A + G; } -Eigen::VectorXd WeakIonGasElectron::iterate(Eigen::VectorXd f0, double delta) +Eigen::VectorXd WeakIonGasElectron::iterate(Eigen::VectorXd& f0, double delta) { - SpMat PQ(m_points, m_points); + SparseMat PQ(m_points, m_points); vector_fp g = vector_g(f0); for (size_t k : m_kInelastic) { - PQ += matrix_PQ(g, k); + PQ += (matrix_Q(g, k) - matrix_P(g, k)) * m_moleFractions[k]; } - SpMat A = matrix_A(f0); - SpMat I(m_points, m_points); + SparseMat A = matrix_A(f0); + SparseMat I(m_points, m_points); for (size_t i = 0; i < m_points; i++) { I.insert(i,i) = 1.0; } @@ -265,14 +248,14 @@ Eigen::VectorXd WeakIonGasElectron::iterate(Eigen::VectorXd f0, double delta) f0(0) += m_chemionScatRate; // solve f0 - Eigen::SparseLU solver(A); + Eigen::SparseLU solver(A); Eigen::VectorXd f1 = solver.solve(f0); - f1 *= 1.0 / norm(f1); + f1 *= 1.0 / norm(f1, m_gridCenter); return f1; } -Eigen::VectorXd WeakIonGasElectron::converge(Eigen::VectorXd f0) +Eigen::VectorXd WeakIonGasElectron::converge(Eigen::VectorXd& f0) { double err0 = 0.0; double err1 = 0.0; @@ -288,7 +271,7 @@ Eigen::VectorXd WeakIonGasElectron::converge(Eigen::VectorXd f0) for (size_t i = 0; i < m_points; i++) { Df0(i) = std::abs(f0(i) - f1(i)); } - err1 = norm(Df0); + err1 = norm(Df0, m_gridCenter); if (err1 < m_rtol) { return f1; } @@ -297,7 +280,7 @@ Eigen::VectorXd WeakIonGasElectron::converge(Eigen::VectorXd f0) throw CanteraError("WeakIonGasElectron::converge", "Convergence failed"); } -double WeakIonGasElectron::netProductionFreq(Eigen::VectorXd f0) +double WeakIonGasElectron::netProductionFreq(Eigen::VectorXd& f0) { double nu = m_chemionScatRate; vector_fp g = vector_g(f0); @@ -305,7 +288,7 @@ double WeakIonGasElectron::netProductionFreq(Eigen::VectorXd f0) for (size_t k = 0; k < m_ncs; k++) { if (m_kinds[k] == "IONIZATION" || m_kinds[k] == "ATTACHMENT") { - SpMat PQ = matrix_PQ(g, k); + SparseMat PQ = (matrix_Q(g, k) - matrix_P(g, k)) * m_moleFractions[k]; Eigen::VectorXd s = PQ * f0; for (size_t i = 0; i < m_points; i++) { nu += s[i]; @@ -321,12 +304,12 @@ double WeakIonGasElectron::electronDiffusivity() vector_fp y(m_points, 0.0); double nu = netProductionFreq(m_f0); for (size_t i = 0; i < m_points; i++) { - if (m_gridC[i] != 0.0) { - y[i] = m_gridC[i] * m_f0(i) / - (m_totalCrossSectionC[i] + nu / m_gamma / pow(m_gridC[i], 0.5)); + if (m_gridCenter[i] != 0.0) { + y[i] = m_gridCenter[i] * m_f0(i) / + (m_totalCrossSectionCenter[i] + nu / m_gamma / pow(m_gridCenter[i], 0.5)); } } - return 1./3. * m_gamma * simpsonQuadrature(m_gridC, y) / m_N; + return 1./3. * m_gamma * simpsonQuadrature(m_gridCenter, y) / m_N; } double WeakIonGasElectron::electronMobility() @@ -336,13 +319,13 @@ double WeakIonGasElectron::electronMobility() vector_fp y(m_points + 1, 0.0); for (size_t i = 1; i < m_points; i++) { // calculate df0 at i-1/2 - double df0 = (m_f0(i) - m_f0(i-1)) / (m_gridC[i] - m_gridC[i-1]); - if (m_gridB[i] != 0.0) { - y[i] = m_gridB[i] * df0 / - (m_totalCrossSectionB[i] + nu / m_gamma / pow(m_gridB[i], 0.5)); + double df0 = (m_f0(i) - m_f0(i-1)) / (m_gridCenter[i] - m_gridCenter[i-1]); + if (m_gridEdge[i] != 0.0) { + y[i] = m_gridEdge[i] * df0 / + (m_totalCrossSectionEdge[i] + nu / m_gamma / pow(m_gridEdge[i], 0.5)); } } - return -1./3. * m_gamma * simpsonQuadrature(m_gridB, y) / m_N; + return -1./3. * m_gamma * simpsonQuadrature(m_gridEdge, y) / m_N; } double WeakIonGasElectron::realMobility() @@ -352,14 +335,14 @@ double WeakIonGasElectron::realMobility() vector_fp y(m_points + 1, 0.0); for (size_t i = 1; i < m_points; i++) { // calculate df0 at i-1/2 - double df0 = (m_f0(i) - m_f0(i-1)) / (m_gridC[i] - m_gridC[i-1]); - if (m_gridB[i] != 0.0) { - double Q = m_totalCrossSectionB[i] + nu / m_gamma / pow(m_gridB[i], 0.5); - double q = 2.0 * Pi * m_F / (m_N * m_gamma * pow(m_gridB[i], 0.5)); - y[i] = m_gridB[i] * Q / (Q * Q + q * q) * df0; + double df0 = (m_f0(i) - m_f0(i-1)) / (m_gridCenter[i] - m_gridCenter[i-1]); + if (m_gridEdge[i] != 0.0) { + double Q = m_totalCrossSectionEdge[i] + nu / m_gamma / pow(m_gridEdge[i], 0.5); + double q = 2.0 * Pi * m_F / (m_N * m_gamma * pow(m_gridEdge[i], 0.5)); + y[i] = m_gridEdge[i] * Q / (Q * Q + q * q) * df0; } } - return -1./3. * m_gamma * simpsonQuadrature(m_gridB, y) / m_N; + return -1./3. * m_gamma * simpsonQuadrature(m_gridEdge, y) / m_N; } double WeakIonGasElectron::powerGain() @@ -378,11 +361,11 @@ double WeakIonGasElectron::elasticPowerLoss() vector_fp y(m_points + 1, 0.0); for (size_t i = 1; i < m_points; i++) { // calculate df0 at i-1/2 - double df0 = (m_f0(i) - m_f0(i-1)) / (m_gridC[i] - m_gridC[i-1]); + double df0 = (m_f0(i) - m_f0(i-1)) / (m_gridCenter[i] - m_gridCenter[i-1]); double f0 = 0.5 * (m_f0(i-1) + m_f0(i)); - y[i] = m_sigmaElastic[i] * (m_gridB[i] * m_gridB[i] * f0 + m_kT * df0); + y[i] = m_sigmaElastic[i] * (m_gridEdge[i] * m_gridEdge[i] * f0 + m_kT * df0); } - sum += m_gamma * simpsonQuadrature(m_gridB, y); + sum += m_gamma * simpsonQuadrature(m_gridEdge, y); return sum * m_N; } @@ -397,10 +380,7 @@ double WeakIonGasElectron::totalCollisionFreq() double WeakIonGasElectron::biMaxwellFraction(size_t k) { - double y0 = 1.0; - double y1 = std::exp(-m_thresholds[k] / m_kT); - y0 *= 1.0 / (y0 + y1); - return y0; + return 1.0 / (1 + exp(-m_thresholds[k] / m_kT)); } double WeakIonGasElectron::inelasticPowerLoss() @@ -423,7 +403,7 @@ double WeakIonGasElectron::rateCoefficient(size_t k) { calculateDistributionFunction(); vector_fp g = vector_g(m_f0); - SpMat P = matrix_P(g, k); + SparseMat P = matrix_P(g, k); Eigen::VectorXd s = P * m_f0; double sum = 0.0; for (size_t i = 0; i < m_points; i++) { @@ -436,7 +416,7 @@ double WeakIonGasElectron::reverseRateCoefficient(size_t k) { calculateDistributionFunction(); vector_fp g = vector_g(m_f0); - SpMat Q = matrix_Q(g, k); + SparseMat Q = matrix_Q(g, k); Eigen::VectorXd s = Q * m_f0; double sum = 0.0; for (size_t i = 0; i < m_points; i++) { @@ -450,7 +430,7 @@ double WeakIonGasElectron::meanElectronEnergy() calculateDistributionFunction(); double sum = 0; for (size_t i = 0; i < m_points - 1; i++) { - sum += (pow(m_gridB[i+1], 2.5) - pow(m_gridB[i], 2.5)) * m_f0(i); + sum += (pow(m_gridEdge[i+1], 2.5) - pow(m_gridEdge[i], 2.5)) * m_f0(i); } return 0.4 * sum; } @@ -469,7 +449,7 @@ double WeakIonGasElectron::electronTemperature(Eigen::VectorXd f0) { double sum = 0; for (size_t i = 0; i < m_points - 1; i++) { - sum += (pow(m_gridB[i+1], 2.5) - pow(m_gridB[i], 2.5)) * f0(i); + sum += (pow(m_gridEdge[i+1], 2.5) - pow(m_gridEdge[i], 2.5)) * f0(i); } return 2./3. * 0.4 * sum / Boltzmann * ElectronCharge; } From 7439c65c8598759318e66627ed4043daa3a00278 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 28 Dec 2019 19:39:06 -0500 Subject: [PATCH 061/139] [test-python-electron] update --- interfaces/cython/cantera/test/test_electron.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interfaces/cython/cantera/test/test_electron.py b/interfaces/cython/cantera/test/test_electron.py index 4aa2812346f..e4b5461fa2a 100644 --- a/interfaces/cython/cantera/test/test_electron.py +++ b/interfaces/cython/cantera/test/test_electron.py @@ -7,7 +7,7 @@ class TestElectron(utilities.CanteraTest): def setUp(self): - self.gas = ct.Solution(infile='ch4_plasma.cti', efile='lxcat.yaml') + self.gas = ct.Plasma(infile='ch4_plasma.cti', efile='lxcat.yaml') def test_electron_properties(self): self.gas.TPX = 1000, ct.one_atm, 'O2:1.0, E:1e-10' @@ -21,7 +21,7 @@ def test_electron_properties(self): self.assertNear(self.gas.net_plasma_production_rates[24], 0.001877, 1e-3) self.assertNear(self.gas.electron_total_collision_frequency, 3.6957e11, 1e-3) self.assertNear(self.gas.electron_power_gain, 3.9811e9, 1e-3) - self.assertNear(self.gas.electron_elastic_power_loss, 2.8671e7, 1e-3) + self.assertNear(self.gas.electron_elastic_power_loss, 2.8744e7, 1e-3) self.assertNear(self.gas.mean_electron_energy, 1.9742, 1e-3) self.assertNear(self.gas.electric_field, 1e5, 1e-3) From 83ee54fae6eefab4dd8b368668c3c59adc0c0a0a Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 29 Dec 2019 08:18:25 -0500 Subject: [PATCH 062/139] [electron] update ElectronCrossSecrtion --- src/electron/ElectronCrossSection.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/electron/ElectronCrossSection.cpp b/src/electron/ElectronCrossSection.cpp index a0df64c5d68..27fb06bd3d1 100644 --- a/src/electron/ElectronCrossSection.cpp +++ b/src/electron/ElectronCrossSection.cpp @@ -12,8 +12,7 @@ namespace Cantera { ElectronCrossSection::ElectronCrossSection() - : product("") - , mass_ratio(Undef) + : mass_ratio(Undef) , threshold(0.0) { } @@ -25,10 +24,12 @@ ElectronCrossSection::~ElectronCrossSection() void ElectronCrossSection::validate() { if (kind == "EFFECTIVE") { - if (data[0][0] != 0.0) { - throw CanteraError("ElectronCrossSection::validate", - "Invalid energy value of type '{}' for '{}'. " - "Energy must starts at zero.", kind, target); + if (data.size() > 0 && data[0].size() > 0) { + if (data[0][0] != 0.0) { + throw CanteraError("ElectronCrossSection::validate", + "Invalid energy value of type '{}' for '{}'. " + "Energy must starts at zero.", kind, target); + } } if (mass_ratio >= 1.0 || mass_ratio < 0.0) { throw CanteraError("ElectronCrossSection::validate", @@ -58,7 +59,7 @@ unique_ptr newElectronCrossSection(const AnyMap& node) ecs->kind = node["kind"].asString(); ecs->target = node["target"].asString(); - ecs->data = node["data"].asVector>(); + ecs->data = node["data"].asVector(); if (ecs->kind == "EFFECTIVE" || ecs->kind == "ELASTIC") { ecs->mass_ratio = node["mass_ratio"].asDouble(); } else { From 45454a32fa312272e5ee5502b05f4090418bd587 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 29 Dec 2019 08:47:56 -0500 Subject: [PATCH 063/139] [numerics] update funcs.cpp --- src/numerics/funcs.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/numerics/funcs.cpp b/src/numerics/funcs.cpp index 1373fcf5197..7993d9ad27e 100644 --- a/src/numerics/funcs.cpp +++ b/src/numerics/funcs.cpp @@ -35,16 +35,14 @@ double simpsonQuadrature(const vector_fp& x, const vector_fp& y) "size of x is not equal to size of y"); } size_t N = x.size(); - vector_fp w(N, -1.0); size_t ns = (N - 1) / 2; size_t ms = (N - 1) % 2; - double sum = 0; + double sum = 0.0; for (size_t i = 0; i < ns; i++) { - vector_fp c; - c.resize(3); - vector_fp xs{x[2*i],x[2*i+1],x[2*i+2]}; - vector_fp ys{y[2*i],y[2*i+1],y[2*i+2]}; - polyfit(3, 2, xs.data(), ys.data(), w.data(), c.data()); + double c[3]; + double xs[3] = {x[2*i],x[2*i+1],x[2*i+2]}; + double ys[3] = {y[2*i],y[2*i+1],y[2*i+2]}; + polyfit(3, 2, xs, ys, nullptr, c); sum += c[0] * x[2*i+2] + c[1] * 0.5 * x[2*i+2] * x[2*i+2] + c[2] * 1./3. * x[2*i+2] * x[2*i+2] * x[2*i+2] - From a81c4a718d0ed82f48e9a03cacd19b739d5c279a Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 30 Dec 2019 03:18:47 -0500 Subject: [PATCH 064/139] [kinetics] update Kinetics GasKinetics BulkKinetics --- include/cantera/kinetics/BulkKinetics.h | 1 - include/cantera/kinetics/GasKinetics.h | 9 ++++++++- include/cantera/kinetics/Kinetics.h | 12 +++++++++--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/include/cantera/kinetics/BulkKinetics.h b/include/cantera/kinetics/BulkKinetics.h index 574b945e41b..17d490cc110 100644 --- a/include/cantera/kinetics/BulkKinetics.h +++ b/include/cantera/kinetics/BulkKinetics.h @@ -60,7 +60,6 @@ class BulkKinetics : public Kinetics bool m_ROP_ok; doublereal m_temp; - double m_temp_e; }; } diff --git a/include/cantera/kinetics/GasKinetics.h b/include/cantera/kinetics/GasKinetics.h index d6a500445c2..186c5471b06 100644 --- a/include/cantera/kinetics/GasKinetics.h +++ b/include/cantera/kinetics/GasKinetics.h @@ -67,11 +67,15 @@ class GasKinetics : public BulkKinetics //! reactions. virtual void update_rates_C(); - //! enable kinetics to use class Electron + //! enable kinetics to use class PlasmaElectron virtual void enableElectron(bool enable) { m_do_electron = enable; } + //! Set the value of electron temperature in Kelvin. The electron temperature is equal + //! to gas temperature by default, and can be set manually to a different temperature. + //! However, if m_do_electron is set to true, class PlasmaElectron is used to calculate + //! the value of electron temperature. virtual void setElectronTemperature(double Te) { m_Te_fix = Te; } @@ -115,6 +119,9 @@ class GasKinetics : public BulkKinetics vector_fp concm_falloff_values; //!@} + //! Electron temperature for electron-temperature reactions + double m_temp_e; + //! flag of enabling electrons bool m_do_electron; diff --git a/include/cantera/kinetics/Kinetics.h b/include/cantera/kinetics/Kinetics.h index cff34099185..6e700535b20 100644 --- a/include/cantera/kinetics/Kinetics.h +++ b/include/cantera/kinetics/Kinetics.h @@ -690,6 +690,8 @@ class Kinetics */ virtual void addPhase(thermo_t& thermo); + //! Add PlasmaElectron object for calculating electron temperature, and + //! reaction rate coefficients of plasma reactions. virtual void addElectron(Electron* electron); /** @@ -822,11 +824,15 @@ class Kinetics m_root = root; } - //! enable kinetics to use class Electron - virtual void enableElectron(bool enable) {} + //! enable kinetics to use class PlasmaElectron + virtual void enableElectron(bool enable) { + throw NotImplementedError("Kinetics::enableElectron"); + } //! set electron temperature - virtual void setElectronTemperature(double Te) {} + virtual void setElectronTemperature(double Te) { + throw NotImplementedError("Kinetics::setElectronTemperature"); + } protected: //! Cache for saved calculations within each Kinetics object. From b63aee08a2423fee0c2f3d59ac62311b0a71e3f5 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 30 Dec 2019 03:44:43 -0500 Subject: [PATCH 065/139] rename files electron->plasmaElectron --- include/cantera/cython/wrappers.h | 4 +- include/cantera/kinetics/Kinetics.h | 8 ++-- .../ElectronCrossSection.h | 0 .../Electron.h => plasma/PlasmaElectron.h} | 48 +++++++++---------- .../PlasmaElectronFactory.h} | 36 +++++++------- .../{electron => plasma}/WeakIonGasElectron.h | 4 +- include/cantera/transport/IonGasTransport.h | 4 +- include/cantera/transport/TransportBase.h | 4 +- interfaces/cython/cantera/_cantera.pxd | 32 ++++++------- interfaces/cython/cantera/_cantera.pyx | 2 +- interfaces/cython/cantera/base.pyx | 40 ++++++++-------- interfaces/cython/cantera/composite.py | 2 +- .../cantera/{electron.pyx => plasma.pyx} | 48 +++++++++---------- interfaces/cython/cantera/transport.pyx | 4 +- src/SConscript | 2 +- src/clib/ct.cpp | 4 +- src/electron/ElectronFactory.cpp | 47 ------------------ src/kinetics/Kinetics.cpp | 2 +- .../ElectronCrossSection.cpp | 0 .../PlasmaElectron.cpp} | 24 +++++----- src/plasma/PlasmaElectronFactory.cpp | 47 ++++++++++++++++++ .../WeakIonGasElectron.cpp | 4 +- src/transport/IonGasTransport.cpp | 2 +- 23 files changed, 184 insertions(+), 184 deletions(-) rename include/cantera/{electron => plasma}/ElectronCrossSection.h (100%) rename include/cantera/{electron/Electron.h => plasma/PlasmaElectron.h} (86%) rename include/cantera/{electron/ElectronFactory.h => plasma/PlasmaElectronFactory.h} (52%) rename include/cantera/{electron => plasma}/WeakIonGasElectron.h (98%) rename interfaces/cython/cantera/{electron.pyx => plasma.pyx} (81%) delete mode 100644 src/electron/ElectronFactory.cpp rename src/{electron => plasma}/ElectronCrossSection.cpp (100%) rename src/{electron/Electron.cpp => plasma/PlasmaElectron.cpp} (93%) create mode 100644 src/plasma/PlasmaElectronFactory.cpp rename src/{electron => plasma}/WeakIonGasElectron.cpp (99%) diff --git a/include/cantera/cython/wrappers.h b/include/cantera/cython/wrappers.h index a3800ff8d53..478ffccf970 100644 --- a/include/cantera/cython/wrappers.h +++ b/include/cantera/cython/wrappers.h @@ -5,7 +5,7 @@ #include "cantera/thermo/ThermoPhase.h" #include "cantera/transport/TransportBase.h" #include "cantera/kinetics/Kinetics.h" -#include "cantera/electron/Electron.h" +#include "cantera/plasma/PlasmaElectron.h" #include "Python.h" @@ -65,7 +65,7 @@ void CxxArray2D_set(Cantera::Array2D& array, size_t i, size_t j, double value) #define KIN_1D(FUNC_NAME) ARRAY_FUNC(kin, Kinetics, FUNC_NAME) #define TRANSPORT_1D(FUNC_NAME) ARRAY_FUNC(tran, Transport, FUNC_NAME) #define TRANSPORT_2D(FUNC_NAME) ARRAY_FUNC2(tran, Transport, FUNC_NAME) -#define ELECTRON_1D(FUNC_NAME) ARRAY_FUNC(elect, Electron, FUNC_NAME) +#define ELECTRON_1D(FUNC_NAME) ARRAY_FUNC(elect, PlasmaElectron, FUNC_NAME) THERMO_1D(getMassFractions) THERMO_1D(setMassFractions) diff --git a/include/cantera/kinetics/Kinetics.h b/include/cantera/kinetics/Kinetics.h index 6e700535b20..2da5ad3fee6 100644 --- a/include/cantera/kinetics/Kinetics.h +++ b/include/cantera/kinetics/Kinetics.h @@ -15,7 +15,7 @@ #include "StoichManager.h" #include "cantera/kinetics/Reaction.h" #include "cantera/base/global.h" -#include "cantera/electron/Electron.h" +#include "cantera/plasma/PlasmaElectron.h" namespace Cantera { @@ -692,7 +692,7 @@ class Kinetics //! Add PlasmaElectron object for calculating electron temperature, and //! reaction rate coefficients of plasma reactions. - virtual void addElectron(Electron* electron); + virtual void addPlasmaElectron(PlasmaElectron* electron); /** * Prepare the class for the addition of reactions, after all phases have @@ -908,8 +908,8 @@ class Kinetics */ std::vector m_thermo; - //! electron class - Electron* m_electron; + //! Plasmaelectron class + PlasmaElectron* m_electron; /** * m_start is a vector of integers specifying the beginning position for the diff --git a/include/cantera/electron/ElectronCrossSection.h b/include/cantera/plasma/ElectronCrossSection.h similarity index 100% rename from include/cantera/electron/ElectronCrossSection.h rename to include/cantera/plasma/ElectronCrossSection.h diff --git a/include/cantera/electron/Electron.h b/include/cantera/plasma/PlasmaElectron.h similarity index 86% rename from include/cantera/electron/Electron.h rename to include/cantera/plasma/PlasmaElectron.h index a023769248b..5d0c0ea5fbc 100644 --- a/include/cantera/electron/Electron.h +++ b/include/cantera/plasma/PlasmaElectron.h @@ -1,16 +1,16 @@ /** - * @file Electron.h - * Header file for class Electron. + * @file PlasmaElectron.h + * Header file for class PlasmaElectron. */ // This file is part of Cantera. See License.txt in the top-level directory or // at https://www.cantera.org/license.txt for license and copyright information. -#ifndef CT_ELECTRON_H -#define CT_ELECTRON_H +#ifndef CT_PLASMAELECTRON_H +#define CT_PLASMAELECTRON_H #include "cantera/thermo/ThermoPhase.h" -#include "cantera/electron/ElectronCrossSection.h" +#include "cantera/plasma/ElectronCrossSection.h" #include "cantera/base/ctexceptions.h" #include "cantera/base/ValueCache.h" #include "cantera/numerics/eigen_dense.h" @@ -27,20 +27,20 @@ namespace Cantera */ /*! - * Class Electron is the base class which manages the grid and grid cache, + * Class PlasmaElectron is the base class which manages the grid and grid cache, * cross-section data, and updating temperature and gas composition. * @ingroup electron */ -class Electron +class PlasmaElectron { public: - Electron(); + PlasmaElectron(); - virtual ~Electron(); + virtual ~PlasmaElectron(); // Electron objects are not copyable or assignable - Electron(const Electron&) = delete; - Electron& operator=(const Electron&) = delete; + PlasmaElectron(const PlasmaElectron&) = delete; + PlasmaElectron& operator=(const PlasmaElectron&) = delete; //! Add an electron cross section to this Electron. Returns `true` if the electron cross section was //! successfully added, or `false` if the electron cross section was ignored. @@ -67,54 +67,54 @@ class Electron //! electron diffusivity virtual double electronDiffusivity() { - throw NotImplementedError("Electron::electronDiffusivity"); + throw NotImplementedError("PlasmaElectron::electronDiffusivity"); } //! electron mobility virtual double electronMobility() { - throw NotImplementedError("Electron::electronMobility"); + throw NotImplementedError("PlasmaElectron::electronMobility"); } //! mean electron energy virtual double meanElectronEnergy() { - throw NotImplementedError("Electron::meanElectronEnergy"); + throw NotImplementedError("PlasmaElectron::meanElectronEnergy"); } virtual double powerGain() { - throw NotImplementedError("Electron::powerGain"); + throw NotImplementedError("PlasmaElectron::powerGain"); } //! elastic power loss virtual double elasticPowerLoss() { - throw NotImplementedError("Electron::elasticPowerLoss"); + throw NotImplementedError("PlasmaElectron::elasticPowerLoss"); } //! inelastic power loss virtual double inelasticPowerLoss() { - throw NotImplementedError("Electron::inelasticPowerLoss"); + throw NotImplementedError("PlasmaElectron::inelasticPowerLoss"); } //! total collision frequency virtual double totalCollisionFreq() { - throw NotImplementedError("Electron::totalCollisionFreq"); + throw NotImplementedError("PlasmaElectron::totalCollisionFreq"); } //! rate coefficient for the electron collision process. [m^3/s] virtual double rateCoefficient(size_t k) { - throw NotImplementedError("Electron::rateCoefficient"); + throw NotImplementedError("PlasmaElectron::rateCoefficient"); } //! reverse rate coefficient for the electron collision process. [m^3/s] virtual double reverseRateCoefficient(size_t k) { - throw NotImplementedError("Electron::reverseRateCoefficient"); + throw NotImplementedError("PlasmaElectron::reverseRateCoefficient"); } //! net plasma production rates virtual void getNetPlasmaProductionRates(double* wdot) { - throw NotImplementedError("Electron::getNetPlasmaProductionRates"); + throw NotImplementedError("PlasmaElectron::getNetPlasmaProductionRates"); } - //! initialize Electron. Need to be called after adding all cross sections. + //! initialize PlasmaElectron. Need to be called after adding all cross sections. void init(thermo_t* thermo); //! Reduced electric field @@ -210,13 +210,13 @@ class Electron //! Return electron temperature virtual double electronTemperature() { - throw NotImplementedError("Electron::electronTemperature"); + throw NotImplementedError("PlasmaElectron::electronTemperature"); } //! Set chemionization scattering-in rate //! Equal to the reaction rate divided by gas and electron number density virtual void setChemionScatRate(double rate) { - throw NotImplementedError("Electron::setChemionScatRate"); + throw NotImplementedError("PlasmaElectron::setChemionScatRate"); } protected: diff --git a/include/cantera/electron/ElectronFactory.h b/include/cantera/plasma/PlasmaElectronFactory.h similarity index 52% rename from include/cantera/electron/ElectronFactory.h rename to include/cantera/plasma/PlasmaElectronFactory.h index c2c79e45a97..95dfdaf5b38 100644 --- a/include/cantera/electron/ElectronFactory.h +++ b/include/cantera/plasma/PlasmaElectronFactory.h @@ -1,32 +1,32 @@ /** - * @file ElectronFactory.h - * Headers for the factory class that can create known Electron objects + * @file PlasmaElectronFactory.h + * Headers for the factory class that can create known PlasmaElectron objects */ // This file is part of Cantera. See License.txt in the top-level directory or // at https://www.cantera.org/license.txt for license and copyright information. -#ifndef ELECTRON_FACTORY_H -#define ELECTRON_FACTORY_H +#ifndef PLASMAELECTRON_FACTORY_H +#define PLASMAELECTRON_FACTORY_H -#include "cantera/electron/Electron.h" +#include "cantera/plasma/PlasmaElectron.h" #include "cantera/base/FactoryBase.h" namespace Cantera { -//! Factory class for electron data managers. +//! Factory class for plasmaelectron data managers. /*! - * This class keeps a list of the known Electron classes, and is + * This class keeps a list of the known PlasmaElectron classes, and is * used to create new instances of these classes. */ -class ElectronFactory : public Factory +class PlasmaElectronFactory : public Factory { public: //! Static function that creates a static instance of the factory. - static ElectronFactory* factory() { + static PlasmaElectronFactory* factory() { std::unique_lock lock(electron_mutex); if (!s_factory) { - s_factory = new ElectronFactory; + s_factory = new PlasmaElectronFactory; } return s_factory; } @@ -38,14 +38,14 @@ class ElectronFactory : public Factory s_factory = 0; } - virtual Electron* newElectron(const std::string& model); + virtual PlasmaElectron* newPlasmaElectron(const std::string& model); private: //! static member of a single instance - static ElectronFactory* s_factory; + static PlasmaElectronFactory* s_factory; //! Private constructors prevents usage - ElectronFactory(); + PlasmaElectronFactory(); //! Decl for locking mutex for thermo factory singleton static std::mutex electron_mutex; @@ -54,18 +54,18 @@ class ElectronFactory : public Factory //! Create a new electron manager instance. /*! * @param model String to look up the model against - * @returns a pointer to a new Electron instance matching the model string. + * @returns a pointer to a new PlasmaElectron instance matching the model string. * Returns NULL if something went wrong. Throws an exception * UnknownThermoPhaseModel if the string wasn't matched. */ -inline Electron* newElectron(const std::string& model) +inline PlasmaElectron* newPlasmaElectron(const std::string& model) { - return ElectronFactory::factory()->create(model); + return PlasmaElectronFactory::factory()->create(model); } -unique_ptr newElectron(const AnyMap& rootNode=AnyMap(), thermo_t* phase = 0); +unique_ptr newPlasmaElectron(const AnyMap& rootNode=AnyMap(), thermo_t* phase = 0); -void addElectronCrossSections(Electron& electron, const AnyValue& cross_section); +void addElectronCrossSections(PlasmaElectron& electron, const AnyValue& cross_section); } diff --git a/include/cantera/electron/WeakIonGasElectron.h b/include/cantera/plasma/WeakIonGasElectron.h similarity index 98% rename from include/cantera/electron/WeakIonGasElectron.h rename to include/cantera/plasma/WeakIonGasElectron.h index 9c78fbc495f..98a422dd990 100644 --- a/include/cantera/electron/WeakIonGasElectron.h +++ b/include/cantera/plasma/WeakIonGasElectron.h @@ -9,7 +9,7 @@ #ifndef CT_WEAKIONGASELECTRON_H #define CT_WEAKIONGASELECTRON_H -#include "cantera/electron/Electron.h" +#include "cantera/plasma/PlasmaElectron.h" #include namespace Cantera @@ -80,7 +80,7 @@ typedef Eigen::SparseMatrix SparseMat; * doi: https://doi.org/10.1051/0004-6361/201220465 * @ingroup electron */ -class WeakIonGasElectron: public Electron +class WeakIonGasElectron: public PlasmaElectron { public: WeakIonGasElectron(); diff --git a/include/cantera/transport/IonGasTransport.h b/include/cantera/transport/IonGasTransport.h index 2b6ae718b6f..46df7a70e4d 100644 --- a/include/cantera/transport/IonGasTransport.h +++ b/include/cantera/transport/IonGasTransport.h @@ -57,7 +57,7 @@ class IonGasTransport : public MixTransport virtual void init(thermo_t* thermo, int mode, int log_level); - virtual void initElectron(Electron* electron); + virtual void initElectron(PlasmaElectron* electron); //! Viscosity of the mixture (kg/m/s). //! Only Neutral species contribute to Viscosity. @@ -126,7 +126,7 @@ class IonGasTransport : public MixTransport vector_fp m_om11_O2; //! electron class - Electron* m_electron; + PlasmaElectron* m_electron; double m_electronMobility; diff --git a/include/cantera/transport/TransportBase.h b/include/cantera/transport/TransportBase.h index b0e988fffb6..377f204e1bf 100644 --- a/include/cantera/transport/TransportBase.h +++ b/include/cantera/transport/TransportBase.h @@ -20,7 +20,7 @@ #define CT_TRANSPORTBASE_H #include "cantera/thermo/ThermoPhase.h" -#include "cantera/electron/Electron.h" +#include "cantera/plasma/PlasmaElectron.h" namespace Cantera { @@ -661,7 +661,7 @@ class Transport } //! initialize the Electron object. This method is overloaded in IonGasTtransport. - virtual void initElectron(Electron* electron) {} + virtual void initElectron(PlasmaElectron* electron) {} virtual void enableElectron(bool enable) {} diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index d0ecf6f9c42..e8cf857ab6e 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -139,7 +139,7 @@ cdef extern from "cantera/base/Solution.h" namespace "Cantera": cdef shared_ptr[CxxSolution] CxxNewSolution "Cantera::Solution::create" () -cdef extern from "cantera/electron/ElectronCrossSection.h" namespace "Cantera": +cdef extern from "cantera/plasma/ElectronCrossSection.h" namespace "Cantera": cdef cppclass CxxElectronCrossSection "Cantera::ElectronCrossSection": CxxElectronCrossSection() CxxElectronCrossSection(string, string, double, vector[double]) @@ -153,9 +153,9 @@ cdef extern from "cantera/electron/ElectronCrossSection.h" namespace "Cantera": cdef shared_ptr[CxxElectronCrossSection] CxxNewElectronCrossSection "newElectronCrossSection" (CxxAnyMap&) except +translate_exception cdef vector[shared_ptr[CxxElectronCrossSection]] CxxGetElectronCrossSection "getElectronCrossSection" (CxxAnyValue&) except +translate_exception -cdef extern from "cantera/electron/Electron.h" namespace "Cantera": - cdef cppclass CxxElectron "Cantera::Electron": - CxxElectron() +cdef extern from "cantera/plasma/PlasmaElectron.h" namespace "Cantera": + cdef cppclass CxxPlasmaElectron "Cantera::PlasmaElectron": + CxxPlasmaElectron() #Properties double grid(size_t) @@ -472,7 +472,7 @@ cdef extern from "cantera/kinetics/Kinetics.h" namespace "Cantera": CxxThermoPhase& thermo(int) void addPhase(CxxThermoPhase&) except +translate_exception - void addElectron(CxxElectron*) except +translate_exception + void addPlasmaElectron(CxxPlasmaElectron*) except +translate_exception void init() except +translate_exception void skipUndeclaredThirdBodies(cbool) void addReaction(shared_ptr[CxxReaction]) except +translate_exception @@ -508,7 +508,7 @@ cdef extern from "cantera/transport/TransportBase.h" namespace "Cantera": double thermalConductivity() except +translate_exception double electricalConductivity() except +translate_exception void getSpeciesViscosities(double*) except +translate_exception - void initElectron(CxxElectron*) except +translate_exception + void initElectron(CxxPlasmaElectron*) except +translate_exception void enableElectron(cbool) except +translate_exception @@ -745,9 +745,9 @@ cdef extern from "cantera/thermo/ThermoFactory.h" namespace "Cantera": cdef shared_ptr[CxxThermoPhase] newPhase(CxxAnyMap&, CxxAnyMap&) except +translate_exception cdef CxxThermoPhase* newThermoPhase(string) except +translate_exception -cdef extern from "cantera/electron/ElectronFactory.h" namespace "Cantera": - cdef shared_ptr[CxxElectron] newElectron(CxxAnyMap&, CxxThermoPhase*) except +translate_exception - cdef CxxElectron* newElectron(string) except +translate_exception +cdef extern from "cantera/plasma/PlasmaElectronFactory.h" namespace "Cantera": + cdef shared_ptr[CxxPlasmaElectron] newPlasmaElectron(CxxAnyMap&, CxxThermoPhase*) except +translate_exception + cdef CxxPlasmaElectron* newPlasmaElectron(string) except +translate_exception cdef extern from "cantera/kinetics/KineticsFactory.h" namespace "Cantera": cdef CxxKinetics* newKineticsMgr(XML_Node&, vector[CxxThermoPhase*]) except +translate_exception @@ -1002,8 +1002,8 @@ cdef extern from "cantera/cython/wrappers.h": cdef void kin_getDestructionRates(CxxKinetics*, double*) except +translate_exception cdef void kin_getNetProductionRates(CxxKinetics*, double*) except +translate_exception - # Electron - cdef void elect_getNetPlasmaProductionRates(CxxElectron*, double*) except +translate_exception + # PlasmaElectron + cdef void elect_getNetPlasmaProductionRates(CxxPlasmaElectron*, double*) except +translate_exception # Transport properties cdef void tran_getMixDiffCoeffs(CxxTransport*, double*) except +translate_exception @@ -1021,7 +1021,7 @@ ctypedef void (*thermoMethod1d)(CxxThermoPhase*, double*) except +translate_exce ctypedef void (*transportMethod1d)(CxxTransport*, double*) except +translate_exception ctypedef void (*transportMethod2d)(CxxTransport*, size_t, double*) except +translate_exception ctypedef void (*kineticsMethod1d)(CxxKinetics*, double*) except +translate_exception -ctypedef void (*electronMethod1d)(CxxElectron*, double*) except +translate_exception +ctypedef void (*plasmaElectronMethod1d)(CxxPlasmaElectron*, double*) except +translate_exception # classes cdef class ElectronCrossSection: @@ -1056,8 +1056,8 @@ cdef class _SolutionBase: cdef CxxKinetics* kinetics cdef shared_ptr[CxxTransport] _transport cdef CxxTransport* transport - cdef shared_ptr[CxxElectron] _electron - cdef CxxElectron* electron + cdef shared_ptr[CxxPlasmaElectron] _plasmaElectron + cdef CxxPlasmaElectron* plasmaElectron cdef int thermo_basis cdef np.ndarray _selected_species cdef object parent @@ -1090,7 +1090,7 @@ cdef class Falloff: cdef class Kinetics(_SolutionBase): pass -cdef class Electron(_SolutionBase): +cdef class PlasmaElectron(_SolutionBase): pass cdef class InterfaceKinetics(Kinetics): @@ -1256,7 +1256,7 @@ cdef np.ndarray get_species_array(Kinetics kin, kineticsMethod1d method) cdef np.ndarray get_reaction_array(Kinetics kin, kineticsMethod1d method) cdef np.ndarray get_transport_1d(Transport tran, transportMethod1d method) cdef np.ndarray get_transport_2d(Transport tran, transportMethod2d method) -cdef np.ndarray get_electron_1d(Electron elect, electronMethod1d method) +cdef np.ndarray get_electron_1d(PlasmaElectron elect, plasmaElectronMethod1d method) cdef CxxIdealGasPhase* getIdealGasPhase(ThermoPhase phase) except * cdef wrapSpeciesThermo(shared_ptr[CxxSpeciesThermo] spthermo) cdef Reaction wrapReaction(shared_ptr[CxxReaction] reaction) diff --git a/interfaces/cython/cantera/_cantera.pyx b/interfaces/cython/cantera/_cantera.pyx index 836a91f7338..b10e34d1af8 100644 --- a/interfaces/cython/cantera/_cantera.pyx +++ b/interfaces/cython/cantera/_cantera.pyx @@ -19,7 +19,7 @@ include "thermo.pyx" include "reaction.pyx" include "kinetics.pyx" include "transport.pyx" -include "electron.pyx" +include "plasma.pyx" include "mixture.pyx" include "reactor.pyx" diff --git a/interfaces/cython/cantera/base.pyx b/interfaces/cython/cantera/base.pyx index 1cd680878a5..16b78d4b548 100644 --- a/interfaces/cython/cantera/base.pyx +++ b/interfaces/cython/cantera/base.pyx @@ -6,7 +6,7 @@ from collections import defaultdict as _defaultdict cdef class _SolutionBase: def __cinit__(self, infile='', name='', adjacent=(), origin=None, source=None, yaml=None, thermo=None, species=(), - kinetics=None, reactions=(), electron=None, + kinetics=None, reactions=(), plasma_electron=None, electron_cross_sections=(), efile=None, **kwargs): if 'phaseid' in kwargs: @@ -37,11 +37,11 @@ cdef class _SolutionBase: self.transport = other.transport self._base = other._base self._source = other._source - self.electron = other.electron + self.plasmaElectron = other.plasmaElectron self._thermo = other._thermo self._kinetics = other._kinetics self._transport = other._transport - self._electron = other._electron + self._plasmaElectron = other._plasmaElectron self.thermo_basis = other.thermo_basis self._selected_species = other._selected_species.copy() @@ -69,12 +69,12 @@ cdef class _SolutionBase: self.base.setThermo(self._thermo) self.base.setKinetics(self._kinetics) - # Initiate electron + # Initiate plasma if efile: self._init_efile(efile) if electron_cross_sections: - self._init_electron(electron, electron_cross_sections) + self._init_electron(plasma_electron, electron_cross_sections) self._selected_species = np.ndarray(0, dtype=np.uint64) @@ -235,32 +235,32 @@ cdef class _SolutionBase: def _init_efile(self, efile): """ - Instantiate a new Electron object via a yaml file. + Instantiate a new PlasmaElectron object via a yaml file. """ cdef CxxAnyMap root root = AnyMapFromYamlFile(stringify(efile)) - if isinstance(self, Electron): - self._electron = newElectron(root, self.thermo) - self.electron = self._electron.get() - self.kinetics.addElectron(self.electron) + if isinstance(self, PlasmaElectron): + self._plasmaElectron = newPlasmaElectron(root, self.thermo) + self.plasmaElectron = self._plasmaElectron.get() + self.kinetics.addPlasmaElectron(self.plasmaElectron) else: - self.electron = NULL + self.plasmaElectron = NULL - def _init_electron(self, electron, electron_cross_sections): + def _init_electron(self, plasma_electron, electron_cross_sections): """ - Instantiate a new Electron object. + Instantiate a new PlasmaElectron object. """ cdef ElectronCrossSection ecs - if isinstance(self, Electron): - self.electron = newElectron(stringify(electron)) - self._electron.reset(self.electron) + if isinstance(self, PlasmaElectron): + self.plasmaElectron = newPlasmaElectron(stringify(plasma_electron)) + self._plasmaElectron.reset(self.plasmaElectron) for ecs in electron_cross_sections: - self.electron.addElectronCrossSection(ecs._electron_cross_section) - self.electron.init(self.thermo) - self.kinetics.addElectron(self.electron) + self.plasmaElectron.addElectronCrossSection(ecs._electron_cross_section) + self.plasmaElectron.init(self.thermo) + self.kinetics.addPlasmaElectron(self.plasmaElectron) else: - self.electron = NULL + self.plasmaElectron = NULL def __getitem__(self, selection): copy = self.__class__(origin=self) diff --git a/interfaces/cython/cantera/composite.py b/interfaces/cython/cantera/composite.py index dbe1c3708b8..2eaf2b7646b 100644 --- a/interfaces/cython/cantera/composite.py +++ b/interfaces/cython/cantera/composite.py @@ -98,7 +98,7 @@ class Solution(ThermoPhase, Kinetics, Transport): __slots__ = () -class Plasma(ThermoPhase, Kinetics, Transport, Electron): +class Plasma(ThermoPhase, Kinetics, Transport, PlasmaElectron): __slots__ = () diff --git a/interfaces/cython/cantera/electron.pyx b/interfaces/cython/cantera/plasma.pyx similarity index 81% rename from interfaces/cython/cantera/electron.pyx rename to interfaces/cython/cantera/plasma.pyx index 1a78bb8c0cc..2b3d2f74011 100644 --- a/interfaces/cython/cantera/electron.pyx +++ b/interfaces/cython/cantera/plasma.pyx @@ -4,15 +4,15 @@ import warnings import weakref -cdef np.ndarray get_electron_1d(Electron elect, electronMethod1d method): +cdef np.ndarray get_electron_1d(PlasmaElectron elect, plasmaElectronMethod1d method): cdef np.ndarray[np.double_t, ndim=1] data = np.empty(elect.thermo.nSpecies()) - method(elect.electron, &data[0]) + method(elect.plasmaElectron, &data[0]) if elect._selected_species.size: return data[elect._selected_species] else: return data -cdef class Electron(_SolutionBase): +cdef class PlasmaElectron(_SolutionBase): """ This class is used to compute electron properties for a phase of matter. """ @@ -23,56 +23,56 @@ cdef class Electron(_SolutionBase): """ Set the grid of cell boundary of electron energy [eV]""" cdef np.ndarray[np.double_t, ndim=1] data = \ np.ascontiguousarray(grid, dtype=np.double) - self.electron.setupGrid(len(data), &data[0]) + self.plasmaElectron.setupGrid(len(data), &data[0]) property electron_temperature: """electron temperature""" def __get__(self): - return self.electron.electronTemperature() + return self.plasmaElectron.electronTemperature() property electron_mobility: """electron mobility [m^2/V/s)]""" def __get__(self): - return self.electron.electronMobility() + return self.plasmaElectron.electronMobility() property electron_diffusivity: """electron diffusivity [m^2/s]""" def __get__(self): - return self.electron.electronDiffusivity() + return self.plasmaElectron.electronDiffusivity() property electron_total_collision_frequency: """electron total collision frequency""" def __get__(self): - return self.electron.totalCollisionFreq() + return self.plasmaElectron.totalCollisionFreq() def electron_rate_coefficient(self, k): """rate coefficient of process k""" - return self.electron.rateCoefficient(k) + return self.plasmaElectron.rateCoefficient(k) def electron_reverse_rate_coefficient(self, k): """reverse rate coefficient of process k""" - return self.electron.reverseRateCoefficient(k) + return self.plasmaElectron.reverseRateCoefficient(k) property electron_power_gain: """ Electron power gain. [eV/s] """ def __get__(self): - return self.electron.powerGain() + return self.plasmaElectron.powerGain() property electron_elastic_power_loss: """ Electron elastic power loss. [eV/s] """ def __get__(self): - return self.electron.elasticPowerLoss() + return self.plasmaElectron.elasticPowerLoss() property electron_inelastic_power_loss: """ Electron inelastic power loss. [eV/s] """ def __get__(self): - return self.electron.inelasticPowerLoss() + return self.plasmaElectron.inelasticPowerLoss() property net_plasma_production_rates: """ @@ -84,43 +84,43 @@ cdef class Electron(_SolutionBase): def set_chemionization_scattering_rate(self, rate): """ Set chemionization scattering-in rate """ - self.electron.setChemionScatRate(rate) + self.plasmaElectron.setChemionScatRate(rate) def set_boltzmann_solver(self, maxn=100, rtol=1e-5, delta0=1e14, m=4.0, init_kTe=0.0, warn=True): """ Set boltzmann solver""" - self.electron.setBoltzmannSolver(maxn, rtol, delta0, m, init_kTe, warn) + self.plasmaElectron.setBoltzmannSolver(maxn, rtol, delta0, m, init_kTe, warn) property mean_electron_energy: """mean electron energy [eV]""" def __get__(self): - return self.electron.meanElectronEnergy() + return self.plasmaElectron.meanElectronEnergy() property electric_field: """reduced electric field strength [V-m2]""" def __get__(self): - return self.electron.electricField() + return self.plasmaElectron.electricField() def __set__(self, E): - self.electron.setElectricField(E) + self.plasmaElectron.setElectricField(E) property electric_field_freq: """electric field freq [Hz]""" def __get__(self): - return self.electron.electricFieldFreq() + return self.plasmaElectron.electricFieldFreq() def __set__(self, F): - self.electron.setElectricFieldFreq(F) + self.plasmaElectron.setElectricFieldFreq(F) def electron_collision_target(self, k): - return pystr(self.electron.target(k)) + return pystr(self.plasmaElectron.target(k)) def electron_collision_kind(self, k): - return pystr(self.electron.kind(k)) + return pystr(self.plasmaElectron.kind(k)) def electron_collision_product(self,k): - return pystr(self.electron.product(k)) + return pystr(self.plasmaElectron.product(k)) def electron_collision_threshold(self, k): - return self.electron.threshold(k) + return self.plasmaElectron.threshold(k) cdef class ElectronCrossSection: diff --git a/interfaces/cython/cantera/transport.pyx b/interfaces/cython/cantera/transport.pyx index 67095d950f9..4fa624f7595 100644 --- a/interfaces/cython/cantera/transport.pyx +++ b/interfaces/cython/cantera/transport.pyx @@ -144,8 +144,8 @@ cdef class Transport(_SolutionBase): model = 'None' self.transport = newTransportMgr(stringify(model), self.thermo) self._transport.reset(self.transport) - if self.electron != NULL: - self.transport.initElectron(self.electron) + if self.plasmaElectron != NULL: + self.transport.initElectron(self.plasmaElectron) super().__init__(*args, **kwargs) self.base.setTransport(self._transport) diff --git a/src/SConscript b/src/SConscript index 0a1498ebd6e..8333017d8d0 100644 --- a/src/SConscript +++ b/src/SConscript @@ -27,7 +27,7 @@ libs = [('base', ['cpp'], baseSetup), ('base', ['^application.cpp'], applicationSetup), ('base', ['^global.cpp'], globalSetup), ('thermo', ['cpp'], defaultSetup), - ('electron', ['cpp'], defaultSetup), + ('plasma', ['cpp'], defaultSetup), ('tpx', ['cpp'], defaultSetup), ('equil', ['cpp','c'], defaultSetup), ('numerics', ['cpp'], defaultSetup), diff --git a/src/clib/ct.cpp b/src/clib/ct.cpp index ab97d16c5c5..442a228cb44 100644 --- a/src/clib/ct.cpp +++ b/src/clib/ct.cpp @@ -17,7 +17,7 @@ // Cantera includes #include "cantera/kinetics/KineticsFactory.h" #include "cantera/transport/TransportFactory.h" -#include "cantera/electron/ElectronFactory.h" +#include "cantera/plasma/PlasmaElectronFactory.h" #include "cantera/base/ctml.h" #include "cantera/kinetics/importKinetics.h" #include "cantera/thermo/ThermoFactory.h" @@ -31,7 +31,7 @@ using namespace Cantera; typedef Cabinet ThermoCabinet; typedef Cabinet KineticsCabinet; typedef Cabinet TransportCabinet; -typedef Cabinet ElectronCabinet; +typedef Cabinet ElectronCabinet; typedef Cabinet XmlCabinet; template<> ThermoCabinet* ThermoCabinet::s_storage = 0; diff --git a/src/electron/ElectronFactory.cpp b/src/electron/ElectronFactory.cpp deleted file mode 100644 index 5f705662121..00000000000 --- a/src/electron/ElectronFactory.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/** - * @file ElectronFactory.cpp - * Definitions for the factory class that can create known Electron objects - */ - -// This file is part of Cantera. See License.txt in the top-level directory or -// at https://www.cantera.org/license.txt for license and copyright information. - -#include "cantera/electron/ElectronFactory.h" -#include "cantera/electron/Electron.h" -#include "cantera/electron/WeakIonGasElectron.h" - - -using namespace std; - -namespace Cantera -{ - -ElectronFactory* ElectronFactory::s_factory = 0; -std::mutex ElectronFactory::electron_mutex; - -ElectronFactory::ElectronFactory() -{ - reg("WeaklyIonizedGas", []() { return new WeakIonGasElectron(); }); -} - -Electron* ElectronFactory::newElectron(const std::string& model) -{ - return create(model); -} - -unique_ptr newElectron(const AnyMap& rootNode, thermo_t* phase) -{ - unique_ptr electron(newElectron(rootNode["electron"].asString())); - addElectronCrossSections(*electron, rootNode["cross_section"]); - electron->init(phase); - return electron; -} - -void addElectronCrossSections(Electron& electron, const AnyValue& cross_section) -{ - for (const auto& item : cross_section.asVector()) { - electron.addElectronCrossSection(newElectronCrossSection(item)); - } -} - -} diff --git a/src/kinetics/Kinetics.cpp b/src/kinetics/Kinetics.cpp index b5e0b0fd4f1..4c9d65a2521 100644 --- a/src/kinetics/Kinetics.cpp +++ b/src/kinetics/Kinetics.cpp @@ -462,7 +462,7 @@ void Kinetics::addPhase(thermo_t& thermo) resizeSpecies(); } -void Kinetics::addElectron(Electron* electron) +void Kinetics::addPlasmaElectron(PlasmaElectron* electron) { m_electron = electron; } diff --git a/src/electron/ElectronCrossSection.cpp b/src/plasma/ElectronCrossSection.cpp similarity index 100% rename from src/electron/ElectronCrossSection.cpp rename to src/plasma/ElectronCrossSection.cpp diff --git a/src/electron/Electron.cpp b/src/plasma/PlasmaElectron.cpp similarity index 93% rename from src/electron/Electron.cpp rename to src/plasma/PlasmaElectron.cpp index ff8544bc65f..b51bf647afb 100644 --- a/src/electron/Electron.cpp +++ b/src/plasma/PlasmaElectron.cpp @@ -1,7 +1,7 @@ // This file is part of Cantera. See License.txt in the top-level directory or // at https://www.cantera.org/license.txt for license and copyright information. -#include "cantera/electron/Electron.h" +#include "cantera/plasma/PlasmaElectron.h" #include "cantera/base/stringUtils.h" #include "cantera/base/ctexceptions.h" #include "cantera/base/ctml.h" @@ -12,7 +12,7 @@ namespace Cantera { -Electron::Electron() +PlasmaElectron::PlasmaElectron() : m_ncs(0) , m_points(200) , m_kT(Undef) @@ -38,11 +38,11 @@ Electron::Electron() m_gamma = pow(2.0 * ElectronCharge / ElectronMass, 0.5); } -Electron::~Electron() +PlasmaElectron::~PlasmaElectron() { } -void Electron::init(thermo_t* thermo) +void PlasmaElectron::init(thermo_t* thermo) { m_thermo = thermo; m_f0_ok = false; @@ -80,7 +80,7 @@ void Electron::init(thermo_t* thermo) m_moleFractions.resize(m_ncs, 0.0); } -void Electron::setGridCache() +void PlasmaElectron::setGridCache() { m_sigma.clear(); m_sigma.resize(m_ncs); @@ -145,7 +145,7 @@ void Electron::setGridCache() } } -void Electron::update_T() +void PlasmaElectron::update_T() { // signal that temperature-dependent quantities will need to be recomputed // before use, and update the local temperature. @@ -157,7 +157,7 @@ void Electron::update_T() } } -void Electron::update_C() +void PlasmaElectron::update_C() { // signal that concentration-dependent quantities will need to be recomputed // before use, and update the local mole fractions. @@ -173,7 +173,7 @@ void Electron::update_C() // warn that a specific species needs cross-section data. for (size_t k : m_kOthers) { if (X[k] > 0.01) { - writelog("Cantera::Electron::update_C"); + writelog("Cantera::PlasmaElectron::update_C"); writelog("\n"); writelog("Warning: The mole fraction of species {} is more than 0.01", m_thermo->speciesName(k)); @@ -183,7 +183,7 @@ void Electron::update_C() } } -bool Electron::addElectronCrossSection(shared_ptr ecs) +bool PlasmaElectron::addElectronCrossSection(shared_ptr ecs) { ecs->validate(); m_targets.push_back(ecs->target); @@ -221,7 +221,7 @@ bool Electron::addElectronCrossSection(shared_ptr ecs) for (size_t k = 0; k < m_ncs; k++) { if (m_targets[k] == ecs->target) if (m_kinds[k] == "ELASTIC" || m_kinds[k] == "EFFECTIVE") { - throw CanteraError("Electron::addElectronCrossSection", + throw CanteraError("PlasmaElectron::addElectronCrossSection", "Already contains a data of EFFECTIVE/ELASTIC cross section for '{}'.", ecs->target); } @@ -239,7 +239,7 @@ bool Electron::addElectronCrossSection(shared_ptr ecs) return true; } -void Electron::calculateElasticCrossSection() +void PlasmaElectron::calculateElasticCrossSection() { for (size_t ke : m_kElastic) { if (m_kinds[ke] == "EFFECTIVE") { @@ -262,7 +262,7 @@ void Electron::calculateElasticCrossSection() } } -void Electron::setupGrid(size_t n, const double* eps) +void PlasmaElectron::setupGrid(size_t n, const double* eps) { m_points = n-1; m_gridCenter.resize(n-1); diff --git a/src/plasma/PlasmaElectronFactory.cpp b/src/plasma/PlasmaElectronFactory.cpp new file mode 100644 index 00000000000..1361afbf355 --- /dev/null +++ b/src/plasma/PlasmaElectronFactory.cpp @@ -0,0 +1,47 @@ +/** + * @file PlasmaElectronFactory.cpp + * Definitions for the factory class that can create known PlasmaElectron objects + */ + +// This file is part of Cantera. See License.txt in the top-level directory or +// at https://www.cantera.org/license.txt for license and copyright information. + +#include "cantera/plasma/PlasmaElectronFactory.h" +#include "cantera/plasma/PlasmaElectron.h" +#include "cantera/plasma/WeakIonGasElectron.h" + + +using namespace std; + +namespace Cantera +{ + +PlasmaElectronFactory* PlasmaElectronFactory::s_factory = 0; +std::mutex PlasmaElectronFactory::electron_mutex; + +PlasmaElectronFactory::PlasmaElectronFactory() +{ + reg("WeaklyIonizedGas", []() { return new WeakIonGasElectron(); }); +} + +PlasmaElectron* PlasmaElectronFactory::newPlasmaElectron(const std::string& model) +{ + return create(model); +} + +unique_ptr newPlasmaElectron(const AnyMap& rootNode, thermo_t* phase) +{ + unique_ptr electron(newPlasmaElectron(rootNode["electron"].asString())); + addElectronCrossSections(*electron, rootNode["cross_section"]); + electron->init(phase); + return electron; +} + +void addElectronCrossSections(PlasmaElectron& electron, const AnyValue& cross_section) +{ + for (const auto& item : cross_section.asVector()) { + electron.addElectronCrossSection(newElectronCrossSection(item)); + } +} + +} diff --git a/src/electron/WeakIonGasElectron.cpp b/src/plasma/WeakIonGasElectron.cpp similarity index 99% rename from src/electron/WeakIonGasElectron.cpp rename to src/plasma/WeakIonGasElectron.cpp index 0c61115d12d..5345e0af595 100644 --- a/src/electron/WeakIonGasElectron.cpp +++ b/src/plasma/WeakIonGasElectron.cpp @@ -1,8 +1,8 @@ // This file is part of Cantera. See License.txt in the top-level directory or // at https://www.cantera.org/license.txt for license and copyright information. -#include "cantera/electron/WeakIonGasElectron.h" -#include "cantera/electron/ElectronFactory.h" +#include "cantera/plasma/WeakIonGasElectron.h" +#include "cantera/plasma/PlasmaElectronFactory.h" #include "cantera/base/utilities.h" #include "cantera/numerics/funcs.h" #include diff --git a/src/transport/IonGasTransport.cpp b/src/transport/IonGasTransport.cpp index a2d4230f4c3..518e68b871d 100644 --- a/src/transport/IonGasTransport.cpp +++ b/src/transport/IonGasTransport.cpp @@ -87,7 +87,7 @@ void IonGasTransport::init(thermo_t* thermo, int mode, int log_level) } } -void IonGasTransport::initElectron(Electron* electron) +void IonGasTransport::initElectron(PlasmaElectron* electron) { m_electron = electron; } From 2443c26bccecb0f2d8fd6e1a0fbe8af6e499ee77 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 3 Jan 2020 08:55:29 -0500 Subject: [PATCH 066/139] [data] add oxygen plasma --- data/inputs/oxygen_cross_sections.yaml | 403 +++++++++++++++++++++++++ data/inputs/oxygen_plasma.yaml | 44 +++ 2 files changed, 447 insertions(+) create mode 100644 data/inputs/oxygen_cross_sections.yaml create mode 100644 data/inputs/oxygen_plasma.yaml diff --git a/data/inputs/oxygen_cross_sections.yaml b/data/inputs/oxygen_cross_sections.yaml new file mode 100644 index 00000000000..0c936d38ead --- /dev/null +++ b/data/inputs/oxygen_cross_sections.yaml @@ -0,0 +1,403 @@ +# Ref.: Itikawa, Y., 2009. Cross sections for electron collisions with oxygen molecules. Journal of Physical and Chemical Reference Data, 38(1), pp.1-20. +cross-sections: +- comment: Total Scattering - Table 1 of Itikawa (2009) + kind: EFFECTIVE + target: O2 + mass_ratio: 1.71e-05 + data: + - [0.00, 3.83e-20] + - [0.10, 3.83e-20] + - [0.12, 4.02e-20] + - [0.15, 4.22e-20] + - [0.17, 4.33e-20] + - [0.20, 4.47e-20] + - [0.25, 4.65e-20] + - [0.30, 4.79e-20] + - [0.35, 4.91e-20] + - [0.40, 5.07e-20] + - [0.45, 5.20e-20] + - [0.5, 5.31e-20] + - [0.6, 5.49e-20] + - [0.7, 5.64e-20] + - [0.8, 5.77e-20] + - [0.9, 5.87e-20] + - [1.0, 5.97e-20] + - [1.2, 6.18e-20] + - [1.5, 6.36e-20] + - [1.7, 6.45e-20] + - [2.0, 6.56e-20] + - [2.5, 6.68e-20] + - [3.0, 6.84e-20] + - [3.5, 7.01e-20] + - [4.0, 7.18e-20] + - [4.5, 7.36e-20] + - [5.0, 7.55e-20] + - [6.0, 7.93e-20] + - [7.0, 8.39e-20] + - [8.0, 9.16e-20] + - [9.0, 9.91e-20] + - [10.0, 1.04e-19] + - [12.0, 1.08e-19] + - [15.0, 1.07e-19] + - [17.0, 1.07e-19] + - [20.0, 1.08e-19] + - [25.0, 1.10e-19] + - [30.0, 1.10e-19] + - [35.0, 1.09e-19] + - [40.0, 1.07e-19] + - [45.0, 1.05e-19] + - [50.0, 1.03e-19] + - [60.0, 9.87e-20] + - [70.0, 9.52e-20] + - [80.0, 9.23e-20] + - [90.0, 8.98e-20] + - [100.0, 8.68e-20] + - [120.0, 7.97e-20] + - [150.0, 7.21e-20] + - [170.0, 6.78e-20] + - [200.0, 6.24e-20] + - [250.0, 5.51e-20] + - [300.0, 4.94e-20] + - [350.0, 4.55e-20] + - [400.0, 4.17e-20] + - [450.0, 3.85e-20] + - [500.0, 3.58e-20] + - [600.0, 3.11e-20] + - [700.0, 2.76e-20] + - [800.0, 2.49e-20] + - [900.0, 2.26e-20] + - [1000.0, 2.08e-20] +- comment: Vibrational Excitation - Table 4 & 5 of Itikawa (2009) + equation: E + O2 => E + O2(v1) + kind: EXCITATION + product: O2(v1) + target: O2 + threshold: 0.19 + data: + - [0.19, 0.0] + - [0.213, 0.0] + - [0.214, 3.0e-21] + - [0.215, 0.0] + - [0.336, 0.0] + - [0.338, 7.05e-20] + - [0.340, 0.0] + - [0.457, 0.0] + - [0.460, 9.85e-20] + - [0.463, 0.0] + - [0.574, 0.0] + - [0.579, 6.69e-20] + - [0.584, 0.0] + - [0.689, 0.0] + - [0.696, 3.39e-20] + - [0.703, 0.0] + - [5.0, 9.50e-22] + - [7.0, 3.05e-21] + - [10.0, 4.4e-21] + - [15.0, 5.70e-22] +- comment: Vibrational Excitation - Table 4 of Itikawa (2009) + equation: E + O2 => E + O2(v2) + kind: EXCITATION + product: O2(v2) + target: O2 + threshold: 0.38 + data: + - [0.38, 0.0] + - [0.457, 0.0] + - [0.460, 5.00e-22] + - [0.463, 0.0] + - [0.574, 0.0] + - [0.579, 8.00e-21] + - [0.584, 0.0] + - [0.689, 0.0] + - [0.696, 1.30e-20] + - [0.703, 0.0] + - [5.0, 3.40e-22] + - [7.0, 1.14e-21] + - [10.0, 1.65e-21] + - [15.0, 1.50e-22] +- comment: Vibrational Excitation - Table 4 of Itikawa (2009) + equation: E + O2 => E + O2(v3) + kind: EXCITATION + product: O2(v3) + target: O2 + threshold: 0.6 + data: + - [0.6, 0.0] + - [0.689, 0.0] + - [0.696, 1.00e-23] + - [0.703, 0.0] + - [7.0, 4.50e-22] + - [10.0, 7.50e-22] + - [15.0, 6.50e-23] +- comment: Excitation of Electronic States - Table 7 of Itikawa (2009) + equation: E + O2 => E + O2(a1) + kind: EXCITATION + product: O2(a1) + target: O2 + threshold: 0.977 + data: + - [0.977, 0.0] + - [5.0, 7.60e-22] + - [7.0, 1.04e-21] + - [10.0, 7.70e-22] + - [15.0, 4.20e-22] + - [20.0, 2.30e-22] +- comment: Excitation of Electronic States - Table 7 of Itikawa (2009) + equation: E + O2 => E + O2(a1) + kind: EXCITATION + product: O2(a1) + target: O2 + threshold: 0.977 + data: + - [0.977, 0.0] + - [5.0, 7.60e-22] + - [7.0, 1.04e-21] + - [10.0, 7.70e-22] + - [15.0, 4.20e-22] + - [20.0, 2.30e-22] +- comment: Excitation of Electronic States - Table 7 of Itikawa (2009) + equation: E + O2 => E + O2(b1) + kind: EXCITATION + product: O2(b1) + target: O2 + threshold: 1.627 + data: + - [1.627, 0.0] + - [5.0, 2.00e-22] + - [7.0, 3.30e-22] + - [10.0, 1.90e-22] + - [15.0, 7.80e-23] + - [20.0, 5.50e-23] +- comment: Excitation of Electronic States - Table 8 of Itikawa (2009) + equation: E + O2 => E + O2(A3) + kind: EXCITATION + product: O2(A3) + target: O2 + threshold: 4.34 + data: + - [4.34, 0.0] + - [10.0, 1.305e-21] + - [15.0, 7.50e-22] + - [20.0, 3.90e-22] + - [30.0, 1.30e-22] +- comment: Excitation of Electronic States - Table 8 of Itikawa (2009) + equation: E + O2 => E + O2(AP) + kind: EXCITATION + product: O2(AP) + target: O2 + threshold: 4.262 + data: + - [4.262, 0.0] + - [10.0, 1.305e-21] + - [15.0, 7.50e-22] + - [20.0, 3.90e-22] + - [30.0, 1.30e-22] +- comment: Excitation of Electronic States - Table 8 of Itikawa (2009) + equation: E + O2 => E + O2(c1) + kind: EXCITATION + product: O2(c1) + target: O2 + threshold: 4.050 + data: + - [4.050, 0.0] + - [10.0, 1.305e-21] + - [15.0, 7.50e-22] + - [20.0, 3.90e-22] + - [30.0, 1.30e-22] +- comment: Excitation of Electronic States - Table 9 of Itikawa (2009) + equation: E + O2 => E + O2(B3) + kind: EXCITATION + product: O2(B3) + target: O2 + threshold: 6.12 + data: + - [6.12, 0.0] + - [15.0, 6.87e-21] + - [20.0, 7.90e-21] + - [30.0, 5.98e-21] + - [50.0, 2.764e-21] +- comment: Dissociative Attachment - Table 13 of Itikawa (2009) + equation: E + O2 => O^- + O + kind: ATTACHMENT + product: O^- + O + target: O2 + threshold: 0.0 + data: + - [4.2, 0.0] + - [4.3, 8.80e-25] + - [4.4, 2.64e-24] + - [4.5, 4.40e-24] + - [4.6, 7.04e-24] + - [4.7, 9.68e-24] + - [4.8, 1.03e-23] + - [4.9, 1.76e-23] + - [5.0, 2.20e-23] + - [5.1, 2.90e-23] + - [5.2, 3.61e-23] + - [5.3, 4.49e-23] + - [5.4, 5.37e-23] + - [5.5, 6.33e-23] + - [5.6, 7.48e-23] + - [5.7, 8.53e-23] + - [5.8, 9.59e-23] + - [5.9, 1.05e-22] + - [6.0, 1.14e-22] + - [6.1, 1.23e-22] + - [6.2, 1.31e-22] + - [6.3, 1.36e-22] + - [6.5, 1.41e-22] + - [6.6, 1.40e-22] + - [6.7, 1.37e-22] + - [6.8, 1.34e-22] + - [6.9, 1.28e-22] + - [7.0, 1.22e-22] + - [7.1, 1.14e-22] + - [7.2, 1.06e-22] + - [7.3, 9.85e-23] + - [7.4, 8.97e-23] + - [7.5, 8.18e-23] + - [7.6, 7.39e-23] + - [7.7, 6.42e-23] + - [7.8, 5.72e-23] + - [7.9, 5.01e-23] + - [8.0, 4.49e-23] + - [8.1, 3.87e-23] + - [8.2, 3.34e-23] + - [8.3, 2.82e-23] + - [8.4, 2.38e-23] + - [8.5, 2.02e-23] + - [8.6, 1.67e-23] + - [8.7, 1.41e-23] + - [8.8, 1.23e-23] + - [8.9, 1.06e-23] + - [9.0, 8.80e-24] + - [9.1, 7.04e-24] + - [9.2, 7.04e-24] + - [9.3, 6.16e-24] + - [9.4, 5.28e-24] + - [9.5, 4.40e-24] + - [9.6, 4.40e-24] + - [9.8, 3.52e-24] + - [9.9, 3.52e-24] +- comment: Total Dissociation for Neutral Products - Table 10 of Itikawa (2009) + equation: E + O2 => E + 2 O + kind: EXCITATION + product: O + O + target: O2 + threshold: 5.58 + data: + - [5.58, 0.0] + - [13.5, 2.20e-21] + - [18.5, 5.29e-21] + - [21.0, 5.65e-21] + - [23.5, 5.25e-21] + - [28.5, 5.87e-21] + - [33.5, 6.63e-21] + - [38.5, 6.10e-21] + - [48.5, 5.34e-21] + - [58.5, 4.44e-21] + - [73.5, 3.66e-21] + - [98.5, 3.31e-21] + - [148.5, 2.96e-21] + - [198.5, 2.91e-21] +- comment: Ionization - Table 11 of Itikawa (2009) + equation: E + O2 => 2 E + O2^+ + kind: IONIZATION + product: O2^+ + target: O2 + threshold: 12.1 + data: + - [12.1, 0.0] + - [13.0, 1.17e-22] + - [15.5, 7.30e-22] + - [18.0, 1.64e-21] + - [23.0, 3.66e-21] + - [28.0, 5.63e-21] + - [33.0, 7.58e-21] + - [38.0, 9.29e-21] + - [43.0, 1.08e-20] + - [48.0, 1.19e-20] + - [53.0, 1.29e-20] + - [58.0, 1.36e-20] + - [63.0, 1.42e-20] + - [68.0, 1.47e-20] + - [73.0, 1.50e-20] + - [78.0, 1.51e-20] + - [83.0, 1.53e-20] + - [88.0, 1.55e-20] + - [93.0, 1.56e-20] + - [98.0, 1.56e-20] + - [108.0, 1.54e-20] + - [118.0, 1.53e-20] + - [138.0, 1.50e-20] + - [158.0, 1.48e-20] + - [178.0, 1.43e-20] + - [198.0, 1.39e-20] + - [223.0, 1.34e-20] + - [248.0, 1.31e-20] + - [273.0, 1.24e-20] + - [298.0, 1.20e-20] + - [348.0, 1.13e-20] + - [398.0, 1.05e-20] + - [448.0, 9.83e-21] + - [498.0, 9.23e-21] + - [548.0, 8.82e-21] + - [598.0, 8.27e-21] + - [648.0, 8.00e-21] + - [698.0, 7.61e-21] + - [748.0, 7.20e-21] + - [798.0, 6.86e-21] + - [848.0, 6.71e-21] + - [898.0, 6.43e-21] + - [948.0, 6.17e-21] + - [998.0, 5.97e-21] +- comment: Ionization - Table 11 of Itikawa (2009) + equation: E + O2 => 2 E + O + O^+ + kind: IONIZATION + product: O + O^+ + target: O2 + threshold: 19.5 + data: + - [13.0, 0.0] + - [15.5, 0.0] + - [18.0, 0.0] + - [23.0, 1.67e-22] + - [28.0, 7.81e-22] + - [33.0, 1.69e-21] + - [38.0, 2.58e-21] + - [43.0, 3.33e-21] + - [48.0, 4.19e-21] + - [53.0, 4.90e-21] + - [58.0, 5.53e-21] + - [63.0, 6.21e-21] + - [68.0, 6.79e-21] + - [73.0, 7.17e-21] + - [78.0, 7.51e-21] + - [83.0, 8.01e-21] + - [88.0, 8.27e-21] + - [93.0, 8.55e-21] + - [98.0, 8.71e-21] + - [108.0, 9.00e-21] + - [118.0, 9.10e-21] + - [138.0, 9.13e-21] + - [158.0, 9.05e-21] + - [178.0, 8.91e-21] + - [198.0, 8.64e-21] + - [223.0, 8.30e-21] + - [248.0, 7.94e-21] + - [273.0, 7.55e-21] + - [298.0, 7.21e-21] + - [348.0, 6.59e-21] + - [398.0, 6.11e-21] + - [448.0, 5.62e-21] + - [498.0, 5.26e-21] + - [548.0, 4.87e-21] + - [598.0, 4.57e-21] + - [648.0, 4.32e-21] + - [698.0, 4.15e-21] + - [748.0, 3.88e-21] + - [798.0, 3.69e-21] + - [848.0, 3.55e-21] + - [898.0, 3.36e-21] + - [948.0, 3.26e-21] + - [998.0, 3.17e-21] diff --git a/data/inputs/oxygen_plasma.yaml b/data/inputs/oxygen_plasma.yaml new file mode 100644 index 00000000000..2933fd0213e --- /dev/null +++ b/data/inputs/oxygen_plasma.yaml @@ -0,0 +1,44 @@ +units: {length: cm, quantity: mol, activation-energy: K} + +phases: +- name: gas + thermo: ideal-gas + elements: [O, E] + species: + - species: [O2^+] + - gri30_ion.yaml/species: [O2, E] + - gri30.yaml/species: [O] + + kinetics: gas + reactions: all + transport: mixture-averaged + state: + T: 300.0 + P: 1.01325e+05 + plasma: WeaklyIonizedGas + cross-sections: + - oxygen_cross_sections.yaml/cross-sections: [O2] + +species: +- name: O2^+ + composition: {O: 2, E: -1} + thermo: + model: NASA7 + temperature-ranges: [298.15, 1000.0, 6000.0] + data: + - [4.61017167, -6.35951952e-03, 1.42425624e-05, -1.20997923e-08, 3.70956878e-12, + 1.39742229e+05, -0.201326874] + - [3.31675922, 1.11522244e-03, -3.83492556e-07, 5.72784687e-11, -2.77648381e-15, + 1.39876823e+05, 5.44726476] + transport: + model: gas + geometry: linear + diameter: 2.750 # Casey + well-depth: 80.0 # Casey + polarizability: 0.847 # Method: B3LYP cc-pVTZ from NIST + note: Casey et al. (2016) doi.org/10.1016/j.proci.2016.08.083 + +reactions: +- equation: O2^+ + E => O + O # Reaction 1 + type: electron-temperature + rate-constant: {A: 6.0e-5, b: -1.0, E1: 0.0, E2: 0.0} \ No newline at end of file From 1b11601d04ff51c186ea02367f8c74e4a8ff138c Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 3 Jan 2020 23:51:23 -0500 Subject: [PATCH 067/139] [plasma] update PlasmaElectronFactory for new yaml format --- .../cantera/plasma/PlasmaElectronFactory.h | 6 ++- src/plasma/PlasmaElectronFactory.cpp | 52 ++++++++++++++++--- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/include/cantera/plasma/PlasmaElectronFactory.h b/include/cantera/plasma/PlasmaElectronFactory.h index 95dfdaf5b38..43b6dd300f1 100644 --- a/include/cantera/plasma/PlasmaElectronFactory.h +++ b/include/cantera/plasma/PlasmaElectronFactory.h @@ -63,9 +63,11 @@ inline PlasmaElectron* newPlasmaElectron(const std::string& model) return PlasmaElectronFactory::factory()->create(model); } -unique_ptr newPlasmaElectron(const AnyMap& rootNode=AnyMap(), thermo_t* phase = 0); +unique_ptr newPlasmaElectron(const AnyMap& phaseNode=AnyMap(), + const AnyMap& rootNode=AnyMap(), + thermo_t* phase = 0); -void addElectronCrossSections(PlasmaElectron& electron, const AnyValue& cross_section); +void addElectronCrossSections(PlasmaElectron& electron, const AnyValue& cross_section, const AnyValue& names); } diff --git a/src/plasma/PlasmaElectronFactory.cpp b/src/plasma/PlasmaElectronFactory.cpp index 1361afbf355..696ce123a0c 100644 --- a/src/plasma/PlasmaElectronFactory.cpp +++ b/src/plasma/PlasmaElectronFactory.cpp @@ -29,18 +29,58 @@ PlasmaElectron* PlasmaElectronFactory::newPlasmaElectron(const std::string& mode return create(model); } -unique_ptr newPlasmaElectron(const AnyMap& rootNode, thermo_t* phase) +unique_ptr newPlasmaElectron(const AnyMap& phaseNode, const AnyMap& rootNode, thermo_t* phase) { - unique_ptr electron(newPlasmaElectron(rootNode["electron"].asString())); - addElectronCrossSections(*electron, rootNode["cross_section"]); + unique_ptr electron(newPlasmaElectron(phaseNode["plasma"].asString())); + if (phaseNode.hasKey("cross-sections")) { + if (phaseNode["cross-sections"].is>()) { + // Each item in 'cross-sections' is a map with one item, where the key is + // a section in another YAML file, and the value is a + // list of target species names to read from that section + for (const auto& crossSectionsNode : phaseNode["cross-sections"].asVector()) { + const string& source = crossSectionsNode.begin()->first; + const auto& names = crossSectionsNode.begin()->second; + const auto& slash = boost::ifind_last(source, "/"); + if (slash) { + // source is a different input file + std::string fileName(source.begin(), slash.begin()); + std::string node(slash.end(), source.end()); + AnyMap crossSections = AnyMap::fromYamlFile(fileName); + addElectronCrossSections(*electron, crossSections[node], names); + } else { + throw InputFileError("newPlasmaElectron", crossSectionsNode, + "Could not find species section named '{}'", source); + } + } + } else { + throw InputFileError("newPlasmaElectron", phaseNode["cross-sections"], + "Could not parse cross-sections declaration of type '{}'", + phaseNode["cross-sections"].type_str()); + } + } electron->init(phase); return electron; } -void addElectronCrossSections(PlasmaElectron& electron, const AnyValue& cross_section) +void addElectronCrossSections(PlasmaElectron& electron, const AnyValue& crossSections, const AnyValue& names) { - for (const auto& item : cross_section.asVector()) { - electron.addElectronCrossSection(newElectronCrossSection(item)); + if (names.is>()) { + // 'names' is a list of target species names which should be found in 'cross-sections' + for (const auto& name : names.asVector()) { + for (const auto& item : crossSections.asVector()) { + if (item["target"].asString() == name) { + electron.addElectronCrossSection(newElectronCrossSection(item)); + } + } + } + } else if (names.is() && names.asString() == "all") { + // The keyword 'all' means to add all cross-sections from this source + for (const auto& item : crossSections.asVector()) { + electron.addElectronCrossSection(newElectronCrossSection(item)); + } + } else { + throw InputFileError("addElectronCrossSections", names, + "Could not parse cross-sections declaration of type '{}'", names.type_str()); } } From e8eccf15c8ebf0cf730aaaaaee2960a119a255f4 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 4 Jan 2020 01:12:06 -0500 Subject: [PATCH 068/139] [interface] update base.pyx --- interfaces/cython/cantera/_cantera.pxd | 2 +- interfaces/cython/cantera/base.pyx | 26 ++++++++------------------ 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index e8cf857ab6e..1c1ad47b2d8 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -746,7 +746,7 @@ cdef extern from "cantera/thermo/ThermoFactory.h" namespace "Cantera": cdef CxxThermoPhase* newThermoPhase(string) except +translate_exception cdef extern from "cantera/plasma/PlasmaElectronFactory.h" namespace "Cantera": - cdef shared_ptr[CxxPlasmaElectron] newPlasmaElectron(CxxAnyMap&, CxxThermoPhase*) except +translate_exception + cdef shared_ptr[CxxPlasmaElectron] newPlasmaElectron(CxxAnyMap&, CxxAnyMap&, CxxThermoPhase*) except +translate_exception cdef CxxPlasmaElectron* newPlasmaElectron(string) except +translate_exception cdef extern from "cantera/kinetics/KineticsFactory.h" namespace "Cantera": diff --git a/interfaces/cython/cantera/base.pyx b/interfaces/cython/cantera/base.pyx index 16b78d4b548..0439ef72c2c 100644 --- a/interfaces/cython/cantera/base.pyx +++ b/interfaces/cython/cantera/base.pyx @@ -69,10 +69,6 @@ cdef class _SolutionBase: self.base.setThermo(self._thermo) self.base.setKinetics(self._kinetics) - # Initiate plasma - if efile: - self._init_efile(efile) - if electron_cross_sections: self._init_electron(plasma_electron, electron_cross_sections) @@ -158,6 +154,14 @@ cdef class _SolutionBase: else: self.kinetics = NULL + # Plasma + if isinstance(self, PlasmaElectron): + self._plasmaElectron = newPlasmaElectron(phaseNode, root, self.thermo) + self.plasmaElectron = self._plasmaElectron.get() + self.kinetics.addPlasmaElectron(self.plasmaElectron) + else: + self.plasmaElectron = NULL + def _init_cti_xml(self, infile, name, adjacent, source): """ Instantiate a set of new Cantera C++ objects from a CTI or XML @@ -233,20 +237,6 @@ cdef class _SolutionBase: for reaction in reactions: self.kinetics.addReaction(reaction._reaction) - def _init_efile(self, efile): - """ - Instantiate a new PlasmaElectron object via a yaml file. - """ - cdef CxxAnyMap root - root = AnyMapFromYamlFile(stringify(efile)) - - if isinstance(self, PlasmaElectron): - self._plasmaElectron = newPlasmaElectron(root, self.thermo) - self.plasmaElectron = self._plasmaElectron.get() - self.kinetics.addPlasmaElectron(self.plasmaElectron) - else: - self.plasmaElectron = NULL - def _init_electron(self, plasma_electron, electron_cross_sections): """ Instantiate a new PlasmaElectron object. From ce3d0b45379e59b707b53fb30273678635662407 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 4 Jan 2020 07:03:30 -0500 Subject: [PATCH 069/139] [kinetics] change ElectronReaction to ElectronTemperatureReaction and delete xml codes --- include/cantera/kinetics/GasKinetics.h | 6 +-- include/cantera/kinetics/Reaction.h | 8 +-- include/cantera/kinetics/reaction_defs.h | 2 +- src/kinetics/GasKinetics.cpp | 20 ++++---- src/kinetics/Reaction.cpp | 62 ++++++++++++++---------- 5 files changed, 54 insertions(+), 44 deletions(-) diff --git a/include/cantera/kinetics/GasKinetics.h b/include/cantera/kinetics/GasKinetics.h index 186c5471b06..7b28f62d4cb 100644 --- a/include/cantera/kinetics/GasKinetics.h +++ b/include/cantera/kinetics/GasKinetics.h @@ -95,7 +95,7 @@ class GasKinetics : public BulkKinetics Rate1 m_falloff_high_rates; //! Rate expressions for electron reactions - Rate1 m_electron_rates; + Rate1 m_electron_temperature_rates; FalloffMgr m_falloffn; @@ -130,13 +130,13 @@ class GasKinetics : public BulkKinetics void processFalloffReactions(); - void addElectronReaction(ElectronReaction& r); + void addElectronTemperatureReaction(ElectronTemperatureReaction& r); void addThreeBodyReaction(ThreeBodyReaction& r); void addFalloffReaction(FalloffReaction& r); void addPlogReaction(PlogReaction& r); void addChebyshevReaction(ChebyshevReaction& r); - void modifyElectronReaction(size_t i, ElectronReaction& r); + void modifyElectronTemperatureReaction(size_t i, ElectronTemperatureReaction& r); void modifyThreeBodyReaction(size_t i, ThreeBodyReaction& r); void modifyFalloffReaction(size_t i, FalloffReaction& r); void modifyPlogReaction(size_t i, PlogReaction& r); diff --git a/include/cantera/kinetics/Reaction.h b/include/cantera/kinetics/Reaction.h index 8761eed1cdb..2354cf1521c 100644 --- a/include/cantera/kinetics/Reaction.h +++ b/include/cantera/kinetics/Reaction.h @@ -94,12 +94,12 @@ class ElementaryReaction : public Reaction //! A reaction which depends on electron temperature, usually including //! electron as a reactant species. -class ElectronReaction : public Reaction +class ElectronTemperatureReaction : public Reaction { public: - ElectronReaction(); - ElectronReaction(const Composition& reactants, const Composition products, - const ElectronArrhenius& rate); + ElectronTemperatureReaction(); + ElectronTemperatureReaction(const Composition& reactants, const Composition products, + const ElectronArrhenius& rate); ElectronArrhenius rate; }; diff --git a/include/cantera/kinetics/reaction_defs.h b/include/cantera/kinetics/reaction_defs.h index 0cd7aa1ea1a..c5056481be5 100644 --- a/include/cantera/kinetics/reaction_defs.h +++ b/include/cantera/kinetics/reaction_defs.h @@ -68,7 +68,7 @@ const int CHEMACT_RXN = 8; /** * A gas-phase reaction that depends on electron temperature. */ -const int ELECTRON_RXN = 9; +const int ELECTRON_TEMPERATURE_RXN = 9; /** * A reaction occurring on a surface. diff --git a/src/kinetics/GasKinetics.cpp b/src/kinetics/GasKinetics.cpp index dc608ac1c1d..aba37388725 100644 --- a/src/kinetics/GasKinetics.cpp +++ b/src/kinetics/GasKinetics.cpp @@ -54,8 +54,8 @@ void GasKinetics::update_rates_T() } if (T != m_temp || Te != m_temp_e) { - if (m_electron_rates.nReactions()) { - m_electron_rates.update(T, Te, logTe, m_rfn.data()); + if (m_electron_temperature_rates.nReactions()) { + m_electron_temperature_rates.update(T, Te, logTe, m_rfn.data()); m_ROP_ok = false; } } @@ -253,8 +253,8 @@ bool GasKinetics::addReaction(shared_ptr r) case ELEMENTARY_RXN: addElementaryReaction(dynamic_cast(*r)); break; - case ELECTRON_RXN: - addElectronReaction(dynamic_cast(*r)); + case ELECTRON_TEMPERATURE_RXN: + addElectronTemperatureReaction(dynamic_cast(*r)); break; case THREE_BODY_RXN: addThreeBodyReaction(dynamic_cast(*r)); @@ -276,9 +276,9 @@ bool GasKinetics::addReaction(shared_ptr r) return true; } -void GasKinetics::addElectronReaction(ElectronReaction& r) +void GasKinetics::addElectronTemperatureReaction(ElectronTemperatureReaction& r) { - m_electron_rates.install(nReactions()-1, r.rate); + m_electron_temperature_rates.install(nReactions()-1, r.rate); } void GasKinetics::addFalloffReaction(FalloffReaction& r) @@ -357,8 +357,8 @@ void GasKinetics::modifyReaction(size_t i, shared_ptr rNew) case THREE_BODY_RXN: modifyThreeBodyReaction(i, dynamic_cast(*rNew)); break; - case ELECTRON_RXN: - modifyElectronReaction(i, dynamic_cast(*rNew)); + case ELECTRON_TEMPERATURE_RXN: + modifyElectronTemperatureReaction(i, dynamic_cast(*rNew)); break; case FALLOFF_RXN: case CHEMACT_RXN: @@ -382,9 +382,9 @@ void GasKinetics::modifyReaction(size_t i, shared_ptr rNew) m_pres += 0.1234; } -void GasKinetics::modifyElectronReaction(size_t i, ElectronReaction& r) +void GasKinetics::modifyElectronTemperatureReaction(size_t i, ElectronTemperatureReaction& r) { - m_electron_rates.replace(i, r.rate); + m_electron_temperature_rates.replace(i, r.rate); } void GasKinetics::modifyThreeBodyReaction(size_t i, ThreeBodyReaction& r) diff --git a/src/kinetics/Reaction.cpp b/src/kinetics/Reaction.cpp index e1e925d3a56..9ff8a52544e 100644 --- a/src/kinetics/Reaction.cpp +++ b/src/kinetics/Reaction.cpp @@ -128,16 +128,16 @@ void ElementaryReaction::validate() } } -ElectronReaction::ElectronReaction(const Composition& reactants_, - const Composition products_, - const ElectronArrhenius& rate_) - : Reaction(ELECTRON_RXN, reactants_, products_) +ElectronTemperatureReaction::ElectronTemperatureReaction(const Composition& reactants_, + const Composition products_, + const ElectronArrhenius& rate_) + : Reaction(ELECTRON_TEMPERATURE_RXN, reactants_, products_) , rate(rate_) { } -ElectronReaction::ElectronReaction() - : Reaction(ELECTRON_RXN) +ElectronTemperatureReaction::ElectronTemperatureReaction() + : Reaction(ELECTRON_TEMPERATURE_RXN) { } @@ -297,14 +297,6 @@ ElectrochemicalReaction::ElectrochemicalReaction(const Composition& reactants_, { } -ElectronArrhenius readElectronArrhenius(const XML_Node& arrhenius_node) -{ - return ElectronArrhenius(getFloat(arrhenius_node, "A", "toSI"), - getFloat(arrhenius_node, "b"), - getFloat(arrhenius_node, "E1", "actEnergy") / GasConstant, - getFloat(arrhenius_node, "E2", "actEnergy") / GasConstant); -} - Arrhenius readArrhenius(const XML_Node& arrhenius_node) { return Arrhenius(getFloat(arrhenius_node, "A", "toSI"), @@ -370,6 +362,28 @@ Arrhenius readArrhenius(const Reaction& R, const AnyValue& rate, return Arrhenius(A, b, Ta); } +ElectronArrhenius readElectronTemperatureArrhenius(const Reaction& R, const AnyValue& rate, + const Kinetics& kin, const UnitSystem& units, + int pressure_dependence=0) +{ + double A, b, T1, T2; + Units rc_units = rateCoeffUnits(R, kin, pressure_dependence); + if (rate.is()) { + auto& rate_map = rate.as(); + A = units.convert(rate_map["A"], rc_units); + b = rate_map["b"].asDouble(); + T1 = units.convertActivationEnergy(rate_map["E1"], "K"); + T2 = units.convertActivationEnergy(rate_map["E2"], "K"); + } else { + auto& rate_vec = rate.asVector(4); + A = units.convert(rate_vec[0], rc_units); + b = rate_vec[1].asDouble(); + T1 = units.convertActivationEnergy(rate_vec[2], "K"); + T2 = units.convertActivationEnergy(rate_vec[3], "K"); + } + return ElectronArrhenius(A, b, T1, T2); +} + //! Parse falloff parameters, given a rateCoeff node /*! * @verbatim @@ -599,15 +613,11 @@ void setupElementaryReaction(ElementaryReaction& R, const AnyMap& node, R.rate = readArrhenius(R, node["rate-constant"], kin, node.units()); } -void setupElectronReaction(ElectronReaction& R, const XML_Node& rxn_node) +void setupElectronTemperatureReaction(ElectronTemperatureReaction& R, const AnyMap& node, + const Kinetics& kin) { - XML_Node& rc_node = rxn_node.child("rateCoeff"); - if (rc_node.hasChild("ElectronArrhenius")) { - R.rate = readElectronArrhenius(rc_node.child("ElectronArrhenius")); - } else { - throw CanteraError("setupElementaryReaction", "Couldn't find Arrhenius node"); - } - setupReaction(R, rxn_node); + setupReaction(R, node, kin); + R.rate = readElectronTemperatureArrhenius(R, node["rate-constant"], kin, node.units()); } void setupThreeBodyReaction(ThreeBodyReaction& R, const XML_Node& rxn_node) @@ -1055,10 +1065,6 @@ shared_ptr newReaction(const XML_Node& rxn_node) auto R = make_shared(); setupElementaryReaction(*R, rxn_node); return R; - } else if (type == "electron") { - auto R = make_shared(); - setupElectronReaction(*R, rxn_node); - return R; } else if (type == "threebody" || type == "three_body") { auto R = make_shared(); setupThreeBodyReaction(*R, rxn_node); @@ -1123,6 +1129,10 @@ unique_ptr newReaction(const AnyMap& node, const Kinetics& kin) unique_ptr R(new ElementaryReaction()); setupElementaryReaction(*R, node, kin); return unique_ptr(move(R)); + } else if (type == "electron-temperature") { + unique_ptr R(new ElectronTemperatureReaction()); + setupElectronTemperatureReaction(*R, node, kin); + return unique_ptr(move(R)); } else if (type == "three-body") { unique_ptr R(new ThreeBodyReaction()); setupThreeBodyReaction(*R, node, kin); From 6d2b0f3c35187857542360ec99e0798942feca68 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 7 Jan 2020 18:44:18 -0500 Subject: [PATCH 070/139] [interface] update ElectronReaction to ElectronTemperatureReaction --- interfaces/cython/cantera/_cantera.pxd | 4 ++-- interfaces/cython/cantera/reaction.pyx | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 1c1ad47b2d8..05d185d6ed2 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -388,8 +388,8 @@ cdef extern from "cantera/kinetics/Reaction.h" namespace "Cantera": Composition efficiencies double default_efficiency - cdef cppclass CxxElectronReaction "Cantera::ElectronReaction" (CxxElementaryReaction): - CxxElectronReaction() + cdef cppclass CxxElectronTemperatureReaction "Cantera::ElectronTemperatureReaction" (CxxElementaryReaction): + CxxElectronTemperatureReaction() cdef cppclass CxxThreeBodyReaction "Cantera::ThreeBodyReaction" (CxxElementaryReaction): CxxThreeBodyReaction() diff --git a/interfaces/cython/cantera/reaction.pyx b/interfaces/cython/cantera/reaction.pyx index d2f09cf6ab6..70fe0557716 100644 --- a/interfaces/cython/cantera/reaction.pyx +++ b/interfaces/cython/cantera/reaction.pyx @@ -3,7 +3,7 @@ cdef extern from "cantera/kinetics/reaction_defs.h" namespace "Cantera": cdef int ELEMENTARY_RXN - cdef int ELECTRON_RXN + cdef int ELECTRON_TEMPERATURE_RXN cdef int THREE_BODY_RXN cdef int FALLOFF_RXN cdef int PLOG_RXN @@ -405,14 +405,14 @@ cdef class ElementaryReaction(Reaction): r.allow_negative_pre_exponential_factor = allow -cdef class ElectronReaction(ElementaryReaction): +cdef class ElectronTemperatureReaction(ElementaryReaction): """ A reaction with electron as reactant """ - reaction_type = ELECTRON_RXN + reaction_type = ELECTRON_TEMPERATURE_RXN - cdef CxxElectronReaction* tbr(self): - return self.reaction + cdef CxxElectronTemperatureReaction* tbr(self): + return self.reaction cdef class ThreeBodyReaction(ElementaryReaction): @@ -830,8 +830,8 @@ cdef Reaction wrapReaction(shared_ptr[CxxReaction] reaction): if reaction_type == ELEMENTARY_RXN: R = ElementaryReaction(init=False) - elif reaction_type == ELECTRON_RXN: - R = ElectronReaction(init=False) + elif reaction_type == ELECTRON_TEMPERATURE_RXN: + R = ElectronTemperatureReaction(init=False) elif reaction_type == THREE_BODY_RXN: R = ThreeBodyReaction(init=False) elif reaction_type == FALLOFF_RXN: @@ -856,8 +856,8 @@ cdef CxxReaction* newReaction(int reaction_type): """ if reaction_type == ELEMENTARY_RXN: return new CxxElementaryReaction() - elif reaction_type == ELECTRON_RXN: - return new CxxElectronReaction() + elif reaction_type == ELECTRON_TEMPERATURE_RXN: + return new CxxElectronTemperatureReaction() elif reaction_type == THREE_BODY_RXN: return new CxxThreeBodyReaction() elif reaction_type == FALLOFF_RXN: From 9fc061bddbd2147a79029e6eba070a16738f173d Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 7 Jan 2020 19:02:14 -0500 Subject: [PATCH 071/139] [test] update test-electron --- .../cython/cantera/test/test_electron.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/interfaces/cython/cantera/test/test_electron.py b/interfaces/cython/cantera/test/test_electron.py index e4b5461fa2a..c6d71024684 100644 --- a/interfaces/cython/cantera/test/test_electron.py +++ b/interfaces/cython/cantera/test/test_electron.py @@ -7,22 +7,22 @@ class TestElectron(utilities.CanteraTest): def setUp(self): - self.gas = ct.Plasma(infile='ch4_plasma.cti', efile='lxcat.yaml') + self.gas = ct.Plasma(infile='oxygen_plasma.yaml') def test_electron_properties(self): self.gas.TPX = 1000, ct.one_atm, 'O2:1.0, E:1e-10' self.gas.electric_field = 1e5 self.gas.electric_field_freq = 0.0 - self.assertNear(self.gas.electron_temperature, 15273, 1e-3) - self.assertNear(self.gas.electron_mobility, 0.3981, 1e-4) - self.assertNear(self.gas.electron_diffusivity, 0.5652, 1e-4) - rate = self.gas.electron_rate_coefficient(19) - self.assertNear(self.gas.net_plasma_production_rates[24] * 1e-10, rate, 1e-4) - self.assertNear(self.gas.net_plasma_production_rates[24], 0.001877, 1e-3) - self.assertNear(self.gas.electron_total_collision_frequency, 3.6957e11, 1e-3) + self.assertNear(self.gas.electron_temperature, 13113, 1e-3) + self.assertNear(self.gas.electron_mobility, 0.3985, 1e-4) + self.assertNear(self.gas.electron_diffusivity, 0.5268, 1e-4) + #rate = self.gas.electron_rate_coefficient(19) + # self.assertNear(self.gas.net_plasma_production_rates[24] * 1e-10, rate, 1e-4) + # self.assertNear(self.gas.net_plasma_production_rates[24], 0.001877, 1e-3) + self.assertNear(self.gas.electron_total_collision_frequency, 3.433e11, 1e-3) self.assertNear(self.gas.electron_power_gain, 3.9811e9, 1e-3) - self.assertNear(self.gas.electron_elastic_power_loss, 2.8744e7, 1e-3) - self.assertNear(self.gas.mean_electron_energy, 1.9742, 1e-3) + self.assertNear(self.gas.electron_elastic_power_loss, 2.4114e7, 1e-3) + self.assertNear(self.gas.mean_electron_energy, 1.6949, 1e-3) self.assertNear(self.gas.electric_field, 1e5, 1e-3) def test_change_electric_field_freq(self): From 714e2596bf982d4143d7e01a9070ef8612fc9456 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 7 Jan 2020 21:16:33 -0500 Subject: [PATCH 072/139] [interface] delete ElectronReaction from cti2yaml --- interfaces/cython/cantera/cti2yaml.py | 28 --------------------------- 1 file changed, 28 deletions(-) diff --git a/interfaces/cython/cantera/cti2yaml.py b/interfaces/cython/cantera/cti2yaml.py index 7c493bac915..20252a98545 100644 --- a/interfaces/cython/cantera/cti2yaml.py +++ b/interfaces/cython/cantera/cti2yaml.py @@ -687,34 +687,6 @@ def get_yaml(self, out): out['nonreactant-orders'] = True -class electron_reaction(reaction): - """ - A electron reaction. - """ - def __init__(self, equation, kf, id='', order='', options=()): - r""" - :param equation: - A string specifying the chemical equation. - :param kf: - The rate coefficient for the forward direction. If a sequence of - three numbers is given, these will be interpreted as [A, b, E1, E2] in - the modified Arrhenius function :math:`A T^b exp(-E1/\hat{R}T) exp(-E2/\hat{R}Te)`. - :param id: - An optional identification string. - :param order: - Override the default reaction orders implied by the reactant - stoichiometric coefficients. Given as a string of key:value pairs, - e.g., ``"CH4:0.25 O2:1.5"``. - :param options: - Processing options, as described in - `Options `__. - May be one or more (as a list) of the following: ``'duplicate'``, - ``'negative_A'``,`` 'negative_orders'``, ``'nonreactant_orders'``. - """ - super().__init__(equation, kf, id, '', options) - self.type = 'electron' - - class three_body_reaction(reaction): """ A three-body reaction. From e5a171b419deec9024d76e6120d20520d5e2ed62 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 7 Jan 2020 21:26:22 -0500 Subject: [PATCH 073/139] [data] delete gri30_plasma & ch4_plasma.cti --- data/inputs/gri30_plasma.cti | 241 ------------------------------- test/data/ch4_plasma.cti | 265 ----------------------------------- 2 files changed, 506 deletions(-) delete mode 100644 data/inputs/gri30_plasma.cti delete mode 100644 test/data/ch4_plasma.cti diff --git a/data/inputs/gri30_plasma.cti b/data/inputs/gri30_plasma.cti deleted file mode 100644 index f121e01cec3..00000000000 --- a/data/inputs/gri30_plasma.cti +++ /dev/null @@ -1,241 +0,0 @@ -units(length='cm', time='s', quantity='mol', act_energy='cal/mol') - -ideal_gas(name='gas', - elements=' O H C N Ar E', - species=['H2 O2 H2O CH4 CO CO2 N2', - '''gri30: H O OH HO2 H2O2 C CH - CH2 CH2(S) CH3 HCO CH2O CH2OH CH3O - CH3OH C2H C2H2 C2H3 C2H4 C2H5 C2H6 HCCO CH2CO HCCOH - N NH NH2 NH3 NNH NO NO2 N2O HNO CN - HCN H2CN HCNN HCNO HOCN HNCO NCO AR C3H7 - C3H8 CH2CHO CH3CHO''', - 'HCO+ H3O+ E'], - reactions=['gri30: all', 'all'], - transport='Ion', - options=['skip_undeclared_species', 'skip_undeclared_third_bodies'], - initial_state=state(temperature=300.0, pressure=OneAtm)) - -#------------------------------------------------------------------------------- -# Species data -#------------------------------------------------------------------------------- -# The values of polarizability of H2, O2, H2O, CH4, CO, CO2, and N2 are from -# the supplementary material of Han, Jie, et al. "Numerical modelling of ion -# transport in flames." Combustion Theory and Modelling 19.6 (2015): 744-772. -# DOI: 10.1080/13647830.2015.1090018 - -species(name = "H2", - atoms = " H:2 ", - thermo = ( - NASA( [ 200.00, 1000.00], [ 2.344331120E+00, 7.980520750E-03, - -1.947815100E-05, 2.015720940E-08, -7.376117610E-12, - -9.179351730E+02, 6.830102380E-01] ), - NASA( [ 1000.00, 3500.00], [ 3.337279200E+00, -4.940247310E-05, - 4.994567780E-07, -1.795663940E-10, 2.002553760E-14, - -9.501589220E+02, -3.205023310E+00] ) - ), - transport = gas_transport( - geom = "linear", - diam = 2.92, - well_depth = 38.00, - polar = 0.455, - rot_relax = 280.00), - note = '''The value of polarizability is from the supplementary - material of Han, Jie, et al. "Numerical modelling of ion - transport in flames." Combustion Theory and Modelling - 19.6 (2015): 744-772. DOI: 10.1080/13647830.2015.1090018''' - ) - -species(name = "O2", - atoms = " O:2 ", - thermo = ( - NASA( [ 200.00, 1000.00], [ 3.782456360E+00, -2.996734160E-03, - 9.847302010E-06, -9.681295090E-09, 3.243728370E-12, - -1.063943560E+03, 3.657675730E+00] ), - NASA( [ 1000.00, 3500.00], [ 3.282537840E+00, 1.483087540E-03, - -7.579666690E-07, 2.094705550E-10, -2.167177940E-14, - -1.088457720E+03, 5.453231290E+00] ) - ), - transport = gas_transport( - geom = "linear", - diam = 3.458, - well_depth = 107.40, - polar = 1.131, - rot_relax = 3.80), - note = "TPIS89" - ) - -species(name = "H2O", - atoms = " H:2 O:1 ", - thermo = ( - NASA( [ 200.00, 1000.00], [ 4.198640560E+00, -2.036434100E-03, - 6.520402110E-06, -5.487970620E-09, 1.771978170E-12, - -3.029372670E+04, -8.490322080E-01] ), - NASA( [ 1000.00, 3500.00], [ 3.033992490E+00, 2.176918040E-03, - -1.640725180E-07, -9.704198700E-11, 1.682009920E-14, - -3.000429710E+04, 4.966770100E+00] ) - ), - transport = gas_transport( - geom = "nonlinear", - diam = 2.605, - well_depth = 572.40, - dipole = 1.844, - polar = 1.053, - rot_relax = 4.00), - note = "L 8/89" - ) - -species(name = "CH4", - atoms = " C:1 H:4 ", - thermo = ( - NASA( [ 200.00, 1000.00], [ 5.149876130E+00, -1.367097880E-02, - 4.918005990E-05, -4.847430260E-08, 1.666939560E-11, - -1.024664760E+04, -4.641303760E+00] ), - NASA( [ 1000.00, 3500.00], [ 7.485149500E-02, 1.339094670E-02, - -5.732858090E-06, 1.222925350E-09, -1.018152300E-13, - -9.468344590E+03, 1.843731800E+01] ) - ), - transport = gas_transport( - geom = "nonlinear", - diam = 3.746, - well_depth = 141.40, - polar = 2.60, - rot_relax = 13.00), - note = "L 8/88" - ) - -species(name = "CO", - atoms = " C:1 O:1 ", - thermo = ( - NASA( [ 200.00, 1000.00], [ 3.579533470E+00, -6.103536800E-04, - 1.016814330E-06, 9.070058840E-10, -9.044244990E-13, - -1.434408600E+04, 3.508409280E+00] ), - NASA( [ 1000.00, 3500.00], [ 2.715185610E+00, 2.062527430E-03, - -9.988257710E-07, 2.300530080E-10, -2.036477160E-14, - -1.415187240E+04, 7.818687720E+00] ) - ), - transport = gas_transport( - geom = "linear", - diam = 3.65, - well_depth = 98.10, - polar = 1.95, - rot_relax = 1.80), - note = "TPIS79" - ) - -species(name = "CO2", - atoms = " C:1 O:2 ", - thermo = ( - NASA( [ 200.00, 1000.00], [ 2.356773520E+00, 8.984596770E-03, - -7.123562690E-06, 2.459190220E-09, -1.436995480E-13, - -4.837196970E+04, 9.901052220E+00] ), - NASA( [ 1000.00, 3500.00], [ 3.857460290E+00, 4.414370260E-03, - -2.214814040E-06, 5.234901880E-10, -4.720841640E-14, - -4.875916600E+04, 2.271638060E+00] ) - ), - transport = gas_transport( - geom = "linear", - diam = 3.763, - well_depth = 244.00, - polar = 2.65, - rot_relax = 2.10), - note = "L 7/88" - ) - -species(name = "N2", - atoms = " N:2 ", - thermo = ( - NASA( [ 300.00, 1000.00], [ 3.298677000E+00, 1.408240400E-03, - -3.963222000E-06, 5.641515000E-09, -2.444854000E-12, - -1.020899900E+03, 3.950372000E+00] ), - NASA( [ 1000.00, 5000.00], [ 2.926640000E+00, 1.487976800E-03, - -5.684760000E-07, 1.009703800E-10, -6.753351000E-15, - -9.227977000E+02, 5.980528000E+00] ) - ), - transport = gas_transport( - geom = "linear", - diam = 3.621, - well_depth = 97.53, - polar = 1.76, - rot_relax = 4.00), - note = "121286" - ) - -species(name = 'HCO+', - atoms = ' H:1 C:1 O:1 E:-1 ', - thermo = ( - NASA( [ 300.00, 1000.00], [ 2.473973600E+00, 8.671559000E-03, - -1.003150000E-05, 6.717052700E-09, -1.787267400E-12, - 9.914660800E+04, 8.175711870E+00] ), - NASA( [ 1000.00, 5000.00], [ 3.741188000E+00, 3.344151700E-03, - -1.239712100E-06, 2.118938800E-10, -1.370415000E-14, - 9.888407800E+04, 2.078613570E+00] ) - ), - transport=gas_transport(geom='linear', - diam=3.59, - well_depth=498.0, - polar=1.356), - note = '''The polarizability is from Han, Jie, et al. - "Numerical modelling of ion transport in flames." - ,and the rest of the parameters are from its neutral - counterpart HCO''') - -species(name = 'H3O+', - atoms = ' H:3 O:1 E:-1 ', - thermo = ( - NASA( [ 298.15, 1000.00], [ 3.792952700E+00, -9.108540000E-04, - 1.163635490E-05, -1.213648870E-08, 4.261596630E-12, - 7.075124010E+04, 1.471568560E+00] ), - NASA( [ 1000.00, 6000.00], [ 2.496477160E+00, 5.728449200E-03, - -1.839532810E-06, 2.735774390E-10, -1.540939850E-14, - 7.097291130E+04, 7.458507790E+00] ) - ), - transport=gas_transport(geom='nonlinear', - diam=3.15, - well_depth=106.2, - dipole=1.417, - polar=0.897), - note = '''The transport parameters are from Han, Jie, et al. - "Numerical modelling of ion transport in flames."''') - -species(name = 'E', - atoms = ' E:1 ', - thermo = ( - NASA( [ 200.00, 1000.00], [ 2.500000000E+00, 0.000000000E+00, - 0.000000000E+00, 0.000000000E+00, 0.000000000E+00, - -7.453750000E+02, -1.172469020E+01] ), - NASA( [ 1000.00, 6000.00], [ 2.500000000E+00, 0.000000000E+00, - 0.000000000E+00, 0.000000000E+00, 0.000000000E+00, - -7.453750000E+02, -1.172469020E+01] ) - ), - transport=gas_transport(geom='atom', - diam=2.05, - well_depth=145.0, - polar=0.667), - note = 'The transport parameters are not used in IonGasTransport') - -#------------------------------------------------------------------------------- -# Reaction data -#------------------------------------------------------------------------------- - -reaction('CH + O => HCO+ + E', [2.51E+11, 0.0, 1700]) - -reaction('HCO+ + H2O => H3O+ + CO', [1.51E+15, 0.0, 0.0]) - -reaction('H3O+ + E => H2O + H', [2.29E+18, -0.5, 0.0]) - -reaction('H3O+ + E => OH + H + H', [7.95E+21, -1.4, 0.0]) - -reaction('H3O+ + E => H2 + OH', [1.25E+19, -0.5, 0.0]) - -reaction('H3O+ + E => O + H2 + H', [6.0E+17, -0.3, 0.0]) - -# DeFilippo, Anthony C., and Jyh-Yuan Chen. "Modeling plasma-assisted methane–air ignition using pre-calculated electron impact reaction rates." Combustion and Flame 172 (2016): 38-48. - -electron_reaction('H3O+ + E => H2O + H', [6.060000e+19, -1.1, 0.0]) - -electron_reaction('H3O+ + E => OH + H + H', [2.250000e+20, -1.1, 0.0]) - -electron_reaction('H3O+ + E => OH + H2', [3.700000e+19, -1.1, 0.0]) - -electron_reaction('H3O+ + E => O + H2 + H', [1.350000e+19, -1.1, 0.0]) - diff --git a/test/data/ch4_plasma.cti b/test/data/ch4_plasma.cti deleted file mode 100644 index 1b7792aa5f0..00000000000 --- a/test/data/ch4_plasma.cti +++ /dev/null @@ -1,265 +0,0 @@ -units(length='cm', time='s', quantity='mol', act_energy='cal/mol') - -ideal_gas(name='gas', - elements='O H C N E', - species=['''gri30: H O OH HO2 H2O2 C CH - CH2 CH2(S) CH3 HCO CH2O CH3O''', - '''H2 O2 H2O CH4 CO CO2 N2 - HCO+ H3O+ E O2- O2(0.98)'''], - reactions=['gri30: all', 'all'], - transport='Ion', - options=['skip_undeclared_species', 'skip_undeclared_third_bodies'], - initial_state=state(temperature=300.0, pressure=OneAtm)) - -#------------------------------------------------------------------------------- -# Species data -#------------------------------------------------------------------------------- -species(name = "H2", - atoms = " H:2 ", - thermo = ( - NASA( [ 200.00, 1000.00], [ 2.344331120E+00, 7.980520750E-03, - -1.947815100E-05, 2.015720940E-08, -7.376117610E-12, - -9.179351730E+02, 6.830102380E-01] ), - NASA( [ 1000.00, 3500.00], [ 3.337279200E+00, -4.940247310E-05, - 4.994567780E-07, -1.795663940E-10, 2.002553760E-14, - -9.501589220E+02, -3.205023310E+00] ) - ), - transport = gas_transport( - geom = "linear", - diam = 2.92, - well_depth = 38.00, - polar = 0.455, - rot_relax = 280.00), - note = "TPIS78" - ) - -species(name = "O2", - atoms = " O:2 ", - thermo = ( - NASA( [ 200.00, 1000.00], [ 3.782456360E+00, -2.996734160E-03, - 9.847302010E-06, -9.681295090E-09, 3.243728370E-12, - -1.063943560E+03, 3.657675730E+00] ), - NASA( [ 1000.00, 3500.00], [ 3.282537840E+00, 1.483087540E-03, - -7.579666690E-07, 2.094705550E-10, -2.167177940E-14, - -1.088457720E+03, 5.453231290E+00] ) - ), - transport = gas_transport( - geom = "linear", - diam = 3.46, - well_depth = 107.40, - polar = 1.131, - rot_relax = 3.80), - note = "TPIS89" - ) - -species(name = "H2O", - atoms = " H:2 O:1 ", - thermo = ( - NASA( [ 200.00, 1000.00], [ 4.198640560E+00, -2.036434100E-03, - 6.520402110E-06, -5.487970620E-09, 1.771978170E-12, - -3.029372670E+04, -8.490322080E-01] ), - NASA( [ 1000.00, 3500.00], [ 3.033992490E+00, 2.176918040E-03, - -1.640725180E-07, -9.704198700E-11, 1.682009920E-14, - -3.000429710E+04, 4.966770100E+00] ) - ), - transport = gas_transport( - geom = "nonlinear", - diam = 2.60, - well_depth = 572.40, - dipole = 1.84, - polar = 1.053, - rot_relax = 4.00), - note = "L 8/89" - ) - -species(name = "CH4", - atoms = " C:1 H:4 ", - thermo = ( - NASA( [ 200.00, 1000.00], [ 5.149876130E+00, -1.367097880E-02, - 4.918005990E-05, -4.847430260E-08, 1.666939560E-11, - -1.024664760E+04, -4.641303760E+00] ), - NASA( [ 1000.00, 3500.00], [ 7.485149500E-02, 1.339094670E-02, - -5.732858090E-06, 1.222925350E-09, -1.018152300E-13, - -9.468344590E+03, 1.843731800E+01] ) - ), - transport = gas_transport( - geom = "nonlinear", - diam = 3.75, - well_depth = 141.40, - polar = 2.60, - rot_relax = 13.00), - note = "L 8/88" - ) - -species(name = "CO", - atoms = " C:1 O:1 ", - thermo = ( - NASA( [ 200.00, 1000.00], [ 3.579533470E+00, -6.103536800E-04, - 1.016814330E-06, 9.070058840E-10, -9.044244990E-13, - -1.434408600E+04, 3.508409280E+00] ), - NASA( [ 1000.00, 3500.00], [ 2.715185610E+00, 2.062527430E-03, - -9.988257710E-07, 2.300530080E-10, -2.036477160E-14, - -1.415187240E+04, 7.818687720E+00] ) - ), - transport = gas_transport( - geom = "linear", - diam = 3.65, - well_depth = 98.10, - polar = 1.95, - rot_relax = 1.80), - note = "TPIS79" - ) - -species(name = "CO2", - atoms = " C:1 O:2 ", - thermo = ( - NASA( [ 200.00, 1000.00], [ 2.356773520E+00, 8.984596770E-03, - -7.123562690E-06, 2.459190220E-09, -1.436995480E-13, - -4.837196970E+04, 9.901052220E+00] ), - NASA( [ 1000.00, 3500.00], [ 3.857460290E+00, 4.414370260E-03, - -2.214814040E-06, 5.234901880E-10, -4.720841640E-14, - -4.875916600E+04, 2.271638060E+00] ) - ), - transport = gas_transport( - geom = "linear", - diam = 3.76, - well_depth = 244.00, - polar = 2.65, - rot_relax = 2.10), - note = "L 7/88" - ) - -species(name = "N2", - atoms = " N:2 ", - thermo = ( - NASA( [ 300.00, 1000.00], [ 3.298677000E+00, 1.408240400E-03, - -3.963222000E-06, 5.641515000E-09, -2.444854000E-12, - -1.020899900E+03, 3.950372000E+00] ), - NASA( [ 1000.00, 5000.00], [ 2.926640000E+00, 1.487976800E-03, - -5.684760000E-07, 1.009703800E-10, -6.753351000E-15, - -9.227977000E+02, 5.980528000E+00] ) - ), - transport = gas_transport( - geom = "linear", - diam = 3.62, - well_depth = 97.53, - polar = 1.76, - rot_relax = 4.00, - disp_coeff = 2.995, - quad_polar = 3.602), - note = "121286" - ) - -species(name = 'HCO+', - atoms = ' H:1 C:1 O:1 E:-1 ', - thermo = ( - NASA( [ 300.00, 1000.00], [ 2.473973600E+00, 8.671559000E-03, - -1.003150000E-05, 6.717052700E-09, -1.787267400E-12, - 9.914660800E+04, 8.175711870E+00] ), - NASA( [ 1000.00, 5000.00], [ 3.741188000E+00, 3.344151700E-03, - -1.239712100E-06, 2.118938800E-10, -1.370415000E-14, - 9.888407800E+04, 2.078613570E+00] ) - ), - transport=gas_transport(geom='linear', - diam=3.59, - well_depth=498.0, - polar=1.356, - rot_relax=0.0, - disp_coeff = 0.416), - note = 'J12/70') - -species(name = 'H3O+', - atoms = ' H:3 O:1 E:-1 ', - thermo = ( - NASA( [ 298.15, 1000.00], [ 3.792952700E+00, -9.108540000E-04, - 1.163635490E-05, -1.213648870E-08, 4.261596630E-12, - 7.075124010E+04, 1.471568560E+00] ), - NASA( [ 1000.00, 6000.00], [ 2.496477160E+00, 5.728449200E-03, - -1.839532810E-06, 2.735774390E-10, -1.540939850E-14, - 7.097291130E+04, 7.458507790E+00] ) - ), - transport=gas_transport(geom='nonlinear', - diam=3.15, - well_depth=106.2, - dipole=1.417, - polar=0.897, - rot_relax=0.0), - note = 'TPIS89') - -species(name='O2-', - atoms='E:1 O:2', - thermo=(NASA([298.15, 1000.00], - [ 3.66442522E+00, -9.28741138E-04, 6.45477082E-06, - -7.74703380E-09, 2.93332662E-12, -6.87076983E+03, - 4.35140681E+00]), - NASA([1000.00, 6000.00], - [ 3.95666294E+00, 5.98141823E-04, -2.12133905E-07, - 3.63267581E-11, -2.24989228E-15, -7.06287229E+03, - 2.27871017E+00])), - transport=gas_transport(geom='linear', - diam=3.33, - well_depth=136.5, - polar=1.424), - note='L4/89') - -species(name = 'E', - atoms = ' E:1 ', - thermo = ( - NASA( [ 200.00, 1000.00], [ 2.500000000E+00, 0.000000000E+00, - 0.000000000E+00, 0.000000000E+00, 0.000000000E+00, - -7.453750000E+02, -1.172469020E+01] ), - NASA( [ 1000.00, 6000.00], [ 2.500000000E+00, 0.000000000E+00, - 0.000000000E+00, 0.000000000E+00, 0.000000000E+00, - -7.453750000E+02, -1.172469020E+01] ) - ), - transport=gas_transport(geom='atom', - diam=2.05, - well_depth=145.0, - polar=0.667, - rot_relax=0.0), - note = 'gas L10/92') - -species(name = "O2(0.98)", - atoms = " O:2 ", - thermo = ( - NASA( [ 200.00, 1000.00], [ 3.782456360E+00, -2.996734160E-03, - 9.847302010E-06, -9.681295090E-09, 3.243728370E-12, - -1.063943560E+03, 3.657675730E+00] ), - NASA( [ 1000.00, 3500.00], [ 3.282537840E+00, 1.483087540E-03, - -7.579666690E-07, 2.094705550E-10, -2.167177940E-14, - -1.088457720E+03, 5.453231290E+00] ) - ), - transport = gas_transport( - geom = "linear", - diam = 3.46, - well_depth = 107.40, - polar = 1.131, - rot_relax = 3.80), - note = "TPIS89" - ) -#------------------------------------------------------------------------------- -# Reaction data -#------------------------------------------------------------------------------- - -reaction('CH + O => HCO+ + E', [2.51E+11, 0.0, 1700]) - -reaction('HCO+ + H2O => H3O+ + CO', [1.51E+15, 0.0, 0.0]) - -reaction('H3O+ + E => H2O + H', [2.29E+18, -0.5, 0.0]) - -reaction('H3O+ + E => OH + H + H', [7.95E+21, -1.4, 0.0]) - -reaction('H3O+ + E => H2 + OH', [1.25E+19, -0.5, 0.0]) - -reaction('H3O+ + E => O + H2 + H', [6.0E+17, -0.3, 0.0]) - -# DeFilippo, Anthony C., and Jyh-Yuan Chen. "Modeling plasma-assisted methane–air ignition using pre-calculated electron impact reaction rates." Combustion and Flame 172 (2016): 38-48. - -electron_reaction('H3O+ + E => H2O + H', [6.060000e+19, -1.1, 0.0]) - -electron_reaction('H3O+ + E => OH + H + H', [2.250000e+20, -1.1, 0.0]) - -electron_reaction('H3O+ + E => OH + H2', [3.700000e+19, -1.1, 0.0]) - -electron_reaction('H3O+ + E => O + H2 + H', [1.350000e+19, -1.1, 0.0]) - From d644015f87c526cb61ee6d94a072c270e4d1b0a6 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Wed, 8 Jan 2020 15:35:46 -0500 Subject: [PATCH 074/139] [plasma] update PlasmaElectronFactory --- src/plasma/PlasmaElectronFactory.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/plasma/PlasmaElectronFactory.cpp b/src/plasma/PlasmaElectronFactory.cpp index 696ce123a0c..d65fad316cb 100644 --- a/src/plasma/PlasmaElectronFactory.cpp +++ b/src/plasma/PlasmaElectronFactory.cpp @@ -33,7 +33,15 @@ unique_ptr newPlasmaElectron(const AnyMap& phaseNode, const AnyM { unique_ptr electron(newPlasmaElectron(phaseNode["plasma"].asString())); if (phaseNode.hasKey("cross-sections")) { - if (phaseNode["cross-sections"].is>()) { + if (phaseNode["cross-sections"].is>()) { + // 'cross-sections' is a list of target species names to be added from the current + // file's 'cross-sections' section + addElectronCrossSections(*electron, phaseNode["cross-sections"], rootNode["cross-sections"]); + } else if (phaseNode["cross-sections"].is()) { + // 'cross-sections' is a keyword applicable to the current file's 'cross-sections' + // section + addElectronCrossSections(*electron, phaseNode["cross-sections"], rootNode["cross-sections"]); + } else if (phaseNode["cross-sections"].is>()) { // Each item in 'cross-sections' is a map with one item, where the key is // a section in another YAML file, and the value is a // list of target species names to read from that section @@ -57,6 +65,9 @@ unique_ptr newPlasmaElectron(const AnyMap& phaseNode, const AnyM "Could not parse cross-sections declaration of type '{}'", phaseNode["cross-sections"].type_str()); } + } else if (rootNode.hasKey("cross-sections")) { + // By default, add all cross sections from the 'cross-sections' section + addElectronCrossSections(*electron, AnyValue("all"), rootNode["cross-sections"]); } electron->init(phase); return electron; From b8e40c31fdbb673b6d2c8562caee54c12810c571 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 11 Jan 2020 07:50:31 -0500 Subject: [PATCH 075/139] [data] update oxygen plama data --- data/inputs/oxygen_plasma.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/data/inputs/oxygen_plasma.yaml b/data/inputs/oxygen_plasma.yaml index 2933fd0213e..db89e0be3c5 100644 --- a/data/inputs/oxygen_plasma.yaml +++ b/data/inputs/oxygen_plasma.yaml @@ -41,4 +41,8 @@ species: reactions: - equation: O2^+ + E => O + O # Reaction 1 type: electron-temperature - rate-constant: {A: 6.0e-5, b: -1.0, E1: 0.0, E2: 0.0} \ No newline at end of file + rate-constant: {A: 6.0e-5, b: -1.0, Ea-T: 0.0, Ea-Te: 0.0} + +- equation: E + O2 => 2 E + O2^+ + type: plasma + process: {kind: ionization, target: O2, product: O2^+} From 66ae420e34753369891b0ac55a26fec7d2e1da0e Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 11 Jan 2020 12:06:27 -0500 Subject: [PATCH 076/139] [kinetics] add plasmaReaction, PlasmaRate --- include/cantera/kinetics/GasKinetics.h | 6 +++ include/cantera/kinetics/Reaction.h | 15 ++++++- include/cantera/kinetics/RxnRates.h | 56 ++++++++++++++++++++++++ include/cantera/kinetics/reaction_defs.h | 6 +++ src/kinetics/GasKinetics.cpp | 28 ++++++++++++ src/kinetics/Reaction.cpp | 27 +++++++++++- src/kinetics/RxnRates.cpp | 4 ++ 7 files changed, 138 insertions(+), 4 deletions(-) diff --git a/include/cantera/kinetics/GasKinetics.h b/include/cantera/kinetics/GasKinetics.h index 7b28f62d4cb..fe3bc673307 100644 --- a/include/cantera/kinetics/GasKinetics.h +++ b/include/cantera/kinetics/GasKinetics.h @@ -97,6 +97,9 @@ class GasKinetics : public BulkKinetics //! Rate expressions for electron reactions Rate1 m_electron_temperature_rates; + //! Rate expressions for plasma reactions + Rate1 m_plasma_rates; + FalloffMgr m_falloffn; ThirdBodyCalc m_3b_concm; @@ -129,14 +132,17 @@ class GasKinetics : public BulkKinetics double m_Te_fix; void processFalloffReactions(); + void processPlasmaReactions(); void addElectronTemperatureReaction(ElectronTemperatureReaction& r); + void addPlasmaReaction(PlasmaReaction& r); void addThreeBodyReaction(ThreeBodyReaction& r); void addFalloffReaction(FalloffReaction& r); void addPlogReaction(PlogReaction& r); void addChebyshevReaction(ChebyshevReaction& r); void modifyElectronTemperatureReaction(size_t i, ElectronTemperatureReaction& r); + void modifyPlasmaReaction(size_t i, PlasmaReaction& r); void modifyThreeBodyReaction(size_t i, ThreeBodyReaction& r); void modifyFalloffReaction(size_t i, FalloffReaction& r); void modifyPlogReaction(size_t i, PlogReaction& r); diff --git a/include/cantera/kinetics/Reaction.h b/include/cantera/kinetics/Reaction.h index 2354cf1521c..7fa06e87b6a 100644 --- a/include/cantera/kinetics/Reaction.h +++ b/include/cantera/kinetics/Reaction.h @@ -84,7 +84,7 @@ class ElementaryReaction : public Reaction { public: ElementaryReaction(); - ElementaryReaction(const Composition& reactants, const Composition products, + ElementaryReaction(const Composition& reactants, const Composition& products, const Arrhenius& rate); virtual void validate(); @@ -98,11 +98,22 @@ class ElectronTemperatureReaction : public Reaction { public: ElectronTemperatureReaction(); - ElectronTemperatureReaction(const Composition& reactants, const Composition products, + ElectronTemperatureReaction(const Composition& reactants, const Composition& products, const ElectronArrhenius& rate); ElectronArrhenius rate; }; +//! A reaction which depends on electron energy distribustion function and electron +//! collision cross section. +class PlasmaReaction : public Reaction +{ +public: + PlasmaReaction(); + PlasmaReaction(const Composition& reactants, const Composition& products, + const PlasmaRate& rate); + PlasmaRate rate; +}; + //! A class for managing third-body efficiencies, including default values class ThirdBody { diff --git a/include/cantera/kinetics/RxnRates.h b/include/cantera/kinetics/RxnRates.h index 6ac77d83053..dd628052933 100644 --- a/include/cantera/kinetics/RxnRates.h +++ b/include/cantera/kinetics/RxnRates.h @@ -178,6 +178,62 @@ class ElectronArrhenius double m_logA, m_b, m_E1, m_E2, m_A; }; +class PlasmaRate +{ +public: + PlasmaRate(); + + //! Update concentration-dependent parts of the rate coefficient. + /*! + * For this class, there are no concentration-dependent parts, so this + * method does nothing. + */ + void update_C(const double* c) { + } + + /** + * Update the value the rate constant. + * + * This function returns the actual value of the rate constant. It can be + * safely called for negative values of the pre-exponential factor. + * + * For this class, the rate constant is calculated from class PlasmaElectron + * instead of + */ + double updateRC(double logT, double recipT) const { + return NAN; + } + + //! Return the pre-exponential factor *A* (in m, kmol, s to powers depending + //! on the reaction order) + /*! + * For this class, there are no pre-exponential factor parts, so this + * method return nan. + */ + double preExponentialFactor() const { + return NAN; + } + + //! Return the temperature exponent *b* + /*! + * For this class, there are no temperature exponent parts, so this + * method return nan. + */ + double temperatureExponent() const { + return NAN; + } + + //! Return the activation energy divided by the gas constant (i.e. the + //! activation temperature) [K] + /*! + * For this class, there are no activation energy parts, so this + * method return nan. + */ + double activationEnergy_R() const { + return NAN; + } +}; + /** * An Arrhenius rate with coverage-dependent terms. * diff --git a/include/cantera/kinetics/reaction_defs.h b/include/cantera/kinetics/reaction_defs.h index c5056481be5..ad1f814b743 100644 --- a/include/cantera/kinetics/reaction_defs.h +++ b/include/cantera/kinetics/reaction_defs.h @@ -70,6 +70,12 @@ const int CHEMACT_RXN = 8; */ const int ELECTRON_TEMPERATURE_RXN = 9; +/** + * A plasma reaction that depends on electron energy distribution function and + * electron collision cross section. + */ +const int PLASMA_RXN = 10; + /** * A reaction occurring on a surface. * NOTE: This is a bit ambiguous, and will be taken out in the future diff --git a/src/kinetics/GasKinetics.cpp b/src/kinetics/GasKinetics.cpp index aba37388725..a47c691158e 100644 --- a/src/kinetics/GasKinetics.cpp +++ b/src/kinetics/GasKinetics.cpp @@ -169,6 +169,14 @@ void GasKinetics::processFalloffReactions() } } +void GasKinetics::processPlasmaReactions() +{ + for (size_t i = 0; i < m_plasma_rates.nReactions(); i++) { + // m_ropf[m_plasmaIndx[i]] = ; + // m_rpor[m_plasmaIndx[i]] = ; + } +} + void GasKinetics::updateROP() { update_rates_C(); @@ -189,6 +197,10 @@ void GasKinetics::updateROP() processFalloffReactions(); } + if (m_plasma_rates.nReactions()) { + processPlasmaReactions(); + } + for (size_t i = 0; i < nReactions(); i++) { // Scale the forward rate coefficient by the perturbation factor m_ropf[i] *= m_perturb[i]; @@ -256,6 +268,9 @@ bool GasKinetics::addReaction(shared_ptr r) case ELECTRON_TEMPERATURE_RXN: addElectronTemperatureReaction(dynamic_cast(*r)); break; + case PLASMA_RXN: + addPlasmaReaction(dynamic_cast(*r)); + break; case THREE_BODY_RXN: addThreeBodyReaction(dynamic_cast(*r)); break; @@ -281,6 +296,11 @@ void GasKinetics::addElectronTemperatureReaction(ElectronTemperatureReaction& r) m_electron_temperature_rates.install(nReactions()-1, r.rate); } +void GasKinetics::addPlasmaReaction(PlasmaReaction& r) +{ + m_plasma_rates.install(nReactions()-1, r.rate); +} + void GasKinetics::addFalloffReaction(FalloffReaction& r) { // install high and low rate coeff calculators and extend the high and low @@ -360,6 +380,9 @@ void GasKinetics::modifyReaction(size_t i, shared_ptr rNew) case ELECTRON_TEMPERATURE_RXN: modifyElectronTemperatureReaction(i, dynamic_cast(*rNew)); break; + case PLASMA_RXN: + modifyPlasmaReaction(i, dynamic_cast(*rNew)); + break; case FALLOFF_RXN: case CHEMACT_RXN: modifyFalloffReaction(i, dynamic_cast(*rNew)); @@ -387,6 +410,11 @@ void GasKinetics::modifyElectronTemperatureReaction(size_t i, ElectronTemperatur m_electron_temperature_rates.replace(i, r.rate); } +void GasKinetics::modifyPlasmaReaction(size_t i, PlasmaReaction& r) +{ + m_plasma_rates.replace(i, r.rate); +} + void GasKinetics::modifyThreeBodyReaction(size_t i, ThreeBodyReaction& r) { m_rates.replace(i, r.rate); diff --git a/src/kinetics/Reaction.cpp b/src/kinetics/Reaction.cpp index 9ff8a52544e..4344f68d667 100644 --- a/src/kinetics/Reaction.cpp +++ b/src/kinetics/Reaction.cpp @@ -103,7 +103,7 @@ std::string Reaction::equation() const } ElementaryReaction::ElementaryReaction(const Composition& reactants_, - const Composition products_, + const Composition& products_, const Arrhenius& rate_) : Reaction(ELEMENTARY_RXN, reactants_, products_) , rate(rate_) @@ -129,7 +129,7 @@ void ElementaryReaction::validate() } ElectronTemperatureReaction::ElectronTemperatureReaction(const Composition& reactants_, - const Composition products_, + const Composition& products_, const ElectronArrhenius& rate_) : Reaction(ELECTRON_TEMPERATURE_RXN, reactants_, products_) , rate(rate_) @@ -141,6 +141,19 @@ ElectronTemperatureReaction::ElectronTemperatureReaction() { } +PlasmaReaction::PlasmaReaction(const Composition& reactants_, + const Composition& products_, + const PlasmaRate& rate_) + : Reaction(PLASMA_RXN, reactants_, products_) + , rate(rate_) +{ +} + +PlasmaReaction::PlasmaReaction() + : Reaction(PLASMA_RXN) +{ +} + ThirdBody::ThirdBody(double default_eff) : default_efficiency(default_eff) { @@ -620,6 +633,12 @@ void setupElectronTemperatureReaction(ElectronTemperatureReaction& R, const AnyM R.rate = readElectronTemperatureArrhenius(R, node["rate-constant"], kin, node.units()); } +void setupPlasmaReaction(PlasmaReaction& R, const AnyMap& node, + const Kinetics& kin) +{ + setupReaction(R, node, kin); +} + void setupThreeBodyReaction(ThreeBodyReaction& R, const XML_Node& rxn_node) { readEfficiencies(R.third_body, rxn_node.child("rateCoeff")); @@ -1133,6 +1152,10 @@ unique_ptr newReaction(const AnyMap& node, const Kinetics& kin) unique_ptr R(new ElectronTemperatureReaction()); setupElectronTemperatureReaction(*R, node, kin); return unique_ptr(move(R)); + } else if (type == "plasma") { + unique_ptr R(new PlasmaReaction()); + setupPlasmaReaction(*R, node, kin); + return unique_ptr(move(R)); } else if (type == "three-body") { unique_ptr R(new ThreeBodyReaction()); setupThreeBodyReaction(*R, node, kin); diff --git a/src/kinetics/RxnRates.cpp b/src/kinetics/RxnRates.cpp index ec06cac898b..41ba4c967cb 100644 --- a/src/kinetics/RxnRates.cpp +++ b/src/kinetics/RxnRates.cpp @@ -50,6 +50,10 @@ ElectronArrhenius::ElectronArrhenius(double A, double b, double E1, double E2) } } +PlasmaRate::PlasmaRate() +{ +} + SurfaceArrhenius::SurfaceArrhenius() : m_b(0.0) , m_E(0.0) From b4c6a4f048da1a38bde0dc9d9f3398d5514b8c26 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 14 Jan 2020 15:00:55 -0500 Subject: [PATCH 077/139] [interface] PlasmaReaction to reaction.pyx --- interfaces/cython/cantera/_cantera.pxd | 3 +++ interfaces/cython/cantera/reaction.pyx | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 05d185d6ed2..f0d940ae19b 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -391,6 +391,9 @@ cdef extern from "cantera/kinetics/Reaction.h" namespace "Cantera": cdef cppclass CxxElectronTemperatureReaction "Cantera::ElectronTemperatureReaction" (CxxElementaryReaction): CxxElectronTemperatureReaction() + cdef cppclass CxxPlasmaReaction "Cantera::PlasmaReaction" (CxxElementaryReaction): + CxxPlasmaReaction() + cdef cppclass CxxThreeBodyReaction "Cantera::ThreeBodyReaction" (CxxElementaryReaction): CxxThreeBodyReaction() CxxThirdBody third_body diff --git a/interfaces/cython/cantera/reaction.pyx b/interfaces/cython/cantera/reaction.pyx index 70fe0557716..c202e834496 100644 --- a/interfaces/cython/cantera/reaction.pyx +++ b/interfaces/cython/cantera/reaction.pyx @@ -4,6 +4,7 @@ cdef extern from "cantera/kinetics/reaction_defs.h" namespace "Cantera": cdef int ELEMENTARY_RXN cdef int ELECTRON_TEMPERATURE_RXN + cdef int PLASMA_RXN cdef int THREE_BODY_RXN cdef int FALLOFF_RXN cdef int PLOG_RXN @@ -415,6 +416,16 @@ cdef class ElectronTemperatureReaction(ElementaryReaction): return self.reaction +cdef class PlasmaReaction(ElementaryReaction): + """ + A reaction with electron as reactant + """ + reaction_type = PLASMA_RXN + + cdef CxxPlasmaReaction* tbr(self): + return self.reaction + + cdef class ThreeBodyReaction(ElementaryReaction): """ A reaction with a non-reacting third body "M" that acts to add or remove @@ -832,6 +843,8 @@ cdef Reaction wrapReaction(shared_ptr[CxxReaction] reaction): R = ElementaryReaction(init=False) elif reaction_type == ELECTRON_TEMPERATURE_RXN: R = ElectronTemperatureReaction(init=False) + elif reaction_type == PLASMA_RXN: + R = PlasmaReaction(init=False) elif reaction_type == THREE_BODY_RXN: R = ThreeBodyReaction(init=False) elif reaction_type == FALLOFF_RXN: @@ -858,6 +871,8 @@ cdef CxxReaction* newReaction(int reaction_type): return new CxxElementaryReaction() elif reaction_type == ELECTRON_TEMPERATURE_RXN: return new CxxElectronTemperatureReaction() + elif reaction_type == PLASMA_RXN: + return new CxxPlasmaReaction() elif reaction_type == THREE_BODY_RXN: return new CxxThreeBodyReaction() elif reaction_type == FALLOFF_RXN: From 3b72b631db6bed021752237327e19d5002af477f Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 17 Jan 2020 13:04:01 -0500 Subject: [PATCH 078/139] [interface-cython] delete NetplasmaProductionRate --- include/cantera/cython/wrappers.h | 3 --- interfaces/cython/cantera/_cantera.pxd | 1 - interfaces/cython/cantera/plasma.pyx | 16 ---------------- 3 files changed, 20 deletions(-) diff --git a/include/cantera/cython/wrappers.h b/include/cantera/cython/wrappers.h index 478ffccf970..bb9d59af723 100644 --- a/include/cantera/cython/wrappers.h +++ b/include/cantera/cython/wrappers.h @@ -65,7 +65,6 @@ void CxxArray2D_set(Cantera::Array2D& array, size_t i, size_t j, double value) #define KIN_1D(FUNC_NAME) ARRAY_FUNC(kin, Kinetics, FUNC_NAME) #define TRANSPORT_1D(FUNC_NAME) ARRAY_FUNC(tran, Transport, FUNC_NAME) #define TRANSPORT_2D(FUNC_NAME) ARRAY_FUNC2(tran, Transport, FUNC_NAME) -#define ELECTRON_1D(FUNC_NAME) ARRAY_FUNC(elect, PlasmaElectron, FUNC_NAME) THERMO_1D(getMassFractions) THERMO_1D(setMassFractions) @@ -119,5 +118,3 @@ TRANSPORT_1D(getMobilities) TRANSPORT_2D(getMultiDiffCoeffs) TRANSPORT_2D(getBinaryDiffCoeffs) - -ELECTRON_1D(getNetPlasmaProductionRates) diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index f0d940ae19b..62472cde6f3 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -1259,7 +1259,6 @@ cdef np.ndarray get_species_array(Kinetics kin, kineticsMethod1d method) cdef np.ndarray get_reaction_array(Kinetics kin, kineticsMethod1d method) cdef np.ndarray get_transport_1d(Transport tran, transportMethod1d method) cdef np.ndarray get_transport_2d(Transport tran, transportMethod2d method) -cdef np.ndarray get_electron_1d(PlasmaElectron elect, plasmaElectronMethod1d method) cdef CxxIdealGasPhase* getIdealGasPhase(ThermoPhase phase) except * cdef wrapSpeciesThermo(shared_ptr[CxxSpeciesThermo] spthermo) cdef Reaction wrapReaction(shared_ptr[CxxReaction] reaction) diff --git a/interfaces/cython/cantera/plasma.pyx b/interfaces/cython/cantera/plasma.pyx index 2b3d2f74011..436e403b941 100644 --- a/interfaces/cython/cantera/plasma.pyx +++ b/interfaces/cython/cantera/plasma.pyx @@ -4,14 +4,6 @@ import warnings import weakref -cdef np.ndarray get_electron_1d(PlasmaElectron elect, plasmaElectronMethod1d method): - cdef np.ndarray[np.double_t, ndim=1] data = np.empty(elect.thermo.nSpecies()) - method(elect.plasmaElectron, &data[0]) - if elect._selected_species.size: - return data[elect._selected_species] - else: - return data - cdef class PlasmaElectron(_SolutionBase): """ This class is used to compute electron properties for a phase of matter. @@ -74,14 +66,6 @@ cdef class PlasmaElectron(_SolutionBase): def __get__(self): return self.plasmaElectron.inelasticPowerLoss() - property net_plasma_production_rates: - """ - Net plasma production rates for each species. [kmol/m^3/s] for bulk phases or - [kmol/m^2/s] for surface phases. - """ - def __get__(self): - return get_electron_1d(self, elect_getNetPlasmaProductionRates) - def set_chemionization_scattering_rate(self, rate): """ Set chemionization scattering-in rate """ self.plasmaElectron.setChemionScatRate(rate) From fdd617d95e7746a8de86b37ad16c90c8387a06f4 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 17 Jan 2020 13:20:20 -0500 Subject: [PATCH 079/139] [plasma] delete netPlasmaProductionRate --- include/cantera/plasma/PlasmaElectron.h | 5 ---- include/cantera/plasma/WeakIonGasElectron.h | 1 - src/plasma/WeakIonGasElectron.cpp | 28 --------------------- 3 files changed, 34 deletions(-) diff --git a/include/cantera/plasma/PlasmaElectron.h b/include/cantera/plasma/PlasmaElectron.h index 5d0c0ea5fbc..2ef0f58994e 100644 --- a/include/cantera/plasma/PlasmaElectron.h +++ b/include/cantera/plasma/PlasmaElectron.h @@ -109,11 +109,6 @@ class PlasmaElectron throw NotImplementedError("PlasmaElectron::reverseRateCoefficient"); } - //! net plasma production rates - virtual void getNetPlasmaProductionRates(double* wdot) { - throw NotImplementedError("PlasmaElectron::getNetPlasmaProductionRates"); - } - //! initialize PlasmaElectron. Need to be called after adding all cross sections. void init(thermo_t* thermo); diff --git a/include/cantera/plasma/WeakIonGasElectron.h b/include/cantera/plasma/WeakIonGasElectron.h index 98a422dd990..8772dae08b9 100644 --- a/include/cantera/plasma/WeakIonGasElectron.h +++ b/include/cantera/plasma/WeakIonGasElectron.h @@ -94,7 +94,6 @@ class WeakIonGasElectron: public PlasmaElectron virtual double totalCollisionFreq(); virtual double reverseRateCoefficient(size_t k); virtual double rateCoefficient(size_t k); - virtual void getNetPlasmaProductionRates(double* wdot); //! The real part of the mobility. This is used in power gain for case of AC. double realMobility(); diff --git a/src/plasma/WeakIonGasElectron.cpp b/src/plasma/WeakIonGasElectron.cpp index 5345e0af595..0ed5002fe6f 100644 --- a/src/plasma/WeakIonGasElectron.cpp +++ b/src/plasma/WeakIonGasElectron.cpp @@ -454,32 +454,4 @@ double WeakIonGasElectron::electronTemperature(Eigen::VectorXd f0) return 2./3. * 0.4 * sum / Boltzmann * ElectronCharge; } -void WeakIonGasElectron::getNetPlasmaProductionRates(double* wdot) -{ - calculateDistributionFunction(); - for (size_t k = 0; k < m_thermo->nSpecies(); k++) { - wdot[k] = 0.0; - } - size_t k_E = m_thermo->speciesIndex("E"); - if (k_E == npos) { - return; - } - double X_E = m_thermo->moleFraction("E"); - for (size_t k : m_kInelastic) { - size_t kr = m_thermo->speciesIndex(m_targets[k]); - size_t kp0 = m_kProducts[k][0]; - size_t kp1 = m_kProducts[k][1]; - if (kr != npos && kp0 != npos && kp1 != npos) { - double rate = m_N * m_N * m_moleFractions[k] * X_E * - rateCoefficient(k) / Avogadro; - wdot[kp0] += rate; - if (kp1 != 9999) { - wdot[kp1] += rate; - } - wdot[kr] -= rate; - wdot[k_E] += (m_inFactor[k] - 1) * rate; - } - } -} - } From ae5a36d5acb52f8fbc0ceadf6da703baca2c2e3c Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 18 Jan 2020 09:52:16 -0500 Subject: [PATCH 080/139] [plasma] move newElectronCrossSection and getElectronCrossSection to PlasmaElectronFactory --- include/cantera/plasma/ElectronCrossSection.h | 8 +--- .../cantera/plasma/PlasmaElectronFactory.h | 6 +++ src/plasma/ElectronCrossSection.cpp | 43 ------------------- src/plasma/PlasmaElectronFactory.cpp | 37 ++++++++++++++++ 4 files changed, 44 insertions(+), 50 deletions(-) diff --git a/include/cantera/plasma/ElectronCrossSection.h b/include/cantera/plasma/ElectronCrossSection.h index 45556bc3a86..e466a11030b 100644 --- a/include/cantera/plasma/ElectronCrossSection.h +++ b/include/cantera/plasma/ElectronCrossSection.h @@ -1,4 +1,4 @@ -//! @file ElectronCrossSection.h Declaration for class Cantera::Species. +//! @file ElectronCrossSection.h Declaration for class Cantera::ElectronCrossSection. // This file is part of Cantera. See License.txt in the top-level directory or // at https://www.cantera.org/license.txt for license and copyright information. @@ -51,12 +51,6 @@ class ElectronCrossSection AnyMap extra; }; -//! Create a new ElectronCrossSection object from an AnyMap specification -unique_ptr newElectronCrossSection(const AnyMap& node); - -//! Generate ElectronCrossSection objects for each item (an AnyMap) in `items`. -std::vector> getElectronCrossSection(const AnyValue& items); - } #endif diff --git a/include/cantera/plasma/PlasmaElectronFactory.h b/include/cantera/plasma/PlasmaElectronFactory.h index 43b6dd300f1..0f5cc4d6bc0 100644 --- a/include/cantera/plasma/PlasmaElectronFactory.h +++ b/include/cantera/plasma/PlasmaElectronFactory.h @@ -69,6 +69,12 @@ unique_ptr newPlasmaElectron(const AnyMap& phaseNode=AnyMap(), void addElectronCrossSections(PlasmaElectron& electron, const AnyValue& cross_section, const AnyValue& names); +//! Create a new ElectronCrossSection object from an AnyMap specification +unique_ptr newElectronCrossSection(const AnyMap& node); + +//! Generate ElectronCrossSection objects for each item (an AnyMap) in `items`. +std::vector> getElectronCrossSection(const AnyValue& items); + } #endif diff --git a/src/plasma/ElectronCrossSection.cpp b/src/plasma/ElectronCrossSection.cpp index 27fb06bd3d1..ee93d2b9b9d 100644 --- a/src/plasma/ElectronCrossSection.cpp +++ b/src/plasma/ElectronCrossSection.cpp @@ -2,12 +2,6 @@ // at https://www.cantera.org/license.txt for license and copyright information. #include "cantera/electron/ElectronCrossSection.h" -#include "cantera/base/stringUtils.h" -#include "cantera/base/ctexceptions.h" -#include "cantera/base/ctml.h" -#include -#include -#include namespace Cantera { @@ -53,41 +47,4 @@ void ElectronCrossSection::validate() } } -unique_ptr newElectronCrossSection(const AnyMap& node) -{ - unique_ptr ecs(new ElectronCrossSection()); - - ecs->kind = node["kind"].asString(); - ecs->target = node["target"].asString(); - ecs->data = node["data"].asVector(); - if (ecs->kind == "EFFECTIVE" || ecs->kind == "ELASTIC") { - ecs->mass_ratio = node["mass_ratio"].asDouble(); - } else { - ecs->threshold = node["threshold"].asDouble(); - ecs->product = node["product"].asString(); - } - - // Store all unparsed keys in the "extra" map - const static std::set known_keys{ - "kind", "target", "product", "data", "mass_ratio", "threshold" - }; - - for (const auto& item : node) { - if (known_keys.count(item.first) == 0) { - ecs->extra[item.first] = item.second; - } - } - - return ecs; -} - -std::vector> getElectronCrossSection(const AnyValue& items) -{ - std::vector > all_cross_sections; - for (const auto& node : items.asVector()) { - all_cross_sections.emplace_back(newElectronCrossSection(node)); - } - return all_cross_sections; -} - } diff --git a/src/plasma/PlasmaElectronFactory.cpp b/src/plasma/PlasmaElectronFactory.cpp index d65fad316cb..738e266e809 100644 --- a/src/plasma/PlasmaElectronFactory.cpp +++ b/src/plasma/PlasmaElectronFactory.cpp @@ -95,4 +95,41 @@ void addElectronCrossSections(PlasmaElectron& electron, const AnyValue& crossSec } } +unique_ptr newElectronCrossSection(const AnyMap& node) +{ + unique_ptr ecs(new ElectronCrossSection()); + + ecs->kind = node["kind"].asString(); + ecs->target = node["target"].asString(); + ecs->data = node["data"].asVector(); + if (ecs->kind == "EFFECTIVE" || ecs->kind == "ELASTIC") { + ecs->mass_ratio = node["mass_ratio"].asDouble(); + } else { + ecs->threshold = node["threshold"].asDouble(); + ecs->product = node["product"].asString(); + } + + // Store all unparsed keys in the "extra" map + const static std::set known_keys{ + "kind", "target", "product", "data", "mass_ratio", "threshold" + }; + + for (const auto& item : node) { + if (known_keys.count(item.first) == 0) { + ecs->extra[item.first] = item.second; + } + } + + return ecs; +} + +std::vector> getElectronCrossSection(const AnyValue& items) +{ + std::vector > all_cross_sections; + for (const auto& node : items.asVector()) { + all_cross_sections.emplace_back(newElectronCrossSection(node)); + } + return all_cross_sections; +} + } From 3dcd9e2ac6e2367c2acfc250b58a2d3bcc76321b Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 18 Jan 2020 19:41:47 -0500 Subject: [PATCH 081/139] [plasma-interface] delete mass_ratio but weird --- interfaces/cython/cantera/_cantera.pxd | 7 ++----- interfaces/cython/cantera/plasma.pyx | 12 +----------- src/plasma/ElectronCrossSection.cpp | 13 +------------ src/plasma/PlasmaElectron.cpp | 1 - src/plasma/PlasmaElectronFactory.cpp | 6 ++---- 5 files changed, 6 insertions(+), 33 deletions(-) diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 62472cde6f3..27c872857cf 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -142,17 +142,12 @@ cdef extern from "cantera/base/Solution.h" namespace "Cantera": cdef extern from "cantera/plasma/ElectronCrossSection.h" namespace "Cantera": cdef cppclass CxxElectronCrossSection "Cantera::ElectronCrossSection": CxxElectronCrossSection() - CxxElectronCrossSection(string, string, double, vector[double]) string kind string target - double mass_ratio string product vector[vector[double]] data - cdef shared_ptr[CxxElectronCrossSection] CxxNewElectronCrossSection "newElectronCrossSection" (CxxAnyMap&) except +translate_exception - cdef vector[shared_ptr[CxxElectronCrossSection]] CxxGetElectronCrossSection "getElectronCrossSection" (CxxAnyValue&) except +translate_exception - cdef extern from "cantera/plasma/PlasmaElectron.h" namespace "Cantera": cdef cppclass CxxPlasmaElectron "Cantera::PlasmaElectron": CxxPlasmaElectron() @@ -751,6 +746,8 @@ cdef extern from "cantera/thermo/ThermoFactory.h" namespace "Cantera": cdef extern from "cantera/plasma/PlasmaElectronFactory.h" namespace "Cantera": cdef shared_ptr[CxxPlasmaElectron] newPlasmaElectron(CxxAnyMap&, CxxAnyMap&, CxxThermoPhase*) except +translate_exception cdef CxxPlasmaElectron* newPlasmaElectron(string) except +translate_exception + cdef shared_ptr[CxxElectronCrossSection] CxxNewElectronCrossSection "newElectronCrossSection" (CxxAnyMap&) except +translate_exception + cdef vector[shared_ptr[CxxElectronCrossSection]] CxxGetElectronCrossSection "getElectronCrossSection" (CxxAnyValue&) except +translate_exception cdef extern from "cantera/kinetics/KineticsFactory.h" namespace "Cantera": cdef CxxKinetics* newKineticsMgr(XML_Node&, vector[CxxThermoPhase*]) except +translate_exception diff --git a/interfaces/cython/cantera/plasma.pyx b/interfaces/cython/cantera/plasma.pyx index 436e403b941..624139842b7 100644 --- a/interfaces/cython/cantera/plasma.pyx +++ b/interfaces/cython/cantera/plasma.pyx @@ -115,8 +115,6 @@ cdef class ElectronCrossSection: A string giving the kind of the collision, e.g. ``'EFFECTIVE'`` :param target: A string giving the target of the collision, e.g. ``'N2'`` - :param mass_ratio: - The mass ratio of electron to molecule. :param init: Used internally when wrapping :ct:`ElectronCrossSection` objects returned from C++ @@ -127,7 +125,7 @@ cdef class ElectronCrossSection: self._electron_cross_section.reset(new CxxElectronCrossSection()) self.electron_cross_section = self._electron_cross_section.get() - def __init__(self, kind=None, target=None, mass_ratio=None, data=None, + def __init__(self, kind=None, target=None, data=None, *args, init=True, **kwargs): if not init: return @@ -138,9 +136,6 @@ cdef class ElectronCrossSection: if target is not None: self.electron_cross_section.target = stringify(target) - if mass_ratio is not None: - self.electron_cross_section.mass_ratio = mass_ratio - if data is not None: self.electron_cross_section.data = data @@ -178,11 +173,6 @@ cdef class ElectronCrossSection: def __get__(self): return pystr(self.electron_cross_section.target) - property mass_ratio: - """ The mass ratio of electron to molecule. """ - def __get__(self): - return self.electron_cross_section.mass_ratio - property product: """ The product of the collision. """ def __get__(self): diff --git a/src/plasma/ElectronCrossSection.cpp b/src/plasma/ElectronCrossSection.cpp index ee93d2b9b9d..761c7bab2a3 100644 --- a/src/plasma/ElectronCrossSection.cpp +++ b/src/plasma/ElectronCrossSection.cpp @@ -6,8 +6,7 @@ namespace Cantera { ElectronCrossSection::ElectronCrossSection() - : mass_ratio(Undef) - , threshold(0.0) + : threshold(0.0) { } @@ -25,22 +24,12 @@ void ElectronCrossSection::validate() "Energy must starts at zero.", kind, target); } } - if (mass_ratio >= 1.0 || mass_ratio < 0.0) { - throw CanteraError("ElectronCrossSection::validate", - "Invalid mass ratio of type '{}' for '{}'. " - "Mass ratio of electron to target must be in the range of 0 to 1.", kind, target); - } } else if (kind == "ELASTIC") { if (data[0][0] != 0.0) { throw CanteraError("ElectronCrossSection::validate", "Invalid energy value of type '{}' for '{}'. " "Energy must starts at zero.", kind, target); } - if (mass_ratio >= 1.0 || mass_ratio < 0.0) { - throw CanteraError("ElectronCrossSection::validate", - "Invalid mass ratio of type '{}' for '{}'. " - "Mass ratio of electron to target must be in the range of 0 to 1.", kind, target); - } } else if (kind != "IONIZATION" && kind != "ATTACHMENT" && kind != "EXCITATION"){ throw CanteraError("ElectronCrossSection::validate", "'{}' is an unknown type of cross section data.", kind); diff --git a/src/plasma/PlasmaElectron.cpp b/src/plasma/PlasmaElectron.cpp index b51bf647afb..5bd2ef98ec3 100644 --- a/src/plasma/PlasmaElectron.cpp +++ b/src/plasma/PlasmaElectron.cpp @@ -189,7 +189,6 @@ bool PlasmaElectron::addElectronCrossSection(shared_ptr ec m_targets.push_back(ecs->target); m_kinds.push_back(ecs->kind); m_products.push_back(ecs->product); - m_massRatios.push_back(ecs->mass_ratio); m_thresholds.push_back(ecs->threshold); // transpose data diff --git a/src/plasma/PlasmaElectronFactory.cpp b/src/plasma/PlasmaElectronFactory.cpp index 738e266e809..a9b2a8961ad 100644 --- a/src/plasma/PlasmaElectronFactory.cpp +++ b/src/plasma/PlasmaElectronFactory.cpp @@ -102,16 +102,14 @@ unique_ptr newElectronCrossSection(const AnyMap& node) ecs->kind = node["kind"].asString(); ecs->target = node["target"].asString(); ecs->data = node["data"].asVector(); - if (ecs->kind == "EFFECTIVE" || ecs->kind == "ELASTIC") { - ecs->mass_ratio = node["mass_ratio"].asDouble(); - } else { + if (ecs->kind != "EFFECTIVE" && ecs->kind != "ELASTIC") { ecs->threshold = node["threshold"].asDouble(); ecs->product = node["product"].asString(); } // Store all unparsed keys in the "extra" map const static std::set known_keys{ - "kind", "target", "product", "data", "mass_ratio", "threshold" + "kind", "target", "product", "data", "threshold" }; for (const auto& item : node) { From f458ebc6b3ad86ec4be94a282881e9ed96046304 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 18 Jan 2020 20:05:35 -0500 Subject: [PATCH 082/139] [plasma, interface] delete chemIonRate --- include/cantera/plasma/WeakIonGasElectron.h | 8 -------- interfaces/cython/cantera/_cantera.pxd | 1 - interfaces/cython/cantera/plasma.pyx | 4 ---- 3 files changed, 13 deletions(-) diff --git a/include/cantera/plasma/WeakIonGasElectron.h b/include/cantera/plasma/WeakIonGasElectron.h index 8772dae08b9..044f44e623e 100644 --- a/include/cantera/plasma/WeakIonGasElectron.h +++ b/include/cantera/plasma/WeakIonGasElectron.h @@ -103,12 +103,6 @@ class WeakIonGasElectron: public PlasmaElectron //! from EEDF. virtual double electronTemperature(); - //! Set chemionization scattering-in rate - virtual void setChemionScatRate(double rate) { - m_chemionScatRate = rate; - m_f0_ok = false; - } - protected: //! Calculate distribution function by solving Boltzmann equation //! with two-term approximate method. @@ -190,8 +184,6 @@ class WeakIonGasElectron: public PlasmaElectron //! Reduced net production frequency. Equation (10) of ref. [1] //! divided by N. //! @param f0 EEDF - //! @param chem_rate Chemionization rate. This is an optional source of - //! electron. double netProductionFreq(Eigen::VectorXd& f0); //! electron temperature. For internal use only. This function is used to evaluate EEDF by diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 27c872857cf..026f8cf37df 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -169,7 +169,6 @@ cdef extern from "cantera/plasma/PlasmaElectron.h" namespace "Cantera": void setElectricField(double) void setElectricFieldFreq(double) double electronTemperature() - void setChemionScatRate(double) void setBoltzmannSolver(size_t, double, double, double, double, cbool) string target(size_t) string kind(size_t) diff --git a/interfaces/cython/cantera/plasma.pyx b/interfaces/cython/cantera/plasma.pyx index 624139842b7..ab072925d9c 100644 --- a/interfaces/cython/cantera/plasma.pyx +++ b/interfaces/cython/cantera/plasma.pyx @@ -66,10 +66,6 @@ cdef class PlasmaElectron(_SolutionBase): def __get__(self): return self.plasmaElectron.inelasticPowerLoss() - def set_chemionization_scattering_rate(self, rate): - """ Set chemionization scattering-in rate """ - self.plasmaElectron.setChemionScatRate(rate) - def set_boltzmann_solver(self, maxn=100, rtol=1e-5, delta0=1e14, m=4.0, init_kTe=0.0, warn=True): """ Set boltzmann solver""" From c9ef11a7f66a913d35b8060a72673b064c074a9c Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 18 Jan 2020 20:56:27 -0500 Subject: [PATCH 083/139] [interface] fix description of data of ElectronCrossSection --- interfaces/cython/cantera/plasma.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interfaces/cython/cantera/plasma.pyx b/interfaces/cython/cantera/plasma.pyx index ab072925d9c..9d25c421078 100644 --- a/interfaces/cython/cantera/plasma.pyx +++ b/interfaces/cython/cantera/plasma.pyx @@ -180,6 +180,6 @@ cdef class ElectronCrossSection: return self.target + " => " + self.product property data: - """ The mass ratio of electron to molecule. """ + """ The data of electron collision cross section. """ def __get__(self): return self.electron_cross_section.data From ec2aefcb7f93aef4cabe9846a2ba9e8f92148f6f Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 4 Apr 2020 23:26:52 -0400 Subject: [PATCH 084/139] change to weakly-ionized-gasin PlasmaElectronFactory.cpp --- data/inputs/oxygen_plasma.yaml | 2 +- src/plasma/PlasmaElectronFactory.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/inputs/oxygen_plasma.yaml b/data/inputs/oxygen_plasma.yaml index db89e0be3c5..47550a267cf 100644 --- a/data/inputs/oxygen_plasma.yaml +++ b/data/inputs/oxygen_plasma.yaml @@ -15,7 +15,7 @@ phases: state: T: 300.0 P: 1.01325e+05 - plasma: WeaklyIonizedGas + plasma: weakly-ionized-gas cross-sections: - oxygen_cross_sections.yaml/cross-sections: [O2] diff --git a/src/plasma/PlasmaElectronFactory.cpp b/src/plasma/PlasmaElectronFactory.cpp index a9b2a8961ad..f31d83fceed 100644 --- a/src/plasma/PlasmaElectronFactory.cpp +++ b/src/plasma/PlasmaElectronFactory.cpp @@ -21,7 +21,7 @@ std::mutex PlasmaElectronFactory::electron_mutex; PlasmaElectronFactory::PlasmaElectronFactory() { - reg("WeaklyIonizedGas", []() { return new WeakIonGasElectron(); }); + reg("weakly-ionized-gas", []() { return new WeakIonGasElectron(); }); } PlasmaElectron* PlasmaElectronFactory::newPlasmaElectron(const std::string& model) From 3889ec8069e6ec29ad2ae046d86c23f435d11441 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 5 Apr 2020 10:09:19 -0400 Subject: [PATCH 085/139] [plasma] fix ElectronCrossSection.cpp --- src/plasma/ElectronCrossSection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plasma/ElectronCrossSection.cpp b/src/plasma/ElectronCrossSection.cpp index 761c7bab2a3..47dbce0f302 100644 --- a/src/plasma/ElectronCrossSection.cpp +++ b/src/plasma/ElectronCrossSection.cpp @@ -1,7 +1,7 @@ // This file is part of Cantera. See License.txt in the top-level directory or // at https://www.cantera.org/license.txt for license and copyright information. -#include "cantera/electron/ElectronCrossSection.h" +#include "cantera/plasma/ElectronCrossSection.h" namespace Cantera { From 257d5e65cb770059b455e43fb94c566c188b32a6 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 7 Apr 2020 17:30:06 -0400 Subject: [PATCH 086/139] make plasma under thermo --- data/inputs/oxygen_plasma.yaml | 3 +- include/cantera/kinetics/GasKinetics.h | 10 -- include/cantera/kinetics/Kinetics.h | 13 -- include/cantera/plasma/ElectronCrossSection.h | 4 + include/cantera/plasma/PlasmaElectron.h | 16 +-- .../cantera/plasma/PlasmaElectronFactory.h | 80 ----------- include/cantera/plasma/WeakIonGasElectron.h | 4 + include/cantera/thermo/IdealGasPhase.h | 8 ++ include/cantera/thermo/Phase.h | 30 +++- include/cantera/thermo/ThermoPhase.h | 5 + include/cantera/transport/IonGasTransport.h | 11 -- include/cantera/transport/TransportBase.h | 6 - interfaces/cython/cantera/_cantera.pxd | 91 ++++++------ interfaces/cython/cantera/base.pyx | 35 +---- interfaces/cython/cantera/composite.py | 4 - interfaces/cython/cantera/kinetics.pyx | 7 - interfaces/cython/cantera/plasma.pyx | 52 +++---- .../cython/cantera/test/test_electron.py | 2 +- interfaces/cython/cantera/transport.pyx | 9 -- src/kinetics/GasKinetics.cpp | 6 +- src/kinetics/Kinetics.cpp | 6 - src/plasma/ElectronCrossSection.cpp | 35 +++++ src/plasma/PlasmaElectron.cpp | 96 +++++++++---- src/plasma/PlasmaElectronFactory.cpp | 133 ------------------ src/plasma/WeakIonGasElectron.cpp | 8 +- src/thermo/ThermoFactory.cpp | 3 + src/transport/IonGasTransport.cpp | 33 ++--- 27 files changed, 253 insertions(+), 457 deletions(-) delete mode 100644 include/cantera/plasma/PlasmaElectronFactory.h delete mode 100644 src/plasma/PlasmaElectronFactory.cpp diff --git a/data/inputs/oxygen_plasma.yaml b/data/inputs/oxygen_plasma.yaml index 47550a267cf..4cdf4fb4e6c 100644 --- a/data/inputs/oxygen_plasma.yaml +++ b/data/inputs/oxygen_plasma.yaml @@ -2,7 +2,7 @@ units: {length: cm, quantity: mol, activation-energy: K} phases: - name: gas - thermo: ideal-gas + thermo: weak-ionized-gas elements: [O, E] species: - species: [O2^+] @@ -15,7 +15,6 @@ phases: state: T: 300.0 P: 1.01325e+05 - plasma: weakly-ionized-gas cross-sections: - oxygen_cross_sections.yaml/cross-sections: [O2] diff --git a/include/cantera/kinetics/GasKinetics.h b/include/cantera/kinetics/GasKinetics.h index fe3bc673307..213199ee214 100644 --- a/include/cantera/kinetics/GasKinetics.h +++ b/include/cantera/kinetics/GasKinetics.h @@ -67,15 +67,8 @@ class GasKinetics : public BulkKinetics //! reactions. virtual void update_rates_C(); - //! enable kinetics to use class PlasmaElectron - virtual void enableElectron(bool enable) { - m_do_electron = enable; - } - //! Set the value of electron temperature in Kelvin. The electron temperature is equal //! to gas temperature by default, and can be set manually to a different temperature. - //! However, if m_do_electron is set to true, class PlasmaElectron is used to calculate - //! the value of electron temperature. virtual void setElectronTemperature(double Te) { m_Te_fix = Te; } @@ -125,9 +118,6 @@ class GasKinetics : public BulkKinetics //! Electron temperature for electron-temperature reactions double m_temp_e; - //! flag of enabling electrons - bool m_do_electron; - //! fixed value of electron temperature double m_Te_fix; diff --git a/include/cantera/kinetics/Kinetics.h b/include/cantera/kinetics/Kinetics.h index 2da5ad3fee6..2c95d26f75f 100644 --- a/include/cantera/kinetics/Kinetics.h +++ b/include/cantera/kinetics/Kinetics.h @@ -15,7 +15,6 @@ #include "StoichManager.h" #include "cantera/kinetics/Reaction.h" #include "cantera/base/global.h" -#include "cantera/plasma/PlasmaElectron.h" namespace Cantera { @@ -690,10 +689,6 @@ class Kinetics */ virtual void addPhase(thermo_t& thermo); - //! Add PlasmaElectron object for calculating electron temperature, and - //! reaction rate coefficients of plasma reactions. - virtual void addPlasmaElectron(PlasmaElectron* electron); - /** * Prepare the class for the addition of reactions, after all phases have * been added. This method is called automatically when the first reaction @@ -824,11 +819,6 @@ class Kinetics m_root = root; } - //! enable kinetics to use class PlasmaElectron - virtual void enableElectron(bool enable) { - throw NotImplementedError("Kinetics::enableElectron"); - } - //! set electron temperature virtual void setElectronTemperature(double Te) { throw NotImplementedError("Kinetics::setElectronTemperature"); @@ -908,9 +898,6 @@ class Kinetics */ std::vector m_thermo; - //! Plasmaelectron class - PlasmaElectron* m_electron; - /** * m_start is a vector of integers specifying the beginning position for the * species vector for the n'th phase in the kinetics class. diff --git a/include/cantera/plasma/ElectronCrossSection.h b/include/cantera/plasma/ElectronCrossSection.h index e466a11030b..ce3b1118beb 100644 --- a/include/cantera/plasma/ElectronCrossSection.h +++ b/include/cantera/plasma/ElectronCrossSection.h @@ -51,6 +51,10 @@ class ElectronCrossSection AnyMap extra; }; +unique_ptr newElectronCrossSection(const AnyMap& node); + +std::vector> getElectronCrossSection(const AnyValue& items); + } #endif diff --git a/include/cantera/plasma/PlasmaElectron.h b/include/cantera/plasma/PlasmaElectron.h index 2ef0f58994e..53c3233d33a 100644 --- a/include/cantera/plasma/PlasmaElectron.h +++ b/include/cantera/plasma/PlasmaElectron.h @@ -9,7 +9,7 @@ #ifndef CT_PLASMAELECTRON_H #define CT_PLASMAELECTRON_H -#include "cantera/thermo/ThermoPhase.h" +#include "cantera/thermo/IdealGasPhase.h" #include "cantera/plasma/ElectronCrossSection.h" #include "cantera/base/ctexceptions.h" #include "cantera/base/ValueCache.h" @@ -17,6 +17,7 @@ namespace Cantera { +unique_ptr newElectronCrossSection(const AnyMap& node); /** * @defgroup electron * This class calculates the electron energy distribution function (EEDF) in a gas @@ -31,16 +32,13 @@ namespace Cantera * cross-section data, and updating temperature and gas composition. * @ingroup electron */ -class PlasmaElectron +class PlasmaElectron: public IdealGasPhase { public: PlasmaElectron(); - virtual ~PlasmaElectron(); - - // Electron objects are not copyable or assignable - PlasmaElectron(const PlasmaElectron&) = delete; - PlasmaElectron& operator=(const PlasmaElectron&) = delete; + void addElectronCrossSections(const AnyValue& crossSections, + const AnyValue& names); //! Add an electron cross section to this Electron. Returns `true` if the electron cross section was //! successfully added, or `false` if the electron cross section was ignored. @@ -109,8 +107,8 @@ class PlasmaElectron throw NotImplementedError("PlasmaElectron::reverseRateCoefficient"); } - //! initialize PlasmaElectron. Need to be called after adding all cross sections. - void init(thermo_t* thermo); + //! initialize PlasmaElectron. + virtual void initPlasma(const AnyMap& phaseNode, const AnyMap& rootNode); //! Reduced electric field double electricField() const { diff --git a/include/cantera/plasma/PlasmaElectronFactory.h b/include/cantera/plasma/PlasmaElectronFactory.h deleted file mode 100644 index 0f5cc4d6bc0..00000000000 --- a/include/cantera/plasma/PlasmaElectronFactory.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @file PlasmaElectronFactory.h - * Headers for the factory class that can create known PlasmaElectron objects - */ - -// This file is part of Cantera. See License.txt in the top-level directory or -// at https://www.cantera.org/license.txt for license and copyright information. - -#ifndef PLASMAELECTRON_FACTORY_H -#define PLASMAELECTRON_FACTORY_H - -#include "cantera/plasma/PlasmaElectron.h" -#include "cantera/base/FactoryBase.h" - -namespace Cantera -{ -//! Factory class for plasmaelectron data managers. -/*! - * This class keeps a list of the known PlasmaElectron classes, and is - * used to create new instances of these classes. - */ -class PlasmaElectronFactory : public Factory -{ -public: - //! Static function that creates a static instance of the factory. - static PlasmaElectronFactory* factory() { - std::unique_lock lock(electron_mutex); - if (!s_factory) { - s_factory = new PlasmaElectronFactory; - } - return s_factory; - } - - //! delete the static instance of this factory - virtual void deleteFactory() { - std::unique_lock lock(electron_mutex); - delete s_factory; - s_factory = 0; - } - - virtual PlasmaElectron* newPlasmaElectron(const std::string& model); - -private: - //! static member of a single instance - static PlasmaElectronFactory* s_factory; - - //! Private constructors prevents usage - PlasmaElectronFactory(); - - //! Decl for locking mutex for thermo factory singleton - static std::mutex electron_mutex; -}; - -//! Create a new electron manager instance. -/*! - * @param model String to look up the model against - * @returns a pointer to a new PlasmaElectron instance matching the model string. - * Returns NULL if something went wrong. Throws an exception - * UnknownThermoPhaseModel if the string wasn't matched. - */ -inline PlasmaElectron* newPlasmaElectron(const std::string& model) -{ - return PlasmaElectronFactory::factory()->create(model); -} - -unique_ptr newPlasmaElectron(const AnyMap& phaseNode=AnyMap(), - const AnyMap& rootNode=AnyMap(), - thermo_t* phase = 0); - -void addElectronCrossSections(PlasmaElectron& electron, const AnyValue& cross_section, const AnyValue& names); - -//! Create a new ElectronCrossSection object from an AnyMap specification -unique_ptr newElectronCrossSection(const AnyMap& node); - -//! Generate ElectronCrossSection objects for each item (an AnyMap) in `items`. -std::vector> getElectronCrossSection(const AnyValue& items); - -} - -#endif diff --git a/include/cantera/plasma/WeakIonGasElectron.h b/include/cantera/plasma/WeakIonGasElectron.h index 044f44e623e..87f64a63830 100644 --- a/include/cantera/plasma/WeakIonGasElectron.h +++ b/include/cantera/plasma/WeakIonGasElectron.h @@ -85,6 +85,10 @@ class WeakIonGasElectron: public PlasmaElectron public: WeakIonGasElectron(); + virtual std::string type() const { + return "WeakIonizedGas"; + } + virtual double electronDiffusivity(); virtual double electronMobility(); virtual double meanElectronEnergy(); diff --git a/include/cantera/thermo/IdealGasPhase.h b/include/cantera/thermo/IdealGasPhase.h index e07f85f52cd..0abd2c57a35 100644 --- a/include/cantera/thermo/IdealGasPhase.h +++ b/include/cantera/thermo/IdealGasPhase.h @@ -602,6 +602,14 @@ class IdealGasPhase: public ThermoPhase virtual bool addSpecies(shared_ptr spec); virtual void setToEquilState(const doublereal* lambda_RT); + virtual double electronMobility() { + return Undef; + } + + virtual double electronDiffusivity() { + return Undef; + } + protected: //! Reference state pressure /*! diff --git a/include/cantera/thermo/Phase.h b/include/cantera/thermo/Phase.h index b125cbe88b6..2c77c954bd2 100644 --- a/include/cantera/thermo/Phase.h +++ b/include/cantera/thermo/Phase.h @@ -659,8 +659,20 @@ class Phase m_ndim = ndim; } - //! @name Thermodynamic Properties - //!@{ + //! Electron temperature (K) + virtual double electronTemperature() { + return m_electron_temp; + } + + //! Electron mobility + virtual double electronMobility() { + return Undef; + } + + //! Electron diffusivity + virtual double electronDiffusivity() { + return Undef; + } //! Temperature (K). //! @return The temperature of the phase @@ -719,6 +731,17 @@ class Phase throw NotImplementedError("Phase::setPressure"); } + //! Set the internally stored electron temperature of the phase (K). + //! @param temp Temperature in Kelvin + virtual void setElectronTemperature(const double e_temp) { + if (e_temp > 0) { + m_electron_temp = e_temp; + } else { + throw CanteraError("Phase::setElectronTemperature", + "temperature must be positive. T = {}", e_temp); + } + } + //! Set the internally stored temperature of the phase (K). //! @param temp Temperature in Kelvin virtual void setTemperature(const doublereal temp) { @@ -986,6 +1009,9 @@ class Phase //! determined from this variable rather than other way round. doublereal m_dens; + //! Electron temperature (K). + double m_electron_temp; + doublereal m_mmw; //!< mean molecular weight of the mixture (kg kmol-1) //! m_ym[k] = mole fraction of species k divided by the mean molecular diff --git a/include/cantera/thermo/ThermoPhase.h b/include/cantera/thermo/ThermoPhase.h index d49ded492be..81ae38eba01 100644 --- a/include/cantera/thermo/ThermoPhase.h +++ b/include/cantera/thermo/ThermoPhase.h @@ -1681,6 +1681,11 @@ class ThermoPhase : public Phase */ virtual void initThermo(); + //! Initialize plasma + virtual void initPlasma(const AnyMap& phaseNode, const AnyMap& rootNode) { + throw NotImplementedError("ThermoPhase::initPlasma"); + } + //! Set the equation of state parameters /*! * @internal The number and meaning of these depends on the subclass. diff --git a/include/cantera/transport/IonGasTransport.h b/include/cantera/transport/IonGasTransport.h index 46df7a70e4d..0b44f8134a2 100644 --- a/include/cantera/transport/IonGasTransport.h +++ b/include/cantera/transport/IonGasTransport.h @@ -57,8 +57,6 @@ class IonGasTransport : public MixTransport virtual void init(thermo_t* thermo, int mode, int log_level); - virtual void initElectron(PlasmaElectron* electron); - //! Viscosity of the mixture (kg/m/s). //! Only Neutral species contribute to Viscosity. virtual double viscosity(); @@ -86,10 +84,6 @@ class IonGasTransport : public MixTransport */ virtual double electricalConductivity(); - virtual void enableElectron(bool enable) { - m_do_electron = enable; - } - protected: //! setup parameters for n64 model void setupN64(); @@ -125,12 +119,7 @@ class IonGasTransport : public MixTransport //! polynomial of the collision integral for O2/O2- vector_fp m_om11_O2; - //! electron class - PlasmaElectron* m_electron; - double m_electronMobility; - - bool m_do_electron; }; } diff --git a/include/cantera/transport/TransportBase.h b/include/cantera/transport/TransportBase.h index 377f204e1bf..1726c2ea195 100644 --- a/include/cantera/transport/TransportBase.h +++ b/include/cantera/transport/TransportBase.h @@ -20,7 +20,6 @@ #define CT_TRANSPORTBASE_H #include "cantera/thermo/ThermoPhase.h" -#include "cantera/plasma/PlasmaElectron.h" namespace Cantera { @@ -660,11 +659,6 @@ class Transport m_root = root; } - //! initialize the Electron object. This method is overloaded in IonGasTtransport. - virtual void initElectron(PlasmaElectron* electron) {} - - virtual void enableElectron(bool enable) {} - protected: //! Enable the transport object for use. /*! diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 026f8cf37df..bc303c9549e 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -148,37 +148,8 @@ cdef extern from "cantera/plasma/ElectronCrossSection.h" namespace "Cantera": string product vector[vector[double]] data -cdef extern from "cantera/plasma/PlasmaElectron.h" namespace "Cantera": - cdef cppclass CxxPlasmaElectron "Cantera::PlasmaElectron": - CxxPlasmaElectron() - - #Properties - double grid(size_t) - size_t nPoints() - double electronMobility() - double electronDiffusivity() - double meanElectronEnergy() - double totalCollisionFreq() - double rateCoefficient(size_t) - double reverseRateCoefficient(size_t) - double powerGain() - double elasticPowerLoss() - double inelasticPowerLoss() - double electricField() - double electricFieldFreq() - void setElectricField(double) - void setElectricFieldFreq(double) - double electronTemperature() - void setBoltzmannSolver(size_t, double, double, double, double, cbool) - string target(size_t) - string kind(size_t) - string product(size_t) - double threshold(size_t) - - # initialization - cbool addElectronCrossSection(shared_ptr[CxxElectronCrossSection]) except +translate_exception - void setupGrid(size_t, double*) except +translate_exception - void init(CxxThermoPhase*) except +translate_exception + cdef shared_ptr[CxxElectronCrossSection] CxxNewElectronCrossSection "newElectronCrossSection" (CxxAnyMap&) except +translate_exception + cdef vector[shared_ptr[CxxElectronCrossSection]] CxxGetElectronCrossSection "getElectronCrossSection" (CxxAnyValue&) except +translate_exception cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera": ctypedef enum ThermoBasis: @@ -214,6 +185,7 @@ cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera": void modifySpecies(size_t, shared_ptr[CxxSpecies]) except +translate_exception void initThermo() except +translate_exception void invalidateCache() except +translate_exception + void initPlasma(CxxAnyMap&, CxxAnyMap&) except +translate_exception # basic thermodynamic properties double temperature() except +translate_exception @@ -322,7 +294,40 @@ cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera": double stoichAirFuelRatio(const double* fuelComp, const double* oxComp, ThermoBasis basis) except +translate_exception cdef extern from "cantera/thermo/IdealGasPhase.h": - cdef cppclass CxxIdealGasPhase "Cantera::IdealGasPhase" + cdef cppclass CxxIdealGasPhase "Cantera::IdealGasPhase": + CxxIdealGasPhase() + + +cdef extern from "cantera/plasma/PlasmaElectron.h": + cdef cppclass CxxPlasmaElectron "Cantera::PlasmaElectron": + CxxPlasmaElectron() + + #Properties + double grid(size_t) + size_t nPoints() + double electronMobility() + double electronDiffusivity() + double meanElectronEnergy() + double totalCollisionFreq() + double rateCoefficient(size_t) + double reverseRateCoefficient(size_t) + double powerGain() + double elasticPowerLoss() + double inelasticPowerLoss() + double electricField() + double electricFieldFreq() + void setElectricField(double) + void setElectricFieldFreq(double) + double electronTemperature() + void setBoltzmannSolver(size_t, double, double, double, double, cbool) + string target(size_t) + string kind(size_t) + string product(size_t) + double threshold(size_t) + + # initialization + cbool addElectronCrossSection(shared_ptr[CxxElectronCrossSection]) except +translate_exception + void setupGrid(size_t, double*) except +translate_exception cdef extern from "cantera/thermo/SurfPhase.h": @@ -469,7 +474,6 @@ cdef extern from "cantera/kinetics/Kinetics.h" namespace "Cantera": CxxThermoPhase& thermo(int) void addPhase(CxxThermoPhase&) except +translate_exception - void addPlasmaElectron(CxxPlasmaElectron*) except +translate_exception void init() except +translate_exception void skipUndeclaredThirdBodies(cbool) void addReaction(shared_ptr[CxxReaction]) except +translate_exception @@ -488,7 +492,6 @@ cdef extern from "cantera/kinetics/Kinetics.h" namespace "Cantera": double multiplier(int) void setMultiplier(int, double) void setElectronTemperature(double) - void enableElectron(cbool) except +translate_exception cdef extern from "cantera/kinetics/InterfaceKinetics.h": @@ -505,8 +508,6 @@ cdef extern from "cantera/transport/TransportBase.h" namespace "Cantera": double thermalConductivity() except +translate_exception double electricalConductivity() except +translate_exception void getSpeciesViscosities(double*) except +translate_exception - void initElectron(CxxPlasmaElectron*) except +translate_exception - void enableElectron(cbool) except +translate_exception cdef extern from "cantera/transport/DustyGasTransport.h" namespace "Cantera": @@ -742,12 +743,6 @@ cdef extern from "cantera/thermo/ThermoFactory.h" namespace "Cantera": cdef shared_ptr[CxxThermoPhase] newPhase(CxxAnyMap&, CxxAnyMap&) except +translate_exception cdef CxxThermoPhase* newThermoPhase(string) except +translate_exception -cdef extern from "cantera/plasma/PlasmaElectronFactory.h" namespace "Cantera": - cdef shared_ptr[CxxPlasmaElectron] newPlasmaElectron(CxxAnyMap&, CxxAnyMap&, CxxThermoPhase*) except +translate_exception - cdef CxxPlasmaElectron* newPlasmaElectron(string) except +translate_exception - cdef shared_ptr[CxxElectronCrossSection] CxxNewElectronCrossSection "newElectronCrossSection" (CxxAnyMap&) except +translate_exception - cdef vector[shared_ptr[CxxElectronCrossSection]] CxxGetElectronCrossSection "getElectronCrossSection" (CxxAnyValue&) except +translate_exception - cdef extern from "cantera/kinetics/KineticsFactory.h" namespace "Cantera": cdef CxxKinetics* newKineticsMgr(XML_Node&, vector[CxxThermoPhase*]) except +translate_exception cdef shared_ptr[CxxKinetics] newKinetics(vector[CxxThermoPhase*], CxxAnyMap&, CxxAnyMap&) except +translate_exception @@ -1001,9 +996,6 @@ cdef extern from "cantera/cython/wrappers.h": cdef void kin_getDestructionRates(CxxKinetics*, double*) except +translate_exception cdef void kin_getNetProductionRates(CxxKinetics*, double*) except +translate_exception - # PlasmaElectron - cdef void elect_getNetPlasmaProductionRates(CxxPlasmaElectron*, double*) except +translate_exception - # Transport properties cdef void tran_getMixDiffCoeffs(CxxTransport*, double*) except +translate_exception cdef void tran_getMixDiffCoeffsMass(CxxTransport*, double*) except +translate_exception @@ -1020,7 +1012,6 @@ ctypedef void (*thermoMethod1d)(CxxThermoPhase*, double*) except +translate_exce ctypedef void (*transportMethod1d)(CxxTransport*, double*) except +translate_exception ctypedef void (*transportMethod2d)(CxxTransport*, size_t, double*) except +translate_exception ctypedef void (*kineticsMethod1d)(CxxKinetics*, double*) except +translate_exception -ctypedef void (*plasmaElectronMethod1d)(CxxPlasmaElectron*, double*) except +translate_exception # classes cdef class ElectronCrossSection: @@ -1055,8 +1046,6 @@ cdef class _SolutionBase: cdef CxxKinetics* kinetics cdef shared_ptr[CxxTransport] _transport cdef CxxTransport* transport - cdef shared_ptr[CxxPlasmaElectron] _plasmaElectron - cdef CxxPlasmaElectron* plasmaElectron cdef int thermo_basis cdef np.ndarray _selected_species cdef object parent @@ -1073,6 +1062,9 @@ cdef class ThermoPhase(_SolutionBase): cdef class InterfacePhase(ThermoPhase): cdef CxxSurfPhase* surf +cdef class PlasmaPhase(ThermoPhase): + cdef CxxPlasmaElectron* plasma + cdef class Reaction: cdef shared_ptr[CxxReaction] _reaction cdef CxxReaction* reaction @@ -1089,9 +1081,6 @@ cdef class Falloff: cdef class Kinetics(_SolutionBase): pass -cdef class PlasmaElectron(_SolutionBase): - pass - cdef class InterfaceKinetics(Kinetics): pass diff --git a/interfaces/cython/cantera/base.pyx b/interfaces/cython/cantera/base.pyx index 0439ef72c2c..e49607aebc0 100644 --- a/interfaces/cython/cantera/base.pyx +++ b/interfaces/cython/cantera/base.pyx @@ -6,8 +6,7 @@ from collections import defaultdict as _defaultdict cdef class _SolutionBase: def __cinit__(self, infile='', name='', adjacent=(), origin=None, source=None, yaml=None, thermo=None, species=(), - kinetics=None, reactions=(), plasma_electron=None, - electron_cross_sections=(), efile=None, **kwargs): + kinetics=None, reactions=(), **kwargs): if 'phaseid' in kwargs: if name is not '': @@ -36,12 +35,9 @@ cdef class _SolutionBase: self.kinetics = other.kinetics self.transport = other.transport self._base = other._base - self._source = other._source - self.plasmaElectron = other.plasmaElectron self._thermo = other._thermo self._kinetics = other._kinetics self._transport = other._transport - self._plasmaElectron = other._plasmaElectron self.thermo_basis = other.thermo_basis self._selected_species = other._selected_species.copy() @@ -69,9 +65,6 @@ cdef class _SolutionBase: self.base.setThermo(self._thermo) self.base.setKinetics(self._kinetics) - if electron_cross_sections: - self._init_electron(plasma_electron, electron_cross_sections) - self._selected_species = np.ndarray(0, dtype=np.uint64) def __init__(self, *args, **kwargs): @@ -140,6 +133,10 @@ cdef class _SolutionBase: "'Solution' instead").format(type(self).__name__) raise NotImplementedError(msg) + # Plasma + if pystr(self.thermo.type()) in ("WeakIonizedGas"): + self.thermo.initPlasma(phaseNode, root) + # Kinetics cdef vector[CxxThermoPhase*] v cdef _SolutionBase phase @@ -154,13 +151,6 @@ cdef class _SolutionBase: else: self.kinetics = NULL - # Plasma - if isinstance(self, PlasmaElectron): - self._plasmaElectron = newPlasmaElectron(phaseNode, root, self.thermo) - self.plasmaElectron = self._plasmaElectron.get() - self.kinetics.addPlasmaElectron(self.plasmaElectron) - else: - self.plasmaElectron = NULL def _init_cti_xml(self, infile, name, adjacent, source): """ @@ -237,21 +227,6 @@ cdef class _SolutionBase: for reaction in reactions: self.kinetics.addReaction(reaction._reaction) - def _init_electron(self, plasma_electron, electron_cross_sections): - """ - Instantiate a new PlasmaElectron object. - """ - cdef ElectronCrossSection ecs - if isinstance(self, PlasmaElectron): - self.plasmaElectron = newPlasmaElectron(stringify(plasma_electron)) - self._plasmaElectron.reset(self.plasmaElectron) - for ecs in electron_cross_sections: - self.plasmaElectron.addElectronCrossSection(ecs._electron_cross_section) - self.plasmaElectron.init(self.thermo) - self.kinetics.addPlasmaElectron(self.plasmaElectron) - else: - self.plasmaElectron = NULL - def __getitem__(self, selection): copy = self.__class__(origin=self) if isinstance(selection, slice): diff --git a/interfaces/cython/cantera/composite.py b/interfaces/cython/cantera/composite.py index 2eaf2b7646b..b614bf67cc9 100644 --- a/interfaces/cython/cantera/composite.py +++ b/interfaces/cython/cantera/composite.py @@ -98,10 +98,6 @@ class Solution(ThermoPhase, Kinetics, Transport): __slots__ = () -class Plasma(ThermoPhase, Kinetics, Transport, PlasmaElectron): - __slots__ = () - - class Interface(InterfacePhase, InterfaceKinetics): """ Two-dimensional interfaces. diff --git a/interfaces/cython/cantera/kinetics.pyx b/interfaces/cython/cantera/kinetics.pyx index 92b0967569a..0359492caa8 100644 --- a/interfaces/cython/cantera/kinetics.pyx +++ b/interfaces/cython/cantera/kinetics.pyx @@ -389,13 +389,6 @@ cdef class Kinetics(_SolutionBase): def __get__(self): return - self.net_rates_of_progress * self.delta_enthalpy - property electron_temperature_reactions_enabled: - """ - enable calculation of electron temperature by solving Boltzmann equation - """ - def __set__(self, enable): - self.kinetics.enableElectron(enable) - cdef class InterfaceKinetics(Kinetics): """ diff --git a/interfaces/cython/cantera/plasma.pyx b/interfaces/cython/cantera/plasma.pyx index 9d25c421078..3e5184b6450 100644 --- a/interfaces/cython/cantera/plasma.pyx +++ b/interfaces/cython/cantera/plasma.pyx @@ -4,103 +4,103 @@ import warnings import weakref -cdef class PlasmaElectron(_SolutionBase): - """ - This class is used to compute electron properties for a phase of matter. - """ - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) +cdef class PlasmaPhase(ThermoPhase): + """ A class representing a plasma phase""" + def __cinit__(self, *args, **kwargs): + if pystr(self.thermo.type()) not in ("WeakIonizedGas"): + raise TypeError('Underlying ThermoPhase object is of the wrong type.') + self.plasma = (self.thermo) def set_electron_energy_grid(self, grid): """ Set the grid of cell boundary of electron energy [eV]""" cdef np.ndarray[np.double_t, ndim=1] data = \ np.ascontiguousarray(grid, dtype=np.double) - self.plasmaElectron.setupGrid(len(data), &data[0]) + self.plasma.setupGrid(len(data), &data[0]) property electron_temperature: """electron temperature""" def __get__(self): - return self.plasmaElectron.electronTemperature() + return self.plasma.electronTemperature() property electron_mobility: """electron mobility [m^2/V/s)]""" def __get__(self): - return self.plasmaElectron.electronMobility() + return self.plasma.electronMobility() property electron_diffusivity: """electron diffusivity [m^2/s]""" def __get__(self): - return self.plasmaElectron.electronDiffusivity() + return self.plasma.electronDiffusivity() property electron_total_collision_frequency: """electron total collision frequency""" def __get__(self): - return self.plasmaElectron.totalCollisionFreq() + return self.plasma.totalCollisionFreq() def electron_rate_coefficient(self, k): """rate coefficient of process k""" - return self.plasmaElectron.rateCoefficient(k) + return self.plasma.rateCoefficient(k) def electron_reverse_rate_coefficient(self, k): """reverse rate coefficient of process k""" - return self.plasmaElectron.reverseRateCoefficient(k) + return self.plasma.reverseRateCoefficient(k) property electron_power_gain: """ Electron power gain. [eV/s] """ def __get__(self): - return self.plasmaElectron.powerGain() + return self.plasma.powerGain() property electron_elastic_power_loss: """ Electron elastic power loss. [eV/s] """ def __get__(self): - return self.plasmaElectron.elasticPowerLoss() + return self.plasma.elasticPowerLoss() property electron_inelastic_power_loss: """ Electron inelastic power loss. [eV/s] """ def __get__(self): - return self.plasmaElectron.inelasticPowerLoss() + return self.plasma.inelasticPowerLoss() def set_boltzmann_solver(self, maxn=100, rtol=1e-5, delta0=1e14, m=4.0, init_kTe=0.0, warn=True): """ Set boltzmann solver""" - self.plasmaElectron.setBoltzmannSolver(maxn, rtol, delta0, m, init_kTe, warn) + self.plasma.setBoltzmannSolver(maxn, rtol, delta0, m, init_kTe, warn) property mean_electron_energy: """mean electron energy [eV]""" def __get__(self): - return self.plasmaElectron.meanElectronEnergy() + return self.plasma.meanElectronEnergy() property electric_field: """reduced electric field strength [V-m2]""" def __get__(self): - return self.plasmaElectron.electricField() + return self.plasma.electricField() def __set__(self, E): - self.plasmaElectron.setElectricField(E) + self.plasma.setElectricField(E) property electric_field_freq: """electric field freq [Hz]""" def __get__(self): - return self.plasmaElectron.electricFieldFreq() + return self.plasma.electricFieldFreq() def __set__(self, F): - self.plasmaElectron.setElectricFieldFreq(F) + self.plasma.setElectricFieldFreq(F) def electron_collision_target(self, k): - return pystr(self.plasmaElectron.target(k)) + return pystr(self.plasma.target(k)) def electron_collision_kind(self, k): - return pystr(self.plasmaElectron.kind(k)) + return pystr(self.plasma.kind(k)) def electron_collision_product(self,k): - return pystr(self.plasmaElectron.product(k)) + return pystr(self.plasma.product(k)) def electron_collision_threshold(self, k): - return self.plasmaElectron.threshold(k) + return self.plasma.threshold(k) cdef class ElectronCrossSection: diff --git a/interfaces/cython/cantera/test/test_electron.py b/interfaces/cython/cantera/test/test_electron.py index c6d71024684..23f7c624509 100644 --- a/interfaces/cython/cantera/test/test_electron.py +++ b/interfaces/cython/cantera/test/test_electron.py @@ -7,7 +7,7 @@ class TestElectron(utilities.CanteraTest): def setUp(self): - self.gas = ct.Plasma(infile='oxygen_plasma.yaml') + self.gas = ct.PlasmaPhase(infile='oxygen_plasma.yaml') def test_electron_properties(self): self.gas.TPX = 1000, ct.one_atm, 'O2:1.0, E:1e-10' diff --git a/interfaces/cython/cantera/transport.pyx b/interfaces/cython/cantera/transport.pyx index 4fa624f7595..e659a253ffc 100644 --- a/interfaces/cython/cantera/transport.pyx +++ b/interfaces/cython/cantera/transport.pyx @@ -144,8 +144,6 @@ cdef class Transport(_SolutionBase): model = 'None' self.transport = newTransportMgr(stringify(model), self.thermo) self._transport.reset(self.transport) - if self.plasmaElectron != NULL: - self.transport.initElectron(self.plasmaElectron) super().__init__(*args, **kwargs) self.base.setTransport(self._transport) @@ -233,13 +231,6 @@ cdef class Transport(_SolutionBase): def __get__(self): return get_transport_1d(self, tran_getMobilities) - property electron_transport_enabled: - """ - enable calculation of electron transport by solving Boltzmann equation - """ - def __set__(self, enable): - self.transport.enableElectron(enable) - cdef class DustyGasTransport(Transport): """ diff --git a/src/kinetics/GasKinetics.cpp b/src/kinetics/GasKinetics.cpp index a47c691158e..439226cbe2e 100644 --- a/src/kinetics/GasKinetics.cpp +++ b/src/kinetics/GasKinetics.cpp @@ -17,7 +17,6 @@ GasKinetics::GasKinetics(thermo_t* thermo) : m_logc_ref(0.0), m_logStandConc(0.0), m_pres(0.0), - m_do_electron(false), m_Te_fix(Undef) { } @@ -28,9 +27,8 @@ void GasKinetics::update_rates_T() double Te = T; if (m_Te_fix != Undef) { Te = m_Te_fix; - } - if (m_electron && m_do_electron) { - Te = m_electron->electronTemperature(); + } else if (thermo().electronTemperature() != Undef) { + Te = thermo().electronTemperature(); } double logTe = log(Te); doublereal P = thermo().pressure(); diff --git a/src/kinetics/Kinetics.cpp b/src/kinetics/Kinetics.cpp index 4c9d65a2521..a9f04c7d125 100644 --- a/src/kinetics/Kinetics.cpp +++ b/src/kinetics/Kinetics.cpp @@ -21,7 +21,6 @@ namespace Cantera Kinetics::Kinetics() : m_kk(0), m_thermo(0), - m_electron(0), m_surfphase(npos), m_rxnphase(npos), m_mindim(4), @@ -462,11 +461,6 @@ void Kinetics::addPhase(thermo_t& thermo) resizeSpecies(); } -void Kinetics::addPlasmaElectron(PlasmaElectron* electron) -{ - m_electron = electron; -} - void Kinetics::resizeSpecies() { m_kk = 0; diff --git a/src/plasma/ElectronCrossSection.cpp b/src/plasma/ElectronCrossSection.cpp index 47dbce0f302..aa74057b1d5 100644 --- a/src/plasma/ElectronCrossSection.cpp +++ b/src/plasma/ElectronCrossSection.cpp @@ -36,4 +36,39 @@ void ElectronCrossSection::validate() } } +unique_ptr newElectronCrossSection(const AnyMap& node) +{ + unique_ptr ecs(new ElectronCrossSection()); + + ecs->kind = node["kind"].asString(); + ecs->target = node["target"].asString(); + ecs->data = node["data"].asVector(); + if (ecs->kind != "EFFECTIVE" && ecs->kind != "ELASTIC") { + ecs->threshold = node["threshold"].asDouble(); + ecs->product = node["product"].asString(); + } + + // Store all unparsed keys in the "extra" map + const static std::set known_keys{ + "kind", "target", "product", "data", "threshold" + }; + + for (const auto& item : node) { + if (known_keys.count(item.first) == 0) { + ecs->extra[item.first] = item.second; + } + } + + return ecs; +} + +std::vector> getElectronCrossSection(const AnyValue& items) +{ + std::vector > all_cross_sections; + for (const auto& node : items.asVector()) { + all_cross_sections.emplace_back(newElectronCrossSection(node)); + } + return all_cross_sections; +} + } diff --git a/src/plasma/PlasmaElectron.cpp b/src/plasma/PlasmaElectron.cpp index 5bd2ef98ec3..f21fd62a096 100644 --- a/src/plasma/PlasmaElectron.cpp +++ b/src/plasma/PlasmaElectron.cpp @@ -38,45 +38,61 @@ PlasmaElectron::PlasmaElectron() m_gamma = pow(2.0 * ElectronCharge / ElectronMass, 0.5); } -PlasmaElectron::~PlasmaElectron() +void PlasmaElectron::initPlasma(const AnyMap& phaseNode, const AnyMap& rootNode) { -} + if (phaseNode.hasKey("cross-sections")) { + if (phaseNode["cross-sections"].is>()) { + // 'cross-sections' is a list of target species names to be added from the current + // file's 'cross-sections' section + addElectronCrossSections(phaseNode["cross-sections"], rootNode["cross-sections"]); + } else if (phaseNode["cross-sections"].is()) { + // 'cross-sections' is a keyword applicable to the current file's 'cross-sections' + // section + addElectronCrossSections(phaseNode["cross-sections"], rootNode["cross-sections"]); + } else if (phaseNode["cross-sections"].is>()) { + // Each item in 'cross-sections' is a map with one item, where the key is + // a section in another YAML file, and the value is a + // list of target species names to read from that section + for (const auto& crossSectionsNode : phaseNode["cross-sections"].asVector()) { + const std::string& source = crossSectionsNode.begin()->first; + const auto& names = crossSectionsNode.begin()->second; + const auto& slash = boost::ifind_last(source, "/"); + if (slash) { + // source is a different input file + std::string fileName(source.begin(), slash.begin()); + std::string node(slash.end(), source.end()); + AnyMap crossSections = AnyMap::fromYamlFile(fileName); + addElectronCrossSections(crossSections[node], names); + } else { + throw InputFileError("newPlasmaElectron", crossSectionsNode, + "Could not find species section named '{}'", source); + } + } + } else { + throw InputFileError("newPlasmaElectron", phaseNode["cross-sections"], + "Could not parse cross-sections declaration of type '{}'", + phaseNode["cross-sections"].type_str()); + } + } else if (rootNode.hasKey("cross-sections")) { + // By default, add all cross sections from the 'cross-sections' section + addElectronCrossSections(AnyValue("all"), rootNode["cross-sections"]); + } -void PlasmaElectron::init(thermo_t* thermo) -{ - m_thermo = thermo; m_f0_ok = false; calculateElasticCrossSection(); setGridCache(); // set up target index m_kTargets.resize(m_ncs); for (size_t k = 0; k < m_ncs; k++) { - m_kTargets[k] = m_thermo->speciesIndex(m_targets[k]); + m_kTargets[k] = speciesIndex(m_targets[k]); } // set up indices of species which has no cross-section data - for (size_t k = 0; k < m_thermo->nSpecies(); k++) { + for (size_t k = 0; k < nSpecies(); k++) { auto it = std::find(m_kTargets.begin(), m_kTargets.end(), k); if (it == m_kTargets.end()) { m_kOthers.push_back(k); } } - m_kProducts.clear(); - m_kProducts.resize(m_ncs); - for (size_t k = 0; k < m_ncs; k++) { - std::string prdct = m_products[k]; - size_t dp = prdct.find(" + "); - if (dp != npos) { - size_t kp0 = m_thermo->speciesIndex(prdct.substr(0, dp)); - prdct.erase(0, dp + 3); - size_t kp1 = m_thermo->speciesIndex(prdct); - m_kProducts[k].push_back(kp0); - m_kProducts[k].push_back(kp1); - } else { - size_t kp0 = m_thermo->speciesIndex(prdct); - m_kProducts[k].push_back(kp0); - m_kProducts[k].push_back(9999); - } - } m_moleFractions.resize(m_ncs, 0.0); } @@ -149,10 +165,10 @@ void PlasmaElectron::update_T() { // signal that temperature-dependent quantities will need to be recomputed // before use, and update the local temperature. - double kT = Boltzmann * m_thermo->temperature() / ElectronCharge; + double kT = Boltzmann * temperature() / ElectronCharge; if (m_kT != kT) { m_kT = kT; - m_N = m_thermo->pressure() / Boltzmann / m_thermo->temperature(); + m_N = pressure() / Boltzmann / temperature(); m_f0_ok = false; } } @@ -161,8 +177,8 @@ void PlasmaElectron::update_C() { // signal that concentration-dependent quantities will need to be recomputed // before use, and update the local mole fractions. - vector_fp X(m_thermo->nSpecies()); - m_thermo->getMoleFractions(&X[0]); + vector_fp X(nSpecies()); + getMoleFractions(&X[0]); for (size_t k = 0; k < m_ncs; k++) { size_t kk = m_kTargets[k]; if (m_moleFractions[k] != X[kk]) { @@ -176,7 +192,7 @@ void PlasmaElectron::update_C() writelog("Cantera::PlasmaElectron::update_C"); writelog("\n"); writelog("Warning: The mole fraction of species {} is more than 0.01", - m_thermo->speciesName(k)); + speciesName(k)); writelog(" but it has no data of cross section."); writelog("\n"); } @@ -238,6 +254,28 @@ bool PlasmaElectron::addElectronCrossSection(shared_ptr ec return true; } +void PlasmaElectron::addElectronCrossSections(const AnyValue& crossSections, const AnyValue& names) +{ + if (names.is>()) { + // 'names' is a list of target species names which should be found in 'cross-sections' + for (const auto& name : names.asVector()) { + for (const auto& item : crossSections.asVector()) { + if (item["target"].asString() == name) { + addElectronCrossSection(newElectronCrossSection(item)); + } + } + } + } else if (names.is() && names.asString() == "all") { + // The keyword 'all' means to add all cross-sections from this source + for (const auto& item : crossSections.asVector()) { + addElectronCrossSection(newElectronCrossSection(item)); + } + } else { + throw InputFileError("addElectronCrossSections", names, + "Could not parse cross-sections declaration of type '{}'", names.type_str()); + } +} + void PlasmaElectron::calculateElasticCrossSection() { for (size_t ke : m_kElastic) { diff --git a/src/plasma/PlasmaElectronFactory.cpp b/src/plasma/PlasmaElectronFactory.cpp deleted file mode 100644 index f31d83fceed..00000000000 --- a/src/plasma/PlasmaElectronFactory.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/** - * @file PlasmaElectronFactory.cpp - * Definitions for the factory class that can create known PlasmaElectron objects - */ - -// This file is part of Cantera. See License.txt in the top-level directory or -// at https://www.cantera.org/license.txt for license and copyright information. - -#include "cantera/plasma/PlasmaElectronFactory.h" -#include "cantera/plasma/PlasmaElectron.h" -#include "cantera/plasma/WeakIonGasElectron.h" - - -using namespace std; - -namespace Cantera -{ - -PlasmaElectronFactory* PlasmaElectronFactory::s_factory = 0; -std::mutex PlasmaElectronFactory::electron_mutex; - -PlasmaElectronFactory::PlasmaElectronFactory() -{ - reg("weakly-ionized-gas", []() { return new WeakIonGasElectron(); }); -} - -PlasmaElectron* PlasmaElectronFactory::newPlasmaElectron(const std::string& model) -{ - return create(model); -} - -unique_ptr newPlasmaElectron(const AnyMap& phaseNode, const AnyMap& rootNode, thermo_t* phase) -{ - unique_ptr electron(newPlasmaElectron(phaseNode["plasma"].asString())); - if (phaseNode.hasKey("cross-sections")) { - if (phaseNode["cross-sections"].is>()) { - // 'cross-sections' is a list of target species names to be added from the current - // file's 'cross-sections' section - addElectronCrossSections(*electron, phaseNode["cross-sections"], rootNode["cross-sections"]); - } else if (phaseNode["cross-sections"].is()) { - // 'cross-sections' is a keyword applicable to the current file's 'cross-sections' - // section - addElectronCrossSections(*electron, phaseNode["cross-sections"], rootNode["cross-sections"]); - } else if (phaseNode["cross-sections"].is>()) { - // Each item in 'cross-sections' is a map with one item, where the key is - // a section in another YAML file, and the value is a - // list of target species names to read from that section - for (const auto& crossSectionsNode : phaseNode["cross-sections"].asVector()) { - const string& source = crossSectionsNode.begin()->first; - const auto& names = crossSectionsNode.begin()->second; - const auto& slash = boost::ifind_last(source, "/"); - if (slash) { - // source is a different input file - std::string fileName(source.begin(), slash.begin()); - std::string node(slash.end(), source.end()); - AnyMap crossSections = AnyMap::fromYamlFile(fileName); - addElectronCrossSections(*electron, crossSections[node], names); - } else { - throw InputFileError("newPlasmaElectron", crossSectionsNode, - "Could not find species section named '{}'", source); - } - } - } else { - throw InputFileError("newPlasmaElectron", phaseNode["cross-sections"], - "Could not parse cross-sections declaration of type '{}'", - phaseNode["cross-sections"].type_str()); - } - } else if (rootNode.hasKey("cross-sections")) { - // By default, add all cross sections from the 'cross-sections' section - addElectronCrossSections(*electron, AnyValue("all"), rootNode["cross-sections"]); - } - electron->init(phase); - return electron; -} - -void addElectronCrossSections(PlasmaElectron& electron, const AnyValue& crossSections, const AnyValue& names) -{ - if (names.is>()) { - // 'names' is a list of target species names which should be found in 'cross-sections' - for (const auto& name : names.asVector()) { - for (const auto& item : crossSections.asVector()) { - if (item["target"].asString() == name) { - electron.addElectronCrossSection(newElectronCrossSection(item)); - } - } - } - } else if (names.is() && names.asString() == "all") { - // The keyword 'all' means to add all cross-sections from this source - for (const auto& item : crossSections.asVector()) { - electron.addElectronCrossSection(newElectronCrossSection(item)); - } - } else { - throw InputFileError("addElectronCrossSections", names, - "Could not parse cross-sections declaration of type '{}'", names.type_str()); - } -} - -unique_ptr newElectronCrossSection(const AnyMap& node) -{ - unique_ptr ecs(new ElectronCrossSection()); - - ecs->kind = node["kind"].asString(); - ecs->target = node["target"].asString(); - ecs->data = node["data"].asVector(); - if (ecs->kind != "EFFECTIVE" && ecs->kind != "ELASTIC") { - ecs->threshold = node["threshold"].asDouble(); - ecs->product = node["product"].asString(); - } - - // Store all unparsed keys in the "extra" map - const static std::set known_keys{ - "kind", "target", "product", "data", "threshold" - }; - - for (const auto& item : node) { - if (known_keys.count(item.first) == 0) { - ecs->extra[item.first] = item.second; - } - } - - return ecs; -} - -std::vector> getElectronCrossSection(const AnyValue& items) -{ - std::vector > all_cross_sections; - for (const auto& node : items.asVector()) { - all_cross_sections.emplace_back(newElectronCrossSection(node)); - } - return all_cross_sections; -} - -} diff --git a/src/plasma/WeakIonGasElectron.cpp b/src/plasma/WeakIonGasElectron.cpp index 0ed5002fe6f..f1238be17a8 100644 --- a/src/plasma/WeakIonGasElectron.cpp +++ b/src/plasma/WeakIonGasElectron.cpp @@ -50,7 +50,7 @@ void WeakIonGasElectron::calculateTotalElasticCrossSection() vector_fp& x = m_crossSections[k][0]; vector_fp& y = m_crossSections[k][1]; for (size_t i = 0; i < m_points; i++) { - double mass_ratio = ElectronMass / (Dalton * m_thermo->molecularWeight(m_kTargets[k])); + double mass_ratio = ElectronMass / (Dalton * molecularWeight(m_kTargets[k])); m_sigmaElastic[i] += 2.0 * mass_ratio * m_moleFractions[k] * linearInterp(m_gridEdge[i], x, y); } @@ -84,7 +84,7 @@ void WeakIonGasElectron::calculateDistributionFunction() double Te = electronTemperature(m_f0); // Evaluate the EEDF by comparing electron temperature to gas temperature, // and replace the EEDF with a Maxwellian distribution at gas temperature. - if (Te < m_thermo->temperature()) { + if (Te < temperature()) { for (size_t j = 0; j < m_points; j++) { m_f0(j) = 2.0 * pow(1.0/Pi, 0.5) * pow(m_kT, -3./2.) * std::exp(-m_gridCenter[j]/m_kT); @@ -438,8 +438,8 @@ double WeakIonGasElectron::meanElectronEnergy() double WeakIonGasElectron::electronTemperature() { double Te = 2./3. * meanElectronEnergy() / Boltzmann * ElectronCharge; - if (Te < m_thermo->temperature()) { - return m_thermo->temperature(); + if (Te < temperature()) { + return temperature(); } else { return Te; } diff --git a/src/thermo/ThermoFactory.cpp b/src/thermo/ThermoFactory.cpp index 1832095905d..30276e63def 100644 --- a/src/thermo/ThermoFactory.cpp +++ b/src/thermo/ThermoFactory.cpp @@ -38,6 +38,7 @@ #include "cantera/thermo/WaterSSTP.h" #include "cantera/thermo/BinarySolutionTabulatedThermo.h" #include "cantera/base/stringUtils.h" +#include "cantera/plasma/WeakIonGasElectron.h" using namespace std; @@ -94,6 +95,8 @@ ThermoFactory::ThermoFactory() addAlias("liquid-water-IAPWS95", "PureLiquidWater"); reg("binary-solution-tabulated", []() { return new BinarySolutionTabulatedThermo(); }); addAlias("binary-solution-tabulated", "BinarySolutionTabulatedThermo"); + reg("weak-ionized-gas", []() { return new WeakIonGasElectron(); }); + addAlias("weak-ionized-gas", "WeakIonizedGas"); } ThermoPhase* ThermoFactory::newThermoPhase(const std::string& model) diff --git a/src/transport/IonGasTransport.cpp b/src/transport/IonGasTransport.cpp index 518e68b871d..6e5f051f8ed 100644 --- a/src/transport/IonGasTransport.cpp +++ b/src/transport/IonGasTransport.cpp @@ -12,9 +12,7 @@ namespace Cantera { IonGasTransport::IonGasTransport() : m_kElectron(npos), - m_electron(NULL), - m_electronMobility(0.4), - m_do_electron(false) + m_electronMobility(0.4) { } @@ -87,11 +85,6 @@ void IonGasTransport::init(thermo_t* thermo, int mode, int log_level) } } -void IonGasTransport::initElectron(PlasmaElectron* electron) -{ - m_electron = electron; -} - double IonGasTransport::viscosity() { update_T(); @@ -360,10 +353,10 @@ void IonGasTransport::getMixDiffCoeffs(double* const d) } else { for (size_t k = 0; k < m_nsp; k++) { if (k == m_kElectron) { - if (m_electron && m_do_electron) { - d[m_kElectron] = m_electron->electronDiffusivity(); - } else { + if (m_thermo->electronDiffusivity() == Undef) { d[k] = m_electronMobility * m_kbt / ElectronCharge; + } else { + d[m_kElectron] = m_thermo->electronDiffusivity(); } } else { double sum2 = 0.0; @@ -400,10 +393,10 @@ void IonGasTransport::getMixDiffCoeffsMass(double* const d) } else { for (size_t k=0; kelectronDiffusivity(); - } else { + if (m_thermo->electronDiffusivity() == Undef) { d[k] = m_electronMobility * m_kbt / ElectronCharge; + } else { + d[m_kElectron] = m_thermo->electronDiffusivity(); } } else { double sum1 = 0.0; @@ -439,10 +432,10 @@ void IonGasTransport::getMixDiffCoeffsMole(double* const d) } else { for (size_t k = 0; k < m_nsp; k++) { if (k == m_kElectron) { - if (m_electron && m_do_electron) { - d[m_kElectron] = m_electron->electronDiffusivity(); - } else { + if (m_thermo->electronDiffusivity() == Undef) { d[k] = m_electronMobility * m_kbt / ElectronCharge; + } else { + d[m_kElectron] = m_thermo->electronDiffusivity(); } } else { double sum2 = 0.0; @@ -473,10 +466,10 @@ void IonGasTransport::getMobilities(double* const mobi) double p = m_thermo->pressure(); for (size_t k = 0; k < m_nsp; k++) { if (k == m_kElectron) { - if (m_electron && m_do_electron) { - mobi[k] = m_electron->electronMobility(); - } else { + if (m_thermo->electronMobility() == Undef) { mobi[k] = m_electronMobility; + } else { + mobi[k] = m_thermo->electronMobility(); } } else { mobi[k] = 0.0; From be67187c030a90482e8d9a006f824b5c9da1b2fe Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 11 Apr 2020 07:40:25 -0400 Subject: [PATCH 087/139] [interface] add description to property process --- interfaces/cython/cantera/plasma.pyx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interfaces/cython/cantera/plasma.pyx b/interfaces/cython/cantera/plasma.pyx index 3e5184b6450..1c0b3bf25d0 100644 --- a/interfaces/cython/cantera/plasma.pyx +++ b/interfaces/cython/cantera/plasma.pyx @@ -175,7 +175,10 @@ cdef class ElectronCrossSection: return pystr(self.electron_cross_section.product) property process: - """ The process of the collision. """ + """ The process of the collision. + Ex. "O2 => O2^+" (ionization) + "O2 => O + O" (dissociation) + "O2 => O2(a1)" (exitation)""" def __get__(self): return self.target + " => " + self.product From cb9b06cdf8cb5c9c726833e88513605612da3c88 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 11 Apr 2020 08:49:40 -0400 Subject: [PATCH 088/139] [interface] add description to plasmaReaction --- interfaces/cython/cantera/reaction.pyx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interfaces/cython/cantera/reaction.pyx b/interfaces/cython/cantera/reaction.pyx index c202e834496..80ec7649029 100644 --- a/interfaces/cython/cantera/reaction.pyx +++ b/interfaces/cython/cantera/reaction.pyx @@ -408,7 +408,8 @@ cdef class ElementaryReaction(Reaction): cdef class ElectronTemperatureReaction(ElementaryReaction): """ - A reaction with electron as reactant + A reaction which the rate coefficient depends on electron temperature. + This type of reaction is used in a plasma. """ reaction_type = ELECTRON_TEMPERATURE_RXN @@ -418,7 +419,7 @@ cdef class ElectronTemperatureReaction(ElementaryReaction): cdef class PlasmaReaction(ElementaryReaction): """ - A reaction with electron as reactant + A reaction which the rate coefficient is obtained by a plasma model. """ reaction_type = PLASMA_RXN From f7464330af8f67e584ab1d76eb748ba7d625a95e Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 11 Apr 2020 15:36:40 -0400 Subject: [PATCH 089/139] [plasma] delete unused member variables --- include/cantera/plasma/PlasmaElectron.h | 39 +++++-------------------- src/plasma/PlasmaElectron.cpp | 20 +++++-------- src/plasma/WeakIonGasElectron.cpp | 10 +++---- 3 files changed, 20 insertions(+), 49 deletions(-) diff --git a/include/cantera/plasma/PlasmaElectron.h b/include/cantera/plasma/PlasmaElectron.h index 53c3233d33a..d3177b55866 100644 --- a/include/cantera/plasma/PlasmaElectron.h +++ b/include/cantera/plasma/PlasmaElectron.h @@ -138,7 +138,7 @@ class PlasmaElectron: public IdealGasPhase //! target of a specific process std::string target(size_t k) { - return m_targets[k]; + return m_ecss[k]->target; } //! index of target @@ -148,27 +148,17 @@ class PlasmaElectron: public IdealGasPhase //! kind of a specific process std::string kind(size_t k) { - return m_kinds[k]; + return m_ecss[k]->kind; } //! product of a specific process std::string product(size_t k) { - return m_products[k]; - } - - //! index of the first product - size_t firstProductIndex(size_t k) { - return m_kProducts[k][0]; - } - - //! index of the second product - size_t secondProductIndex(size_t k) { - return m_kProducts[k][1]; + return m_ecss[k]->product; } //! threshold of a specific process double threshold(size_t k) { - return m_thresholds[k]; + return m_ecss[k]->threshold; } //! scattering-in factor @@ -228,6 +218,9 @@ class PlasmaElectron: public IdealGasPhase //! number of cross section sets size_t m_ncs; + //! array of cross-section object + std::vector> m_ecss; + //! Grid of electron energy (cell center) [eV] vector_fp m_gridCenter; @@ -271,9 +264,6 @@ class PlasmaElectron: public IdealGasPhase //! flag of electron energy distribution function bool m_f0_ok; - //! pointer to the object representing the phase - thermo_t* m_thermo; - //! Maximum number of iterations size_t m_maxn; @@ -308,21 +298,6 @@ class PlasmaElectron: public IdealGasPhase //! The energy boundaries of the overlap of cell i and j std::vector> m_eps; - //! list of targets of electron collision - std::vector m_targets; - - //! list of kinds of electron collision - std::vector m_kinds; - - //! list of products of electron collision - std::vector m_products; - - //! list of mass ratio of electron to target species - vector_fp m_massRatios; - - //! list of thresholds of electron collision - vector_fp m_thresholds; - //! cross section data. m_crossSections[i][j][k] where i is the specific process, //! j=0 is the vector of electron energy [eV], j=1 is the vector of cross section, and // k is the index of vector. diff --git a/src/plasma/PlasmaElectron.cpp b/src/plasma/PlasmaElectron.cpp index f21fd62a096..33589445405 100644 --- a/src/plasma/PlasmaElectron.cpp +++ b/src/plasma/PlasmaElectron.cpp @@ -84,7 +84,7 @@ void PlasmaElectron::initPlasma(const AnyMap& phaseNode, const AnyMap& rootNode) // set up target index m_kTargets.resize(m_ncs); for (size_t k = 0; k < m_ncs; k++) { - m_kTargets[k] = speciesIndex(m_targets[k]); + m_kTargets[k] = speciesIndex(target(k)); } // set up indices of species which has no cross-section data for (size_t k = 0; k < nSpecies(); k++) { @@ -111,7 +111,7 @@ void PlasmaElectron::setGridCache() vector_fp& y = m_crossSections[k][1]; vector_fp eps1(m_points + 1); for (size_t i = 0; i < m_points + 1; i++) { - eps1[i] = clip(m_shiftFactor[k] * m_gridEdge[i] + m_thresholds[k], + eps1[i] = clip(m_shiftFactor[k] * m_gridEdge[i] + threshold(k), m_gridEdge[0] + 1e-9, m_gridEdge[m_points] - 1e-9); } @@ -202,10 +202,7 @@ void PlasmaElectron::update_C() bool PlasmaElectron::addElectronCrossSection(shared_ptr ecs) { ecs->validate(); - m_targets.push_back(ecs->target); - m_kinds.push_back(ecs->kind); - m_products.push_back(ecs->product); - m_thresholds.push_back(ecs->threshold); + m_ecss.push_back(ecs); // transpose data std::vector transdata(2, vector_fp(ecs->data.size())); @@ -234,8 +231,8 @@ bool PlasmaElectron::addElectronCrossSection(shared_ptr ec if (ecs->kind == "EFFECTIVE" || ecs->kind == "ELASTIC") { for (size_t k = 0; k < m_ncs; k++) { - if (m_targets[k] == ecs->target) - if (m_kinds[k] == "ELASTIC" || m_kinds[k] == "EFFECTIVE") { + if (target(k) == ecs->target) + if (kind(k) == "ELASTIC" || kind(k) == "EFFECTIVE") { throw CanteraError("PlasmaElectron::addElectronCrossSection", "Already contains a data of EFFECTIVE/ELASTIC cross section for '{}'.", ecs->target); @@ -279,11 +276,10 @@ void PlasmaElectron::addElectronCrossSections(const AnyValue& crossSections, con void PlasmaElectron::calculateElasticCrossSection() { for (size_t ke : m_kElastic) { - if (m_kinds[ke] == "EFFECTIVE") { - // replace effective with elastic - m_kinds[ke] = "ELASTIC"; + if (kind(ke) == "EFFECTIVE") { + // substract inelastic from effective for (size_t k : m_kInelastic) { - if (m_targets[k] == m_targets[ke]) { + if (target(k) == target(ke)) { vector_fp& x = m_crossSections[k][0]; vector_fp& y = m_crossSections[k][1]; for (size_t i = 0; i < m_crossSections[ke][0].size(); i++) { diff --git a/src/plasma/WeakIonGasElectron.cpp b/src/plasma/WeakIonGasElectron.cpp index f1238be17a8..33f2ac28c7b 100644 --- a/src/plasma/WeakIonGasElectron.cpp +++ b/src/plasma/WeakIonGasElectron.cpp @@ -286,8 +286,8 @@ double WeakIonGasElectron::netProductionFreq(Eigen::VectorXd& f0) vector_fp g = vector_g(f0); for (size_t k = 0; k < m_ncs; k++) { - if (m_kinds[k] == "IONIZATION" || - m_kinds[k] == "ATTACHMENT") { + if (kind(k) == "IONIZATION" || + kind(k) == "ATTACHMENT") { SparseMat PQ = (matrix_Q(g, k) - matrix_P(g, k)) * m_moleFractions[k]; Eigen::VectorXd s = PQ * f0; for (size_t i = 0; i < m_points; i++) { @@ -380,7 +380,7 @@ double WeakIonGasElectron::totalCollisionFreq() double WeakIonGasElectron::biMaxwellFraction(size_t k) { - return 1.0 / (1 + exp(-m_thresholds[k] / m_kT)); + return 1.0 / (1 + exp(-threshold(k) / m_kT)); } double WeakIonGasElectron::inelasticPowerLoss() @@ -388,10 +388,10 @@ double WeakIonGasElectron::inelasticPowerLoss() calculateDistributionFunction(); double sum = 0.0; for (size_t k : m_kInelastic) { - if (m_kinds[k] == "EXCITATION") { + if (kind(k) == "EXCITATION") { double y_low = biMaxwellFraction(k); double y_up = 1.0 - y_low; - sum += m_thresholds[k] * m_moleFractions[k] * + sum += threshold(k) * m_moleFractions[k] * (y_low * rateCoefficient(k) - y_up * reverseRateCoefficient(k)); } From 51b44b28d39d28b5101b08a9bd58a69230c7e00b Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 11 Apr 2020 17:46:49 -0400 Subject: [PATCH 090/139] change to small letters for electron collision kind --- data/inputs/oxygen_cross_sections.yaml | 30 +++++++++++++------------- src/plasma/ElectronCrossSection.cpp | 8 +++---- src/plasma/PlasmaElectron.cpp | 14 ++++++------ src/plasma/WeakIonGasElectron.cpp | 6 +++--- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/data/inputs/oxygen_cross_sections.yaml b/data/inputs/oxygen_cross_sections.yaml index 0c936d38ead..d48a87af077 100644 --- a/data/inputs/oxygen_cross_sections.yaml +++ b/data/inputs/oxygen_cross_sections.yaml @@ -1,7 +1,7 @@ # Ref.: Itikawa, Y., 2009. Cross sections for electron collisions with oxygen molecules. Journal of Physical and Chemical Reference Data, 38(1), pp.1-20. cross-sections: - comment: Total Scattering - Table 1 of Itikawa (2009) - kind: EFFECTIVE + kind: effective target: O2 mass_ratio: 1.71e-05 data: @@ -69,7 +69,7 @@ cross-sections: - [1000.0, 2.08e-20] - comment: Vibrational Excitation - Table 4 & 5 of Itikawa (2009) equation: E + O2 => E + O2(v1) - kind: EXCITATION + kind: excitation product: O2(v1) target: O2 threshold: 0.19 @@ -96,7 +96,7 @@ cross-sections: - [15.0, 5.70e-22] - comment: Vibrational Excitation - Table 4 of Itikawa (2009) equation: E + O2 => E + O2(v2) - kind: EXCITATION + kind: excitation product: O2(v2) target: O2 threshold: 0.38 @@ -117,7 +117,7 @@ cross-sections: - [15.0, 1.50e-22] - comment: Vibrational Excitation - Table 4 of Itikawa (2009) equation: E + O2 => E + O2(v3) - kind: EXCITATION + kind: excitation product: O2(v3) target: O2 threshold: 0.6 @@ -131,7 +131,7 @@ cross-sections: - [15.0, 6.50e-23] - comment: Excitation of Electronic States - Table 7 of Itikawa (2009) equation: E + O2 => E + O2(a1) - kind: EXCITATION + kind: excitation product: O2(a1) target: O2 threshold: 0.977 @@ -144,7 +144,7 @@ cross-sections: - [20.0, 2.30e-22] - comment: Excitation of Electronic States - Table 7 of Itikawa (2009) equation: E + O2 => E + O2(a1) - kind: EXCITATION + kind: excitation product: O2(a1) target: O2 threshold: 0.977 @@ -157,7 +157,7 @@ cross-sections: - [20.0, 2.30e-22] - comment: Excitation of Electronic States - Table 7 of Itikawa (2009) equation: E + O2 => E + O2(b1) - kind: EXCITATION + kind: excitation product: O2(b1) target: O2 threshold: 1.627 @@ -170,7 +170,7 @@ cross-sections: - [20.0, 5.50e-23] - comment: Excitation of Electronic States - Table 8 of Itikawa (2009) equation: E + O2 => E + O2(A3) - kind: EXCITATION + kind: excitation product: O2(A3) target: O2 threshold: 4.34 @@ -182,7 +182,7 @@ cross-sections: - [30.0, 1.30e-22] - comment: Excitation of Electronic States - Table 8 of Itikawa (2009) equation: E + O2 => E + O2(AP) - kind: EXCITATION + kind: excitation product: O2(AP) target: O2 threshold: 4.262 @@ -194,7 +194,7 @@ cross-sections: - [30.0, 1.30e-22] - comment: Excitation of Electronic States - Table 8 of Itikawa (2009) equation: E + O2 => E + O2(c1) - kind: EXCITATION + kind: excitation product: O2(c1) target: O2 threshold: 4.050 @@ -206,7 +206,7 @@ cross-sections: - [30.0, 1.30e-22] - comment: Excitation of Electronic States - Table 9 of Itikawa (2009) equation: E + O2 => E + O2(B3) - kind: EXCITATION + kind: excitation product: O2(B3) target: O2 threshold: 6.12 @@ -218,7 +218,7 @@ cross-sections: - [50.0, 2.764e-21] - comment: Dissociative Attachment - Table 13 of Itikawa (2009) equation: E + O2 => O^- + O - kind: ATTACHMENT + kind: attachment product: O^- + O target: O2 threshold: 0.0 @@ -281,7 +281,7 @@ cross-sections: - [9.9, 3.52e-24] - comment: Total Dissociation for Neutral Products - Table 10 of Itikawa (2009) equation: E + O2 => E + 2 O - kind: EXCITATION + kind: excitation product: O + O target: O2 threshold: 5.58 @@ -302,7 +302,7 @@ cross-sections: - [198.5, 2.91e-21] - comment: Ionization - Table 11 of Itikawa (2009) equation: E + O2 => 2 E + O2^+ - kind: IONIZATION + kind: ionization product: O2^+ target: O2 threshold: 12.1 @@ -353,7 +353,7 @@ cross-sections: - [998.0, 5.97e-21] - comment: Ionization - Table 11 of Itikawa (2009) equation: E + O2 => 2 E + O + O^+ - kind: IONIZATION + kind: ionization product: O + O^+ target: O2 threshold: 19.5 diff --git a/src/plasma/ElectronCrossSection.cpp b/src/plasma/ElectronCrossSection.cpp index aa74057b1d5..2889117df35 100644 --- a/src/plasma/ElectronCrossSection.cpp +++ b/src/plasma/ElectronCrossSection.cpp @@ -16,7 +16,7 @@ ElectronCrossSection::~ElectronCrossSection() void ElectronCrossSection::validate() { - if (kind == "EFFECTIVE") { + if (kind == "effective") { if (data.size() > 0 && data[0].size() > 0) { if (data[0][0] != 0.0) { throw CanteraError("ElectronCrossSection::validate", @@ -24,13 +24,13 @@ void ElectronCrossSection::validate() "Energy must starts at zero.", kind, target); } } - } else if (kind == "ELASTIC") { + } else if (kind == "elastic") { if (data[0][0] != 0.0) { throw CanteraError("ElectronCrossSection::validate", "Invalid energy value of type '{}' for '{}'. " "Energy must starts at zero.", kind, target); } - } else if (kind != "IONIZATION" && kind != "ATTACHMENT" && kind != "EXCITATION"){ + } else if (kind != "ionization" && kind != "attachment" && kind != "excitation"){ throw CanteraError("ElectronCrossSection::validate", "'{}' is an unknown type of cross section data.", kind); } @@ -43,7 +43,7 @@ unique_ptr newElectronCrossSection(const AnyMap& node) ecs->kind = node["kind"].asString(); ecs->target = node["target"].asString(); ecs->data = node["data"].asVector(); - if (ecs->kind != "EFFECTIVE" && ecs->kind != "ELASTIC") { + if (ecs->kind != "effective" && ecs->kind != "elastic") { ecs->threshold = node["threshold"].asDouble(); ecs->product = node["product"].asString(); } diff --git a/src/plasma/PlasmaElectron.cpp b/src/plasma/PlasmaElectron.cpp index 33589445405..cd38608b8c4 100644 --- a/src/plasma/PlasmaElectron.cpp +++ b/src/plasma/PlasmaElectron.cpp @@ -214,27 +214,27 @@ bool PlasmaElectron::addElectronCrossSection(shared_ptr ec m_crossSections.push_back(transdata); // shift factor - if (ecs->kind == "IONIZATION") { + if (ecs->kind == "ionization") { m_shiftFactor.push_back(2); } else { m_shiftFactor.push_back(1); } // scattering-in factor - if (ecs->kind == "IONIZATION") { + if (ecs->kind == "ionization") { m_inFactor.push_back(2); - } else if (ecs->kind == "ATTACHMENT") { + } else if (ecs->kind == "attachment") { m_inFactor.push_back(0); } else { m_inFactor.push_back(1); } - if (ecs->kind == "EFFECTIVE" || ecs->kind == "ELASTIC") { + if (ecs->kind == "effective" || ecs->kind == "elastic") { for (size_t k = 0; k < m_ncs; k++) { if (target(k) == ecs->target) - if (kind(k) == "ELASTIC" || kind(k) == "EFFECTIVE") { + if (kind(k) == "elastic" || kind(k) == "effective") { throw CanteraError("PlasmaElectron::addElectronCrossSection", - "Already contains a data of EFFECTIVE/ELASTIC cross section for '{}'.", + "Already contains a data of effective/ELASTIC cross section for '{}'.", ecs->target); } } @@ -276,7 +276,7 @@ void PlasmaElectron::addElectronCrossSections(const AnyValue& crossSections, con void PlasmaElectron::calculateElasticCrossSection() { for (size_t ke : m_kElastic) { - if (kind(ke) == "EFFECTIVE") { + if (kind(ke) == "effective") { // substract inelastic from effective for (size_t k : m_kInelastic) { if (target(k) == target(ke)) { diff --git a/src/plasma/WeakIonGasElectron.cpp b/src/plasma/WeakIonGasElectron.cpp index 33f2ac28c7b..26163cddfe6 100644 --- a/src/plasma/WeakIonGasElectron.cpp +++ b/src/plasma/WeakIonGasElectron.cpp @@ -286,8 +286,8 @@ double WeakIonGasElectron::netProductionFreq(Eigen::VectorXd& f0) vector_fp g = vector_g(f0); for (size_t k = 0; k < m_ncs; k++) { - if (kind(k) == "IONIZATION" || - kind(k) == "ATTACHMENT") { + if (kind(k) == "ionization" || + kind(k) == "attachment") { SparseMat PQ = (matrix_Q(g, k) - matrix_P(g, k)) * m_moleFractions[k]; Eigen::VectorXd s = PQ * f0; for (size_t i = 0; i < m_points; i++) { @@ -388,7 +388,7 @@ double WeakIonGasElectron::inelasticPowerLoss() calculateDistributionFunction(); double sum = 0.0; for (size_t k : m_kInelastic) { - if (kind(k) == "EXCITATION") { + if (kind(k) == "excitation") { double y_low = biMaxwellFraction(k); double y_up = 1.0 - y_low; sum += threshold(k) * m_moleFractions[k] * From 24eedc37b05ac09fd4b69bb795624f414e7a15fe Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 12 Apr 2020 15:48:54 -0400 Subject: [PATCH 091/139] [plasma] directly use functions of thermo (delete update_T and update_C) --- include/cantera/plasma/PlasmaElectron.h | 12 ++++---- src/plasma/PlasmaElectron.cpp | 30 +++++-------------- src/plasma/WeakIonGasElectron.cpp | 39 +++++++++++++++++-------- 3 files changed, 41 insertions(+), 40 deletions(-) diff --git a/include/cantera/plasma/PlasmaElectron.h b/include/cantera/plasma/PlasmaElectron.h index d3177b55866..237af2e4dc8 100644 --- a/include/cantera/plasma/PlasmaElectron.h +++ b/include/cantera/plasma/PlasmaElectron.h @@ -202,15 +202,17 @@ class PlasmaElectron: public IdealGasPhase throw NotImplementedError("PlasmaElectron::setChemionScatRate"); } + //! Overload to signal updating electron energy density function. + virtual void setTemperature(const double temp); + protected: // set grid cache void setGridCache(); - //! update temperature-dependent properties - void update_T(); - - //! update composition-dependent properties - void update_C(); + //! Signal updating electron energy density function and + //! check gas comsition for any substantial species without + //! the cross-section data. + virtual void compositionChanged(); //! Calculate elastic cross section void calculateElasticCrossSection(); diff --git a/src/plasma/PlasmaElectron.cpp b/src/plasma/PlasmaElectron.cpp index cd38608b8c4..eb9b6cad9ad 100644 --- a/src/plasma/PlasmaElectron.cpp +++ b/src/plasma/PlasmaElectron.cpp @@ -93,7 +93,6 @@ void PlasmaElectron::initPlasma(const AnyMap& phaseNode, const AnyMap& rootNode) m_kOthers.push_back(k); } } - m_moleFractions.resize(m_ncs, 0.0); } void PlasmaElectron::setGridCache() @@ -161,34 +160,19 @@ void PlasmaElectron::setGridCache() } } -void PlasmaElectron::update_T() +void PlasmaElectron::setTemperature(const double temp) { - // signal that temperature-dependent quantities will need to be recomputed - // before use, and update the local temperature. - double kT = Boltzmann * temperature() / ElectronCharge; - if (m_kT != kT) { - m_kT = kT; - m_N = pressure() / Boltzmann / temperature(); - m_f0_ok = false; - } + Phase::setTemperature(temp); + m_f0_ok = false; } -void PlasmaElectron::update_C() +void PlasmaElectron::compositionChanged() { - // signal that concentration-dependent quantities will need to be recomputed - // before use, and update the local mole fractions. - vector_fp X(nSpecies()); - getMoleFractions(&X[0]); - for (size_t k = 0; k < m_ncs; k++) { - size_t kk = m_kTargets[k]; - if (m_moleFractions[k] != X[kk]) { - m_moleFractions[k] = X[kk]; - m_f0_ok = false; - } - } + Phase::compositionChanged(); + m_f0_ok = false; // warn that a specific species needs cross-section data. for (size_t k : m_kOthers) { - if (X[k] > 0.01) { + if (moleFraction(k) > 0.01) { writelog("Cantera::PlasmaElectron::update_C"); writelog("\n"); writelog("Warning: The mole fraction of species {} is more than 0.01", diff --git a/src/plasma/WeakIonGasElectron.cpp b/src/plasma/WeakIonGasElectron.cpp index 26163cddfe6..e9f5a223cf0 100644 --- a/src/plasma/WeakIonGasElectron.cpp +++ b/src/plasma/WeakIonGasElectron.cpp @@ -34,10 +34,12 @@ void WeakIonGasElectron::calculateTotalCrossSection() vector_fp& x = m_crossSections[k][0]; vector_fp& y = m_crossSections[k][1]; for (size_t i = 0; i < m_points; i++) { - m_totalCrossSectionCenter[i] += m_moleFractions[k] * linearInterp(m_gridCenter[i], x, y); + m_totalCrossSectionCenter[i] += moleFraction(m_kTargets[k]) * + linearInterp(m_gridCenter[i], x, y); } for (size_t i = 0; i < m_points + 1; i++) { - m_totalCrossSectionEdge[i] += m_moleFractions[k] * linearInterp(m_gridEdge[i], x, y); + m_totalCrossSectionEdge[i] += moleFraction(m_kTargets[k]) * + linearInterp(m_gridEdge[i], x, y); } } } @@ -51,7 +53,7 @@ void WeakIonGasElectron::calculateTotalElasticCrossSection() vector_fp& y = m_crossSections[k][1]; for (size_t i = 0; i < m_points; i++) { double mass_ratio = ElectronMass / (Dalton * molecularWeight(m_kTargets[k])); - m_sigmaElastic[i] += 2.0 * mass_ratio * m_moleFractions[k] * + m_sigmaElastic[i] += 2.0 * mass_ratio * moleFraction(m_kTargets[k]) * linearInterp(m_gridEdge[i], x, y); } } @@ -59,17 +61,29 @@ void WeakIonGasElectron::calculateTotalElasticCrossSection() void WeakIonGasElectron::calculateDistributionFunction() { - // check if T or C is changed - update_T(); - update_C(); - if (m_f0_ok) { + // Check temperature and update temperature-dependent variables. + double kT = Boltzmann * temperature() / ElectronCharge; + if (m_kT != kT) { + m_kT = kT; + m_f0_ok = false; + } + // Check density and update density-dependent properties + double N = molarDensity() * Avogadro; + if (m_N != N) { + m_N = N; + m_f0_ok = false; + } + + // Skip the calculation if the independent variables did not change. + // Note gas composition is automatically checked with compositionChanged(). + if (m_f0_ok == true) { return; } calculateTotalCrossSection(); calculateTotalElasticCrossSection(); - double kT = m_kT; + //! Use kTe for initial f0 if (m_init_kTe != 0.0) { kT = m_init_kTe; } @@ -232,7 +246,7 @@ Eigen::VectorXd WeakIonGasElectron::iterate(Eigen::VectorXd& f0, double delta) SparseMat PQ(m_points, m_points); vector_fp g = vector_g(f0); for (size_t k : m_kInelastic) { - PQ += (matrix_Q(g, k) - matrix_P(g, k)) * m_moleFractions[k]; + PQ += (matrix_Q(g, k) - matrix_P(g, k)) * moleFraction(m_kTargets[k]); } SparseMat A = matrix_A(f0); @@ -288,7 +302,8 @@ double WeakIonGasElectron::netProductionFreq(Eigen::VectorXd& f0) for (size_t k = 0; k < m_ncs; k++) { if (kind(k) == "ionization" || kind(k) == "attachment") { - SparseMat PQ = (matrix_Q(g, k) - matrix_P(g, k)) * m_moleFractions[k]; + SparseMat PQ = (matrix_Q(g, k) - matrix_P(g, k)) * + moleFraction(m_kTargets[k]); Eigen::VectorXd s = PQ * f0; for (size_t i = 0; i < m_points; i++) { nu += s[i]; @@ -373,7 +388,7 @@ double WeakIonGasElectron::totalCollisionFreq() { double sum = 0.0; for (size_t k = 0; k < m_ncs; k++) { - sum += m_moleFractions[k] * rateCoefficient(k); + sum += moleFraction(m_kTargets[k]) * rateCoefficient(k); } return sum * m_N; } @@ -391,7 +406,7 @@ double WeakIonGasElectron::inelasticPowerLoss() if (kind(k) == "excitation") { double y_low = biMaxwellFraction(k); double y_up = 1.0 - y_low; - sum += threshold(k) * m_moleFractions[k] * + sum += threshold(k) * moleFraction(m_kTargets[k]) * (y_low * rateCoefficient(k) - y_up * reverseRateCoefficient(k)); } From d098c0459e363876c66db3f9c368c3b38b754ac1 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 13 Apr 2020 12:58:51 -0400 Subject: [PATCH 092/139] [plasma] change class name --- data/inputs/oxygen_plasma.yaml | 2 +- .../{PlasmaElectron.h => PlasmaPhase.h} | 38 ++++++------- ...eakIonGasElectron.h => WeaklyIonizedGas.h} | 14 ++--- interfaces/cython/cantera/_cantera.pxd | 8 +-- interfaces/cython/cantera/plasma.pyx | 2 +- .../{PlasmaElectron.cpp => PlasmaPhase.cpp} | 28 +++++----- ...onGasElectron.cpp => WeaklyIonizedGas.cpp} | 55 +++++++++---------- src/thermo/ThermoFactory.cpp | 6 +- 8 files changed, 76 insertions(+), 77 deletions(-) rename include/cantera/plasma/{PlasmaElectron.h => PlasmaPhase.h} (88%) rename include/cantera/plasma/{WeakIonGasElectron.h => WeaklyIonizedGas.h} (96%) rename src/plasma/{PlasmaElectron.cpp => PlasmaPhase.cpp} (91%) rename src/plasma/{WeakIonGasElectron.cpp => WeaklyIonizedGas.cpp} (89%) diff --git a/data/inputs/oxygen_plasma.yaml b/data/inputs/oxygen_plasma.yaml index 4cdf4fb4e6c..065bd7589a8 100644 --- a/data/inputs/oxygen_plasma.yaml +++ b/data/inputs/oxygen_plasma.yaml @@ -2,7 +2,7 @@ units: {length: cm, quantity: mol, activation-energy: K} phases: - name: gas - thermo: weak-ionized-gas + thermo: weakly-ionized-gas elements: [O, E] species: - species: [O2^+] diff --git a/include/cantera/plasma/PlasmaElectron.h b/include/cantera/plasma/PlasmaPhase.h similarity index 88% rename from include/cantera/plasma/PlasmaElectron.h rename to include/cantera/plasma/PlasmaPhase.h index 237af2e4dc8..969889a981c 100644 --- a/include/cantera/plasma/PlasmaElectron.h +++ b/include/cantera/plasma/PlasmaPhase.h @@ -1,13 +1,13 @@ /** - * @file PlasmaElectron.h - * Header file for class PlasmaElectron. + * @file PlasmaPhase.h + * Header file for class PlasmaPhase. */ // This file is part of Cantera. See License.txt in the top-level directory or // at https://www.cantera.org/license.txt for license and copyright information. -#ifndef CT_PLASMAELECTRON_H -#define CT_PLASMAELECTRON_H +#ifndef CT_PLASMAPHASE_H +#define CT_PLASMAPHASE_H #include "cantera/thermo/IdealGasPhase.h" #include "cantera/plasma/ElectronCrossSection.h" @@ -28,14 +28,14 @@ unique_ptr newElectronCrossSection(const AnyMap& node); */ /*! - * Class PlasmaElectron is the base class which manages the grid and grid cache, + * Class Plasma is the base class which manages the grid and grid cache, * cross-section data, and updating temperature and gas composition. * @ingroup electron */ -class PlasmaElectron: public IdealGasPhase +class PlasmaPhase: public IdealGasPhase { public: - PlasmaElectron(); + PlasmaPhase(); void addElectronCrossSections(const AnyValue& crossSections, const AnyValue& names); @@ -65,49 +65,49 @@ class PlasmaElectron: public IdealGasPhase //! electron diffusivity virtual double electronDiffusivity() { - throw NotImplementedError("PlasmaElectron::electronDiffusivity"); + throw NotImplementedError("PlasmaPhase::electronDiffusivity"); } //! electron mobility virtual double electronMobility() { - throw NotImplementedError("PlasmaElectron::electronMobility"); + throw NotImplementedError("PlasmaPhase::electronMobility"); } //! mean electron energy virtual double meanElectronEnergy() { - throw NotImplementedError("PlasmaElectron::meanElectronEnergy"); + throw NotImplementedError("PlasmaPhase::meanElectronEnergy"); } virtual double powerGain() { - throw NotImplementedError("PlasmaElectron::powerGain"); + throw NotImplementedError("PlasmaPhase::powerGain"); } //! elastic power loss virtual double elasticPowerLoss() { - throw NotImplementedError("PlasmaElectron::elasticPowerLoss"); + throw NotImplementedError("PlasmaPhase::elasticPowerLoss"); } //! inelastic power loss virtual double inelasticPowerLoss() { - throw NotImplementedError("PlasmaElectron::inelasticPowerLoss"); + throw NotImplementedError("PlasmaPhase::inelasticPowerLoss"); } //! total collision frequency virtual double totalCollisionFreq() { - throw NotImplementedError("PlasmaElectron::totalCollisionFreq"); + throw NotImplementedError("PlasmaPhase::totalCollisionFreq"); } //! rate coefficient for the electron collision process. [m^3/s] virtual double rateCoefficient(size_t k) { - throw NotImplementedError("PlasmaElectron::rateCoefficient"); + throw NotImplementedError("PlasmaPhase::rateCoefficient"); } //! reverse rate coefficient for the electron collision process. [m^3/s] virtual double reverseRateCoefficient(size_t k) { - throw NotImplementedError("PlasmaElectron::reverseRateCoefficient"); + throw NotImplementedError("PlasmaPhase::reverseRateCoefficient"); } - //! initialize PlasmaElectron. + //! initialize Plasma. virtual void initPlasma(const AnyMap& phaseNode, const AnyMap& rootNode); //! Reduced electric field @@ -193,13 +193,13 @@ class PlasmaElectron: public IdealGasPhase //! Return electron temperature virtual double electronTemperature() { - throw NotImplementedError("PlasmaElectron::electronTemperature"); + throw NotImplementedError("PlasmaPhase::electronTemperature"); } //! Set chemionization scattering-in rate //! Equal to the reaction rate divided by gas and electron number density virtual void setChemionScatRate(double rate) { - throw NotImplementedError("PlasmaElectron::setChemionScatRate"); + throw NotImplementedError("PlasmaPhase::setChemionScatRate"); } //! Overload to signal updating electron energy density function. diff --git a/include/cantera/plasma/WeakIonGasElectron.h b/include/cantera/plasma/WeaklyIonizedGas.h similarity index 96% rename from include/cantera/plasma/WeakIonGasElectron.h rename to include/cantera/plasma/WeaklyIonizedGas.h index 87f64a63830..5b6f268157a 100644 --- a/include/cantera/plasma/WeakIonGasElectron.h +++ b/include/cantera/plasma/WeaklyIonizedGas.h @@ -1,15 +1,15 @@ /** - * @file WeakIonGasElectron.h - * Header file for class WeakIonGasElectron. + * @file WeaklyIonizedGas.h + * Header file for class WeaklyIonizedGas. */ // This file is part of Cantera. See License.txt in the top-level directory or // at https://www.cantera.org/license.txt for license and copyright information. -#ifndef CT_WEAKIONGASELECTRON_H -#define CT_WEAKIONGASELECTRON_H +#ifndef CT_WEAKLYIONIZEDGAS_H +#define CT_WEAKLYIONIZEDGAS_H -#include "cantera/plasma/PlasmaElectron.h" +#include "cantera/plasma/PlasmaPhase.h" #include namespace Cantera @@ -80,10 +80,10 @@ typedef Eigen::SparseMatrix SparseMat; * doi: https://doi.org/10.1051/0004-6361/201220465 * @ingroup electron */ -class WeakIonGasElectron: public PlasmaElectron +class WeaklyIonizedGas: public PlasmaPhase { public: - WeakIonGasElectron(); + WeaklyIonizedGas(); virtual std::string type() const { return "WeakIonizedGas"; diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index bc303c9549e..d37722c5038 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -298,9 +298,9 @@ cdef extern from "cantera/thermo/IdealGasPhase.h": CxxIdealGasPhase() -cdef extern from "cantera/plasma/PlasmaElectron.h": - cdef cppclass CxxPlasmaElectron "Cantera::PlasmaElectron": - CxxPlasmaElectron() +cdef extern from "cantera/plasma/PlasmaPhase.h": + cdef cppclass CxxPlasmaPhase "Cantera::PlasmaPhase": + CxxPlasmaPhase() #Properties double grid(size_t) @@ -1063,7 +1063,7 @@ cdef class InterfacePhase(ThermoPhase): cdef CxxSurfPhase* surf cdef class PlasmaPhase(ThermoPhase): - cdef CxxPlasmaElectron* plasma + cdef CxxPlasmaPhase* plasma cdef class Reaction: cdef shared_ptr[CxxReaction] _reaction diff --git a/interfaces/cython/cantera/plasma.pyx b/interfaces/cython/cantera/plasma.pyx index 1c0b3bf25d0..f4c2c8a1d55 100644 --- a/interfaces/cython/cantera/plasma.pyx +++ b/interfaces/cython/cantera/plasma.pyx @@ -9,7 +9,7 @@ cdef class PlasmaPhase(ThermoPhase): def __cinit__(self, *args, **kwargs): if pystr(self.thermo.type()) not in ("WeakIonizedGas"): raise TypeError('Underlying ThermoPhase object is of the wrong type.') - self.plasma = (self.thermo) + self.plasma = (self.thermo) def set_electron_energy_grid(self, grid): """ Set the grid of cell boundary of electron energy [eV]""" diff --git a/src/plasma/PlasmaElectron.cpp b/src/plasma/PlasmaPhase.cpp similarity index 91% rename from src/plasma/PlasmaElectron.cpp rename to src/plasma/PlasmaPhase.cpp index eb9b6cad9ad..8c7981b5772 100644 --- a/src/plasma/PlasmaElectron.cpp +++ b/src/plasma/PlasmaPhase.cpp @@ -1,7 +1,7 @@ // This file is part of Cantera. See License.txt in the top-level directory or // at https://www.cantera.org/license.txt for license and copyright information. -#include "cantera/plasma/PlasmaElectron.h" +#include "cantera/plasma/PlasmaPhase.h" #include "cantera/base/stringUtils.h" #include "cantera/base/ctexceptions.h" #include "cantera/base/ctml.h" @@ -12,7 +12,7 @@ namespace Cantera { -PlasmaElectron::PlasmaElectron() +PlasmaPhase::PlasmaPhase() : m_ncs(0) , m_points(200) , m_kT(Undef) @@ -38,7 +38,7 @@ PlasmaElectron::PlasmaElectron() m_gamma = pow(2.0 * ElectronCharge / ElectronMass, 0.5); } -void PlasmaElectron::initPlasma(const AnyMap& phaseNode, const AnyMap& rootNode) +void PlasmaPhase::initPlasma(const AnyMap& phaseNode, const AnyMap& rootNode) { if (phaseNode.hasKey("cross-sections")) { if (phaseNode["cross-sections"].is>()) { @@ -64,12 +64,12 @@ void PlasmaElectron::initPlasma(const AnyMap& phaseNode, const AnyMap& rootNode) AnyMap crossSections = AnyMap::fromYamlFile(fileName); addElectronCrossSections(crossSections[node], names); } else { - throw InputFileError("newPlasmaElectron", crossSectionsNode, + throw InputFileError("newPlasma", crossSectionsNode, "Could not find species section named '{}'", source); } } } else { - throw InputFileError("newPlasmaElectron", phaseNode["cross-sections"], + throw InputFileError("newPlasma", phaseNode["cross-sections"], "Could not parse cross-sections declaration of type '{}'", phaseNode["cross-sections"].type_str()); } @@ -95,7 +95,7 @@ void PlasmaElectron::initPlasma(const AnyMap& phaseNode, const AnyMap& rootNode) } } -void PlasmaElectron::setGridCache() +void PlasmaPhase::setGridCache() { m_sigma.clear(); m_sigma.resize(m_ncs); @@ -160,20 +160,20 @@ void PlasmaElectron::setGridCache() } } -void PlasmaElectron::setTemperature(const double temp) +void PlasmaPhase::setTemperature(const double temp) { Phase::setTemperature(temp); m_f0_ok = false; } -void PlasmaElectron::compositionChanged() +void PlasmaPhase::compositionChanged() { Phase::compositionChanged(); m_f0_ok = false; // warn that a specific species needs cross-section data. for (size_t k : m_kOthers) { if (moleFraction(k) > 0.01) { - writelog("Cantera::PlasmaElectron::update_C"); + writelog("Cantera::PlasmaPhase::update_C"); writelog("\n"); writelog("Warning: The mole fraction of species {} is more than 0.01", speciesName(k)); @@ -183,7 +183,7 @@ void PlasmaElectron::compositionChanged() } } -bool PlasmaElectron::addElectronCrossSection(shared_ptr ecs) +bool PlasmaPhase::addElectronCrossSection(shared_ptr ecs) { ecs->validate(); m_ecss.push_back(ecs); @@ -217,7 +217,7 @@ bool PlasmaElectron::addElectronCrossSection(shared_ptr ec for (size_t k = 0; k < m_ncs; k++) { if (target(k) == ecs->target) if (kind(k) == "elastic" || kind(k) == "effective") { - throw CanteraError("PlasmaElectron::addElectronCrossSection", + throw CanteraError("PlasmaPhase::addElectronCrossSection", "Already contains a data of effective/ELASTIC cross section for '{}'.", ecs->target); } @@ -235,7 +235,7 @@ bool PlasmaElectron::addElectronCrossSection(shared_ptr ec return true; } -void PlasmaElectron::addElectronCrossSections(const AnyValue& crossSections, const AnyValue& names) +void PlasmaPhase::addElectronCrossSections(const AnyValue& crossSections, const AnyValue& names) { if (names.is>()) { // 'names' is a list of target species names which should be found in 'cross-sections' @@ -257,7 +257,7 @@ void PlasmaElectron::addElectronCrossSections(const AnyValue& crossSections, con } } -void PlasmaElectron::calculateElasticCrossSection() +void PlasmaPhase::calculateElasticCrossSection() { for (size_t ke : m_kElastic) { if (kind(ke) == "effective") { @@ -279,7 +279,7 @@ void PlasmaElectron::calculateElasticCrossSection() } } -void PlasmaElectron::setupGrid(size_t n, const double* eps) +void PlasmaPhase::setupGrid(size_t n, const double* eps) { m_points = n-1; m_gridCenter.resize(n-1); diff --git a/src/plasma/WeakIonGasElectron.cpp b/src/plasma/WeaklyIonizedGas.cpp similarity index 89% rename from src/plasma/WeakIonGasElectron.cpp rename to src/plasma/WeaklyIonizedGas.cpp index e9f5a223cf0..0164c825061 100644 --- a/src/plasma/WeakIonGasElectron.cpp +++ b/src/plasma/WeaklyIonizedGas.cpp @@ -1,8 +1,7 @@ // This file is part of Cantera. See License.txt in the top-level directory or // at https://www.cantera.org/license.txt for license and copyright information. -#include "cantera/plasma/WeakIonGasElectron.h" -#include "cantera/plasma/PlasmaElectronFactory.h" +#include "cantera/plasma/WeaklyIonizedGas.h" #include "cantera/base/utilities.h" #include "cantera/numerics/funcs.h" #include @@ -21,12 +20,12 @@ double norm(const Eigen::VectorXd& f, const vector_fp& grid) return simpsonQuadrature(grid, p); } -WeakIonGasElectron::WeakIonGasElectron() +WeaklyIonizedGas::WeaklyIonizedGas() : m_chemionScatRate(0.0) { } -void WeakIonGasElectron::calculateTotalCrossSection() +void WeaklyIonizedGas::calculateTotalCrossSection() { m_totalCrossSectionCenter.assign(m_points, 0.0); m_totalCrossSectionEdge.assign(m_points + 1, 0.0); @@ -44,7 +43,7 @@ void WeakIonGasElectron::calculateTotalCrossSection() } } -void WeakIonGasElectron::calculateTotalElasticCrossSection() +void WeaklyIonizedGas::calculateTotalElasticCrossSection() { m_sigmaElastic.clear(); m_sigmaElastic.resize(m_points, 0.0); @@ -59,7 +58,7 @@ void WeakIonGasElectron::calculateTotalElasticCrossSection() } } -void WeakIonGasElectron::calculateDistributionFunction() +void WeaklyIonizedGas::calculateDistributionFunction() { // Check temperature and update temperature-dependent variables. double kT = Boltzmann * temperature() / ElectronCharge; @@ -108,7 +107,7 @@ void WeakIonGasElectron::calculateDistributionFunction() m_f0_ok = true; } -double WeakIonGasElectron::integralPQ(double a, double b, double u0, double u1, +double WeaklyIonizedGas::integralPQ(double a, double b, double u0, double u1, double g, double x0) { double A1; @@ -135,7 +134,7 @@ double WeakIonGasElectron::integralPQ(double a, double b, double u0, double u1, return c0 * A1 + c1 * A2; } -vector_fp WeakIonGasElectron::vector_g(Eigen::VectorXd& f0) +vector_fp WeaklyIonizedGas::vector_g(Eigen::VectorXd& f0) { vector_fp g(m_points, 0.0); g[0] = std::log(f0(1)/f0(0)) / (m_gridCenter[1] - m_gridCenter[0]); @@ -147,7 +146,7 @@ vector_fp WeakIonGasElectron::vector_g(Eigen::VectorXd& f0) return g; } -SparseMat WeakIonGasElectron::matrix_P(vector_fp& g, size_t k) +SparseMat WeaklyIonizedGas::matrix_P(vector_fp& g, size_t k) { std::vector tripletList; for (size_t n = 0; n < m_eps[k].size(); n++) { @@ -165,7 +164,7 @@ SparseMat WeakIonGasElectron::matrix_P(vector_fp& g, size_t k) return P; } -SparseMat WeakIonGasElectron::matrix_Q(vector_fp& g, size_t k) +SparseMat WeaklyIonizedGas::matrix_Q(vector_fp& g, size_t k) { std::vector tripletList; for (size_t n = 0; n < m_eps[k].size(); n++) { @@ -184,7 +183,7 @@ SparseMat WeakIonGasElectron::matrix_Q(vector_fp& g, size_t k) return Q; } -SparseMat WeakIonGasElectron::matrix_A(Eigen::VectorXd& f0) +SparseMat WeaklyIonizedGas::matrix_A(Eigen::VectorXd& f0) { vector_fp a0(m_points + 1); vector_fp a1(m_points + 1); @@ -241,7 +240,7 @@ SparseMat WeakIonGasElectron::matrix_A(Eigen::VectorXd& f0) return A + G; } -Eigen::VectorXd WeakIonGasElectron::iterate(Eigen::VectorXd& f0, double delta) +Eigen::VectorXd WeaklyIonizedGas::iterate(Eigen::VectorXd& f0, double delta) { SparseMat PQ(m_points, m_points); vector_fp g = vector_g(f0); @@ -269,7 +268,7 @@ Eigen::VectorXd WeakIonGasElectron::iterate(Eigen::VectorXd& f0, double delta) return f1; } -Eigen::VectorXd WeakIonGasElectron::converge(Eigen::VectorXd& f0) +Eigen::VectorXd WeaklyIonizedGas::converge(Eigen::VectorXd& f0) { double err0 = 0.0; double err1 = 0.0; @@ -291,10 +290,10 @@ Eigen::VectorXd WeakIonGasElectron::converge(Eigen::VectorXd& f0) } f0 = f1; } - throw CanteraError("WeakIonGasElectron::converge", "Convergence failed"); + throw CanteraError("WeaklyIonizedGas::converge", "Convergence failed"); } -double WeakIonGasElectron::netProductionFreq(Eigen::VectorXd& f0) +double WeaklyIonizedGas::netProductionFreq(Eigen::VectorXd& f0) { double nu = m_chemionScatRate; vector_fp g = vector_g(f0); @@ -313,7 +312,7 @@ double WeakIonGasElectron::netProductionFreq(Eigen::VectorXd& f0) return nu; } -double WeakIonGasElectron::electronDiffusivity() +double WeaklyIonizedGas::electronDiffusivity() { calculateDistributionFunction(); vector_fp y(m_points, 0.0); @@ -327,7 +326,7 @@ double WeakIonGasElectron::electronDiffusivity() return 1./3. * m_gamma * simpsonQuadrature(m_gridCenter, y) / m_N; } -double WeakIonGasElectron::electronMobility() +double WeaklyIonizedGas::electronMobility() { calculateDistributionFunction(); double nu = netProductionFreq(m_f0); @@ -343,7 +342,7 @@ double WeakIonGasElectron::electronMobility() return -1./3. * m_gamma * simpsonQuadrature(m_gridEdge, y) / m_N; } -double WeakIonGasElectron::realMobility() +double WeaklyIonizedGas::realMobility() { calculateDistributionFunction(); double nu = netProductionFreq(m_f0); @@ -360,7 +359,7 @@ double WeakIonGasElectron::realMobility() return -1./3. * m_gamma * simpsonQuadrature(m_gridEdge, y) / m_N; } -double WeakIonGasElectron::powerGain() +double WeaklyIonizedGas::powerGain() { if (m_F != 0.0) { return m_E * m_E * electronMobility(); @@ -369,7 +368,7 @@ double WeakIonGasElectron::powerGain() } } -double WeakIonGasElectron::elasticPowerLoss() +double WeaklyIonizedGas::elasticPowerLoss() { calculateDistributionFunction(); double sum = 0.0; @@ -384,7 +383,7 @@ double WeakIonGasElectron::elasticPowerLoss() return sum * m_N; } -double WeakIonGasElectron::totalCollisionFreq() +double WeaklyIonizedGas::totalCollisionFreq() { double sum = 0.0; for (size_t k = 0; k < m_ncs; k++) { @@ -393,12 +392,12 @@ double WeakIonGasElectron::totalCollisionFreq() return sum * m_N; } -double WeakIonGasElectron::biMaxwellFraction(size_t k) +double WeaklyIonizedGas::biMaxwellFraction(size_t k) { return 1.0 / (1 + exp(-threshold(k) / m_kT)); } -double WeakIonGasElectron::inelasticPowerLoss() +double WeaklyIonizedGas::inelasticPowerLoss() { calculateDistributionFunction(); double sum = 0.0; @@ -414,7 +413,7 @@ double WeakIonGasElectron::inelasticPowerLoss() return sum * m_N; } -double WeakIonGasElectron::rateCoefficient(size_t k) +double WeaklyIonizedGas::rateCoefficient(size_t k) { calculateDistributionFunction(); vector_fp g = vector_g(m_f0); @@ -427,7 +426,7 @@ double WeakIonGasElectron::rateCoefficient(size_t k) return sum; } -double WeakIonGasElectron::reverseRateCoefficient(size_t k) +double WeaklyIonizedGas::reverseRateCoefficient(size_t k) { calculateDistributionFunction(); vector_fp g = vector_g(m_f0); @@ -440,7 +439,7 @@ double WeakIonGasElectron::reverseRateCoefficient(size_t k) return sum; } -double WeakIonGasElectron::meanElectronEnergy() +double WeaklyIonizedGas::meanElectronEnergy() { calculateDistributionFunction(); double sum = 0; @@ -450,7 +449,7 @@ double WeakIonGasElectron::meanElectronEnergy() return 0.4 * sum; } -double WeakIonGasElectron::electronTemperature() +double WeaklyIonizedGas::electronTemperature() { double Te = 2./3. * meanElectronEnergy() / Boltzmann * ElectronCharge; if (Te < temperature()) { @@ -460,7 +459,7 @@ double WeakIonGasElectron::electronTemperature() } } -double WeakIonGasElectron::electronTemperature(Eigen::VectorXd f0) +double WeaklyIonizedGas::electronTemperature(Eigen::VectorXd f0) { double sum = 0; for (size_t i = 0; i < m_points - 1; i++) { diff --git a/src/thermo/ThermoFactory.cpp b/src/thermo/ThermoFactory.cpp index 30276e63def..532ab5a6e97 100644 --- a/src/thermo/ThermoFactory.cpp +++ b/src/thermo/ThermoFactory.cpp @@ -38,7 +38,7 @@ #include "cantera/thermo/WaterSSTP.h" #include "cantera/thermo/BinarySolutionTabulatedThermo.h" #include "cantera/base/stringUtils.h" -#include "cantera/plasma/WeakIonGasElectron.h" +#include "cantera/plasma/WeaklyIonizedGas.h" using namespace std; @@ -95,8 +95,8 @@ ThermoFactory::ThermoFactory() addAlias("liquid-water-IAPWS95", "PureLiquidWater"); reg("binary-solution-tabulated", []() { return new BinarySolutionTabulatedThermo(); }); addAlias("binary-solution-tabulated", "BinarySolutionTabulatedThermo"); - reg("weak-ionized-gas", []() { return new WeakIonGasElectron(); }); - addAlias("weak-ionized-gas", "WeakIonizedGas"); + reg("weakly-ionized-gas", []() { return new WeaklyIonizedGas(); }); + addAlias("weakly-ionized-gas", "WeaklyIonizedGas"); } ThermoPhase* ThermoFactory::newThermoPhase(const std::string& model) From 52fb35d0b24f7bfc74732f940b9a376bc35f592a Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 13 Apr 2020 16:00:50 -0400 Subject: [PATCH 093/139] [interface] fix listFromFile logic --- interfaces/cython/cantera/plasma.pyx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interfaces/cython/cantera/plasma.pyx b/interfaces/cython/cantera/plasma.pyx index f4c2c8a1d55..db6810f0c39 100644 --- a/interfaces/cython/cantera/plasma.pyx +++ b/interfaces/cython/cantera/plasma.pyx @@ -148,9 +148,11 @@ cdef class ElectronCrossSection: Directories on Cantera's input file path will be searched for the specified file. """ - if filename.lower().split('.')[-1] in ('yml', 'yaml'): + if filename.endswith('.yml') or filename.endswith('.yaml'): root = AnyMapFromYamlFile(stringify(filename)) cxx_electron_cross_section = CxxGetElectronCrossSection(root[stringify(section)]) + else: + raise ValueError("The file type must be yml or yaml") cross_section = [] for a in cxx_electron_cross_section: From abe66b6190e442b9bc9fb5299f07ebf666014bbc Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 13 Apr 2020 20:23:39 -0400 Subject: [PATCH 094/139] fix setupBoltzmannSolver and add setMoleFractionThreshold and setInitialMeanElectronEnergy --- include/cantera/plasma/PlasmaPhase.h | 30 +++++++++++++++++++------- interfaces/cython/cantera/_cantera.pxd | 4 +++- interfaces/cython/cantera/plasma.pyx | 26 ++++++++++++++++++---- src/plasma/PlasmaPhase.cpp | 4 ++-- 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/include/cantera/plasma/PlasmaPhase.h b/include/cantera/plasma/PlasmaPhase.h index 969889a981c..a188842437d 100644 --- a/include/cantera/plasma/PlasmaPhase.h +++ b/include/cantera/plasma/PlasmaPhase.h @@ -177,18 +177,31 @@ class PlasmaPhase: public IdealGasPhase * to reduce the error by a factor of m in each iteration. Larger m * means faster convergence but also has higher risk of encountering * numerical instabilities. - * @param init_kTe Initial electron mean energy in [eV]. Assume - * initial EEDF to be Maxwell-Boltzmann distribution at init_kTe. - * @param warn Flag of showing warning of insufficient cross section data. */ - void setBoltzmannSolver(size_t maxn, double rtol, double delta0, - double m, double init_kTe, bool warn) { + void setupBoltzmannSolver(size_t maxn, double rtol, + double delta0, double m) { m_maxn = maxn; m_rtol = rtol; m_delta0 = delta0; m_factorM = m; + } + + /** + * Set the threshold of mole fraction for showing warning of + * insufficient cross-section data. The warning will show if + * any substantial species whose mole fraction is higher than + * the threshold lack the cross-section data. + */ + void setMoleFractionThreshold(double fraction) { + m_moleFractionThreshold = fraction; + } + + /** + * Set initial mean electron energy in [eV]. Assume initial + * EEDF to be Maxwell-Boltzmann distribution at init_kTe. + */ + void setInitialMeanElectronEnergy(double init_kTe) { m_init_kTe = init_kTe; - m_warn = warn; } //! Return electron temperature @@ -282,8 +295,9 @@ class PlasmaPhase: public IdealGasPhase //! Initial electron mean energy double m_init_kTe; - //! Flag of warning of insufficient cross section data - bool m_warn; + //! The threshold of mole fraction for showing warning of + //! insufficient cross-section data. + double m_moleFractionThreshold; //! Gas number density double m_N; diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index d37722c5038..f6874e242ec 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -319,7 +319,9 @@ cdef extern from "cantera/plasma/PlasmaPhase.h": void setElectricField(double) void setElectricFieldFreq(double) double electronTemperature() - void setBoltzmannSolver(size_t, double, double, double, double, cbool) + void setupBoltzmannSolver(size_t, double, double, double) + void setMoleFractionThreshold(double) + void setInitialMeanElectronEnergy(double) string target(size_t) string kind(size_t) string product(size_t) diff --git a/interfaces/cython/cantera/plasma.pyx b/interfaces/cython/cantera/plasma.pyx index db6810f0c39..8afb2b9eab8 100644 --- a/interfaces/cython/cantera/plasma.pyx +++ b/interfaces/cython/cantera/plasma.pyx @@ -66,10 +66,28 @@ cdef class PlasmaPhase(ThermoPhase): def __get__(self): return self.plasma.inelasticPowerLoss() - def set_boltzmann_solver(self, maxn=100, rtol=1e-5, delta0=1e14, - m=4.0, init_kTe=0.0, warn=True): - """ Set boltzmann solver""" - self.plasma.setBoltzmannSolver(maxn, rtol, delta0, m, init_kTe, warn) + def setup_boltzmann_solver(self, maxn=100, rtol=1e-5, + delta0=1e14, m=4.0): + """ + Setup Boltzmann Equation solver. + :param maxn: + Maximum number of iterations + :param rtol: + Relative tolerance + :param delta0: + Initial value of the iteration parameter + :param m: + Reduction factor of error + """ + self.plasma.setupBoltzmannSolver(maxn, rtol, delta0, m) + + def set_mole_fraction_threshold(self, fraction): + """ Set mole fraction threshold. """ + self.plasma.setMoleFractionThreshold(fraction) + + def set_initial_mean_electron_energy(self, init_kTe): + """ Set initial mean electron energy. [eV]""" + self.plasma.setInitialMeanElectronEnergy(init_kTe) property mean_electron_energy: """mean electron energy [eV]""" diff --git a/src/plasma/PlasmaPhase.cpp b/src/plasma/PlasmaPhase.cpp index 8c7981b5772..65b60794d5f 100644 --- a/src/plasma/PlasmaPhase.cpp +++ b/src/plasma/PlasmaPhase.cpp @@ -24,7 +24,7 @@ PlasmaPhase::PlasmaPhase() , m_delta0(1e14) , m_factorM(4.0) , m_init_kTe(0.0) - , m_warn(true) + , m_moleFractionThreshold(0.01) { // default energy grid m_gridCenter.resize(m_points); @@ -172,7 +172,7 @@ void PlasmaPhase::compositionChanged() m_f0_ok = false; // warn that a specific species needs cross-section data. for (size_t k : m_kOthers) { - if (moleFraction(k) > 0.01) { + if (moleFraction(k) > m_moleFractionThreshold) { writelog("Cantera::PlasmaPhase::update_C"); writelog("\n"); writelog("Warning: The mole fraction of species {} is more than 0.01", From 412e166b6f6864296692558cd48e76d0db0f3941 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 13 Apr 2020 21:14:05 -0400 Subject: [PATCH 095/139] [interface] change to test_plasma --- .../cython/cantera/test/{test_electron.py => test_plasma.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename interfaces/cython/cantera/test/{test_electron.py => test_plasma.py} (98%) diff --git a/interfaces/cython/cantera/test/test_electron.py b/interfaces/cython/cantera/test/test_plasma.py similarity index 98% rename from interfaces/cython/cantera/test/test_electron.py rename to interfaces/cython/cantera/test/test_plasma.py index 23f7c624509..32797549c85 100644 --- a/interfaces/cython/cantera/test/test_electron.py +++ b/interfaces/cython/cantera/test/test_plasma.py @@ -5,7 +5,7 @@ import copy -class TestElectron(utilities.CanteraTest): +class TestPlasma(utilities.CanteraTest): def setUp(self): self.gas = ct.PlasmaPhase(infile='oxygen_plasma.yaml') From 807e987a740b5fa7b56b1664e4b3adf9972a90fd Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 19 Apr 2020 22:52:23 -0400 Subject: [PATCH 096/139] [kinetics, interface] update kinetics add PlasmaKinetics --- include/cantera/kinetics/GasKinetics.h | 25 +++------ include/cantera/kinetics/PlasmaKinetics.h | 62 ++++++++++++++++++++++ include/cantera/kinetics/RateCoeffMgr.h | 2 +- include/cantera/kinetics/Reaction.h | 4 +- include/cantera/kinetics/RxnRates.h | 64 ----------------------- interfaces/cython/cantera/_cantera.pxd | 4 +- interfaces/cython/cantera/kinetics.pyx | 4 -- src/kinetics/GasKinetics.cpp | 59 ++++++--------------- src/kinetics/KineticsFactory.cpp | 3 ++ src/kinetics/PlasmaKinetics.cpp | 60 +++++++++++++++++++++ src/kinetics/Reaction.cpp | 20 +++++-- src/kinetics/RxnRates.cpp | 4 -- 12 files changed, 169 insertions(+), 142 deletions(-) create mode 100644 include/cantera/kinetics/PlasmaKinetics.h create mode 100644 src/kinetics/PlasmaKinetics.cpp diff --git a/include/cantera/kinetics/GasKinetics.h b/include/cantera/kinetics/GasKinetics.h index 213199ee214..7c02f35ae08 100644 --- a/include/cantera/kinetics/GasKinetics.h +++ b/include/cantera/kinetics/GasKinetics.h @@ -67,12 +67,6 @@ class GasKinetics : public BulkKinetics //! reactions. virtual void update_rates_C(); - //! Set the value of electron temperature in Kelvin. The electron temperature is equal - //! to gas temperature by default, and can be set manually to a different temperature. - virtual void setElectronTemperature(double Te) { - m_Te_fix = Te; - } - protected: //! Reaction index of each falloff reaction std::vector m_fallindx; @@ -87,12 +81,6 @@ class GasKinetics : public BulkKinetics //! Rate expressions for falloff reactions at the high-pressure limit Rate1 m_falloff_high_rates; - //! Rate expressions for electron reactions - Rate1 m_electron_temperature_rates; - - //! Rate expressions for plasma reactions - Rate1 m_plasma_rates; - FalloffMgr m_falloffn; ThirdBodyCalc m_3b_concm; @@ -101,6 +89,9 @@ class GasKinetics : public BulkKinetics Rate1 m_plog_rates; Rate1 m_cheb_rates; + //! Rate expressions for electron reactions + Rate1 m_electron_temperature_rates; + //! @name Reaction rate data //!@{ doublereal m_logp_ref; @@ -118,21 +109,17 @@ class GasKinetics : public BulkKinetics //! Electron temperature for electron-temperature reactions double m_temp_e; - //! fixed value of electron temperature - double m_Te_fix; - void processFalloffReactions(); - void processPlasmaReactions(); void addElectronTemperatureReaction(ElectronTemperatureReaction& r); - void addPlasmaReaction(PlasmaReaction& r); + virtual void addPlasmaReaction(PlasmaReaction& r) { + throw NotImplementedError("GasKinetics::addPlasmaReaction"); + } void addThreeBodyReaction(ThreeBodyReaction& r); void addFalloffReaction(FalloffReaction& r); void addPlogReaction(PlogReaction& r); void addChebyshevReaction(ChebyshevReaction& r); - void modifyElectronTemperatureReaction(size_t i, ElectronTemperatureReaction& r); - void modifyPlasmaReaction(size_t i, PlasmaReaction& r); void modifyThreeBodyReaction(size_t i, ThreeBodyReaction& r); void modifyFalloffReaction(size_t i, FalloffReaction& r); void modifyPlogReaction(size_t i, PlogReaction& r); diff --git a/include/cantera/kinetics/PlasmaKinetics.h b/include/cantera/kinetics/PlasmaKinetics.h new file mode 100644 index 00000000000..75add494b93 --- /dev/null +++ b/include/cantera/kinetics/PlasmaKinetics.h @@ -0,0 +1,62 @@ +/** + * @file PlasmaKinetics.h + * @ingroup chemkinetics + */ + +// This file is part of Cantera. See License.txt in the top-level directory or +// at http://www.cantera.org/license.txt for license and copyright information. + +#ifndef CT_PLASMAKINETICS_H +#define CT_PLASMAKINETICS_H + +#include "GasKinetics.h" +#include "cantera/plasma/PlasmaPhase.h" + +namespace Cantera +{ + +/** + * Kinetics manager for elementary plasma-phase chemistry. + * @ingroup kinetics + */ +class PlasmaKinetics : public GasKinetics +{ +public: + //! @name Constructors and General Information + //! @{ + + //! Constructor. + /*! + * @param thermo Pointer to the gas ThermoPhase (optional) + */ + PlasmaKinetics(thermo_t* thermo = 0); + + virtual std::string kineticsType() const { + return "Plasma"; + } + + //! @} + //! @name Reaction Mechanism Setup Routines + //! @{ + virtual void init(); + //@} + + //! Update rates of the plasma reaction + virtual void update_rates_T(); + +protected: + virtual void addPlasmaReaction(PlasmaReaction& r); + + //! Reaction index of each plasma reaction + std::vector m_plasmaIndx; + + //! Process index of each plasma reaction; + std::vector m_plasmaProcessIndx; + + //! Pointer to the plasma phase + PlasmaPhase* m_plasma; +}; + +} + +#endif diff --git a/include/cantera/kinetics/RateCoeffMgr.h b/include/cantera/kinetics/RateCoeffMgr.h index 468884763c7..f52d7066cbf 100644 --- a/include/cantera/kinetics/RateCoeffMgr.h +++ b/include/cantera/kinetics/RateCoeffMgr.h @@ -70,7 +70,7 @@ class Rate1 } /** - * Similar as update(double, double, double*) but with an extra argument + * Similar to update(T, logT, values) but with an extra argument * (second argument) of electron temperature, and change logT to logTe. * This is used for plasma reactions where the electrons have a different * temperature. diff --git a/include/cantera/kinetics/Reaction.h b/include/cantera/kinetics/Reaction.h index 7fa06e87b6a..e158c00195c 100644 --- a/include/cantera/kinetics/Reaction.h +++ b/include/cantera/kinetics/Reaction.h @@ -110,8 +110,8 @@ class PlasmaReaction : public Reaction public: PlasmaReaction(); PlasmaReaction(const Composition& reactants, const Composition& products, - const PlasmaRate& rate); - PlasmaRate rate; + const std::map& process); + std::map process; }; //! A class for managing third-body efficiencies, including default values diff --git a/include/cantera/kinetics/RxnRates.h b/include/cantera/kinetics/RxnRates.h index dd628052933..da66dd2b426 100644 --- a/include/cantera/kinetics/RxnRates.h +++ b/include/cantera/kinetics/RxnRates.h @@ -126,14 +126,6 @@ class ElectronArrhenius /// @param E2 Activation energy in temperature units for electron temperature. Kelvin. ElectronArrhenius(double A, double b, double E1, double E2); - //! Update concentration-dependent parts of the rate coefficient. - /*! - * For this class, there are no concentration-dependent parts, so this - * method does nothing. - */ - void update_C(const double* c) { - } - /** * Update the value of the natural logarithm of the rate constant. */ @@ -178,62 +170,6 @@ class ElectronArrhenius double m_logA, m_b, m_E1, m_E2, m_A; }; -class PlasmaRate -{ -public: - PlasmaRate(); - - //! Update concentration-dependent parts of the rate coefficient. - /*! - * For this class, there are no concentration-dependent parts, so this - * method does nothing. - */ - void update_C(const double* c) { - } - - /** - * Update the value the rate constant. - * - * This function returns the actual value of the rate constant. It can be - * safely called for negative values of the pre-exponential factor. - * - * For this class, the rate constant is calculated from class PlasmaElectron - * instead of - */ - double updateRC(double logT, double recipT) const { - return NAN; - } - - //! Return the pre-exponential factor *A* (in m, kmol, s to powers depending - //! on the reaction order) - /*! - * For this class, there are no pre-exponential factor parts, so this - * method return nan. - */ - double preExponentialFactor() const { - return NAN; - } - - //! Return the temperature exponent *b* - /*! - * For this class, there are no temperature exponent parts, so this - * method return nan. - */ - double temperatureExponent() const { - return NAN; - } - - //! Return the activation energy divided by the gas constant (i.e. the - //! activation temperature) [K] - /*! - * For this class, there are no activation energy parts, so this - * method return nan. - */ - double activationEnergy_R() const { - return NAN; - } -}; - /** * An Arrhenius rate with coverage-dependent terms. * diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index f6874e242ec..9b200fc19c9 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -393,7 +393,8 @@ cdef extern from "cantera/kinetics/Reaction.h" namespace "Cantera": CxxElectronTemperatureReaction() cdef cppclass CxxPlasmaReaction "Cantera::PlasmaReaction" (CxxElementaryReaction): - CxxPlasmaReaction() + CxxPlasmaReaction() + stdmap[string,string] process cdef cppclass CxxThreeBodyReaction "Cantera::ThreeBodyReaction" (CxxElementaryReaction): CxxThreeBodyReaction() @@ -493,7 +494,6 @@ cdef extern from "cantera/kinetics/Kinetics.h" namespace "Cantera": double multiplier(int) void setMultiplier(int, double) - void setElectronTemperature(double) cdef extern from "cantera/kinetics/InterfaceKinetics.h": diff --git a/interfaces/cython/cantera/kinetics.pyx b/interfaces/cython/cantera/kinetics.pyx index 0359492caa8..d8a3f53e07a 100644 --- a/interfaces/cython/cantera/kinetics.pyx +++ b/interfaces/cython/cantera/kinetics.pyx @@ -253,10 +253,6 @@ cdef class Kinetics(_SolutionBase): data[k,i] = self.kinetics.productStoichCoeff(k,i) return data - def set_electron_temperature(self, Te): - self.kinetics.setElectronTemperature(Te) - - property forward_rates_of_progress: """ Forward rates of progress for the reactions. [kmol/m^3/s] for bulk diff --git a/src/kinetics/GasKinetics.cpp b/src/kinetics/GasKinetics.cpp index 439226cbe2e..2f6e15100b5 100644 --- a/src/kinetics/GasKinetics.cpp +++ b/src/kinetics/GasKinetics.cpp @@ -16,21 +16,13 @@ GasKinetics::GasKinetics(thermo_t* thermo) : m_logp_ref(0.0), m_logc_ref(0.0), m_logStandConc(0.0), - m_pres(0.0), - m_Te_fix(Undef) + m_pres(0.0) { } void GasKinetics::update_rates_T() { doublereal T = thermo().temperature(); - double Te = T; - if (m_Te_fix != Undef) { - Te = m_Te_fix; - } else if (thermo().electronTemperature() != Undef) { - Te = thermo().electronTemperature(); - } - double logTe = log(Te); doublereal P = thermo().pressure(); m_logStandConc = log(thermo().standardConcentration()); doublereal logT = log(T); @@ -51,13 +43,6 @@ void GasKinetics::update_rates_T() m_ROP_ok = false; } - if (T != m_temp || Te != m_temp_e) { - if (m_electron_temperature_rates.nReactions()) { - m_electron_temperature_rates.update(T, Te, logTe, m_rfn.data()); - m_ROP_ok = false; - } - } - if (T != m_temp || P != m_pres) { if (m_plog_rates.nReactions()) { m_plog_rates.update(T, logT, m_rfn.data()); @@ -69,9 +54,20 @@ void GasKinetics::update_rates_T() m_ROP_ok = false; } } + + double Te = thermo().electronTemperature(); + double logTe = log(Te); + + if (T != m_temp || Te != m_temp_e) { + if (m_electron_temperature_rates.nReactions()) { + m_electron_temperature_rates.update(T, Te, logTe, m_rfn.data()); + m_ROP_ok = false; + } + } + + m_temp_e = Te; m_pres = P; m_temp = T; - m_temp_e = Te; } void GasKinetics::update_rates_C() @@ -141,7 +137,6 @@ void GasKinetics::getEquilibriumConstants(doublereal* kc) // force an update of T-dependent properties, so that m_rkcn will // be updated before it is used next. m_temp = 0.0; - m_temp_e = 0.0; } void GasKinetics::processFalloffReactions() @@ -167,14 +162,6 @@ void GasKinetics::processFalloffReactions() } } -void GasKinetics::processPlasmaReactions() -{ - for (size_t i = 0; i < m_plasma_rates.nReactions(); i++) { - // m_ropf[m_plasmaIndx[i]] = ; - // m_rpor[m_plasmaIndx[i]] = ; - } -} - void GasKinetics::updateROP() { update_rates_C(); @@ -195,10 +182,6 @@ void GasKinetics::updateROP() processFalloffReactions(); } - if (m_plasma_rates.nReactions()) { - processPlasmaReactions(); - } - for (size_t i = 0; i < nReactions(); i++) { // Scale the forward rate coefficient by the perturbation factor m_ropf[i] *= m_perturb[i]; @@ -294,11 +277,6 @@ void GasKinetics::addElectronTemperatureReaction(ElectronTemperatureReaction& r) m_electron_temperature_rates.install(nReactions()-1, r.rate); } -void GasKinetics::addPlasmaReaction(PlasmaReaction& r) -{ - m_plasma_rates.install(nReactions()-1, r.rate); -} - void GasKinetics::addFalloffReaction(FalloffReaction& r) { // install high and low rate coeff calculators and extend the high and low @@ -379,7 +357,8 @@ void GasKinetics::modifyReaction(size_t i, shared_ptr rNew) modifyElectronTemperatureReaction(i, dynamic_cast(*rNew)); break; case PLASMA_RXN: - modifyPlasmaReaction(i, dynamic_cast(*rNew)); + throw CanteraError("GasKinetics::modifyReaction", + "{} reaction type cannot be modified", rNew->reaction_type); break; case FALLOFF_RXN: case CHEMACT_RXN: @@ -399,8 +378,8 @@ void GasKinetics::modifyReaction(size_t i, shared_ptr rNew) // invalidate all cached data m_ROP_ok = false; m_temp += 0.1234; - m_temp_e += 0.1234; m_pres += 0.1234; + m_temp_e += 0.1234; } void GasKinetics::modifyElectronTemperatureReaction(size_t i, ElectronTemperatureReaction& r) @@ -408,11 +387,6 @@ void GasKinetics::modifyElectronTemperatureReaction(size_t i, ElectronTemperatur m_electron_temperature_rates.replace(i, r.rate); } -void GasKinetics::modifyPlasmaReaction(size_t i, PlasmaReaction& r) -{ - m_plasma_rates.replace(i, r.rate); -} - void GasKinetics::modifyThreeBodyReaction(size_t i, ThreeBodyReaction& r) { m_rates.replace(i, r.rate); @@ -446,6 +420,7 @@ void GasKinetics::invalidateCache() { BulkKinetics::invalidateCache(); m_pres += 0.13579; + m_temp_e += 0.13579; } } diff --git a/src/kinetics/KineticsFactory.cpp b/src/kinetics/KineticsFactory.cpp index 998c9b10b51..12dce365bac 100644 --- a/src/kinetics/KineticsFactory.cpp +++ b/src/kinetics/KineticsFactory.cpp @@ -7,6 +7,7 @@ #include "cantera/kinetics/KineticsFactory.h" #include "cantera/kinetics/GasKinetics.h" +#include "cantera/kinetics/PlasmaKinetics.h" #include "cantera/kinetics/InterfaceKinetics.h" #include "cantera/kinetics/EdgeKinetics.h" #include "cantera/kinetics/importKinetics.h" @@ -44,6 +45,8 @@ KineticsFactory::KineticsFactory() { addAlias("gas", "gaskinetics"); reg("surface", []() { return new InterfaceKinetics(); }); addAlias("surface", "interface"); + reg("plasma", []() { return new PlasmaKinetics(); }); + addAlias("plasma", "plasmakinetics"); reg("edge", []() { return new EdgeKinetics(); }); } diff --git a/src/kinetics/PlasmaKinetics.cpp b/src/kinetics/PlasmaKinetics.cpp new file mode 100644 index 00000000000..288549b7cd4 --- /dev/null +++ b/src/kinetics/PlasmaKinetics.cpp @@ -0,0 +1,60 @@ +/** + * @file PlasmaKinetics.cpp Homogeneous kinetics in ideal gases + */ + +// This file is part of Cantera. See License.txt in the top-level directory or +// at http://www.cantera.org/license.txt for license and copyright information. + +#include "cantera/kinetics/PlasmaKinetics.h" + +using namespace std; + +namespace Cantera +{ +PlasmaKinetics::PlasmaKinetics(thermo_t* thermo) + : GasKinetics(thermo) +{ +} + +void PlasmaKinetics::update_rates_T() +{ + GasKinetics::update_rates_T(); + auto i = 0; + for (auto k : m_plasmaProcessIndx) { + m_rfn[m_plasmaIndx[i]] = m_plasma->rateCoefficient(k); + i++; + } + if (i != 0) { + m_ROP_ok = false; + } +} + +void PlasmaKinetics::addPlasmaReaction(PlasmaReaction& r) +{ + m_plasmaIndx.push_back(nReactions()-1); + + // find plasma process index + bool found = false; + for (size_t k = 0; k < m_plasma->nElectronCrossSections(); k++) { + if (r.process["kind"] == m_plasma->kind(k) && + r.process["target"] == m_plasma->target(k) && + r.process["product"] == m_plasma->product(k)) { + m_plasmaProcessIndx.push_back(k); + found = true; + break; + } + } + if (!found) { + throw CanteraError("PlasmaKinetics::addPlasmaReaction", + "Cannot find corresponding electron ", + "collision process for {}", r.equation()); + } +} + +void PlasmaKinetics::init() +{ + GasKinetics::init(); + m_plasma = dynamic_cast(&thermo()); +} + +} diff --git a/src/kinetics/Reaction.cpp b/src/kinetics/Reaction.cpp index 4344f68d667..9a01ba3f82b 100644 --- a/src/kinetics/Reaction.cpp +++ b/src/kinetics/Reaction.cpp @@ -143,9 +143,9 @@ ElectronTemperatureReaction::ElectronTemperatureReaction() PlasmaReaction::PlasmaReaction(const Composition& reactants_, const Composition& products_, - const PlasmaRate& rate_) + const std::map& process_) : Reaction(PLASMA_RXN, reactants_, products_) - , rate(rate_) + , process(process_) { } @@ -385,8 +385,8 @@ ElectronArrhenius readElectronTemperatureArrhenius(const Reaction& R, const AnyV auto& rate_map = rate.as(); A = units.convert(rate_map["A"], rc_units); b = rate_map["b"].asDouble(); - T1 = units.convertActivationEnergy(rate_map["E1"], "K"); - T2 = units.convertActivationEnergy(rate_map["E2"], "K"); + T1 = units.convertActivationEnergy(rate_map["Ea-T"], "K"); + T2 = units.convertActivationEnergy(rate_map["Ea-Te"], "K"); } else { auto& rate_vec = rate.asVector(4); A = units.convert(rate_vec[0], rc_units); @@ -637,6 +637,18 @@ void setupPlasmaReaction(PlasmaReaction& R, const AnyMap& node, const Kinetics& kin) { setupReaction(R, node, kin); + std::string kind, target, product; + if (node["process"].is()) { + auto& process_map = node["process"].as(); + R.process["kind"] = process_map["kind"].asString(); + R.process["target"] = process_map["target"].asString(); + R.process["product"] = process_map["product"].asString(); + } else { + auto& process_vec = node["process"].asVector(3); + R.process["kind"] = process_vec[0].asString(); + R.process["target"] = process_vec[1].asString(); + R.process["product"] = process_vec[2].asString(); + } } void setupThreeBodyReaction(ThreeBodyReaction& R, const XML_Node& rxn_node) diff --git a/src/kinetics/RxnRates.cpp b/src/kinetics/RxnRates.cpp index 41ba4c967cb..ec06cac898b 100644 --- a/src/kinetics/RxnRates.cpp +++ b/src/kinetics/RxnRates.cpp @@ -50,10 +50,6 @@ ElectronArrhenius::ElectronArrhenius(double A, double b, double E1, double E2) } } -PlasmaRate::PlasmaRate() -{ -} - SurfaceArrhenius::SurfaceArrhenius() : m_b(0.0) , m_E(0.0) From 500324c0b0d61236472040b47926107a299d0af0 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 19 Apr 2020 23:08:48 -0400 Subject: [PATCH 097/139] [date] update oxygen_plasma.yaml --- data/inputs/oxygen_plasma.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/inputs/oxygen_plasma.yaml b/data/inputs/oxygen_plasma.yaml index 065bd7589a8..e21ddeb793c 100644 --- a/data/inputs/oxygen_plasma.yaml +++ b/data/inputs/oxygen_plasma.yaml @@ -9,7 +9,7 @@ phases: - gri30_ion.yaml/species: [O2, E] - gri30.yaml/species: [O] - kinetics: gas + kinetics: plasma reactions: all transport: mixture-averaged state: From a3bb1b04380e326b37113112b72667bffbdf3885 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 20 Apr 2020 11:07:16 -0400 Subject: [PATCH 098/139] [test] update test_plasma --- interfaces/cython/cantera/test/test_plasma.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/interfaces/cython/cantera/test/test_plasma.py b/interfaces/cython/cantera/test/test_plasma.py index 32797549c85..2824aeb0443 100644 --- a/interfaces/cython/cantera/test/test_plasma.py +++ b/interfaces/cython/cantera/test/test_plasma.py @@ -8,6 +8,7 @@ class TestPlasma(utilities.CanteraTest): def setUp(self): self.gas = ct.PlasmaPhase(infile='oxygen_plasma.yaml') + self.gas.set_electron_energy_grid(np.linspace(0, 9.95, 200)) def test_electron_properties(self): self.gas.TPX = 1000, ct.one_atm, 'O2:1.0, E:1e-10' @@ -16,9 +17,7 @@ def test_electron_properties(self): self.assertNear(self.gas.electron_temperature, 13113, 1e-3) self.assertNear(self.gas.electron_mobility, 0.3985, 1e-4) self.assertNear(self.gas.electron_diffusivity, 0.5268, 1e-4) - #rate = self.gas.electron_rate_coefficient(19) - # self.assertNear(self.gas.net_plasma_production_rates[24] * 1e-10, rate, 1e-4) - # self.assertNear(self.gas.net_plasma_production_rates[24], 0.001877, 1e-3) + self.assertNear(self.gas.plasma_process_rate_coefficient(5), 1.55e-16, 1e-4) self.assertNear(self.gas.electron_total_collision_frequency, 3.433e11, 1e-3) self.assertNear(self.gas.electron_power_gain, 3.9811e9, 1e-3) self.assertNear(self.gas.electron_elastic_power_loss, 2.4114e7, 1e-3) From 71a0c9375b61da1f2dfca870da31582fbcdadf00 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 20 Apr 2020 11:12:12 -0400 Subject: [PATCH 099/139] [plasma] increase default grid points --- src/plasma/PlasmaPhase.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plasma/PlasmaPhase.cpp b/src/plasma/PlasmaPhase.cpp index 65b60794d5f..41fecffec71 100644 --- a/src/plasma/PlasmaPhase.cpp +++ b/src/plasma/PlasmaPhase.cpp @@ -14,7 +14,7 @@ namespace Cantera { PlasmaPhase::PlasmaPhase() : m_ncs(0) - , m_points(200) + , m_points(500) , m_kT(Undef) , m_E(0.0) , m_F(0.0) @@ -31,8 +31,8 @@ PlasmaPhase::PlasmaPhase() m_gridEdge.resize(m_points + 1); m_f0.resize(m_points); for (size_t j = 0; j < m_points; j++) { - m_gridCenter[j] = j / 20.0 + 1.0 / 40.0; - m_gridEdge[j] = j / 20.0; + m_gridCenter[j] = j / 10.0 + 1.0 / 20.0; + m_gridEdge[j] = j / 10.0; } m_gridEdge[m_points] = 10.0; m_gamma = pow(2.0 * ElectronCharge / ElectronMass, 0.5); From 306d14bfcd1bfbba94926e926e6b6a4e134697ff Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 20 Apr 2020 12:42:07 -0400 Subject: [PATCH 100/139] [interface] change to plasma_process_rate_coefficient --- interfaces/cython/cantera/plasma.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interfaces/cython/cantera/plasma.pyx b/interfaces/cython/cantera/plasma.pyx index 8afb2b9eab8..a2b3cb44815 100644 --- a/interfaces/cython/cantera/plasma.pyx +++ b/interfaces/cython/cantera/plasma.pyx @@ -37,11 +37,11 @@ cdef class PlasmaPhase(ThermoPhase): def __get__(self): return self.plasma.totalCollisionFreq() - def electron_rate_coefficient(self, k): + def plasma_process_rate_coefficient(self, k): """rate coefficient of process k""" return self.plasma.rateCoefficient(k) - def electron_reverse_rate_coefficient(self, k): + def plasma_process_reverse_rate_coefficient(self, k): """reverse rate coefficient of process k""" return self.plasma.reverseRateCoefficient(k) From c65c04da4e34422304f76c7064409bafd3863f4f Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 20 Apr 2020 13:59:56 -0400 Subject: [PATCH 101/139] [test] add test_plasma to test_kinetics.py --- interfaces/cython/cantera/composite.py | 4 ++++ interfaces/cython/cantera/test/test_kinetics.py | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/interfaces/cython/cantera/composite.py b/interfaces/cython/cantera/composite.py index b614bf67cc9..1155cfcfece 100644 --- a/interfaces/cython/cantera/composite.py +++ b/interfaces/cython/cantera/composite.py @@ -98,6 +98,10 @@ class Solution(ThermoPhase, Kinetics, Transport): __slots__ = () +class Plasma(PlasmaPhase, Kinetics, Transport): + __slots__ = () + + class Interface(InterfacePhase, InterfaceKinetics): """ Two-dimensional interfaces. diff --git a/interfaces/cython/cantera/test/test_kinetics.py b/interfaces/cython/cantera/test/test_kinetics.py index d87d50ab4b6..9dec4d4b5d2 100644 --- a/interfaces/cython/cantera/test/test_kinetics.py +++ b/interfaces/cython/cantera/test/test_kinetics.py @@ -1072,6 +1072,14 @@ def test_interface(self): self.assertNear(surf1.net_rates_of_progress[1], surf2.net_rates_of_progress[0]) + def test_plasma(self): + gas = ct.Plasma('oxygen_plasma.yaml') + gas.TPX = 1000, ct.one_atm, 'O2:1.0' + gas.set_electron_energy_grid(np.linspace(0, 50, 200)) + gas.electric_field = 1e6 + self.assertNear(gas.forward_rate_constants[1], + gas.plasma_process_rate_coefficient(13)) + def test_modify_invalid(self): # different reaction type tbr = self.gas.reaction(0) From 6730f3bfa57b813b8949609d8b3c34c45993c214 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 20 Apr 2020 15:59:45 -0400 Subject: [PATCH 102/139] [plasma] fix showing warning for gas composition. Previous code shows warning when Plasma object initialize --- include/cantera/plasma/PlasmaPhase.h | 6 ++++-- src/plasma/PlasmaPhase.cpp | 6 +++++- src/plasma/WeaklyIonizedGas.cpp | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/cantera/plasma/PlasmaPhase.h b/include/cantera/plasma/PlasmaPhase.h index a188842437d..aa4dedbd389 100644 --- a/include/cantera/plasma/PlasmaPhase.h +++ b/include/cantera/plasma/PlasmaPhase.h @@ -222,10 +222,12 @@ class PlasmaPhase: public IdealGasPhase // set grid cache void setGridCache(); - //! Signal updating electron energy density function and + //! Signal updating electron energy density function + virtual void compositionChanged(); + //! check gas comsition for any substantial species without //! the cross-section data. - virtual void compositionChanged(); + void checkSpeciesNoCrossSection(); //! Calculate elastic cross section void calculateElasticCrossSection(); diff --git a/src/plasma/PlasmaPhase.cpp b/src/plasma/PlasmaPhase.cpp index 41fecffec71..670b9df12b0 100644 --- a/src/plasma/PlasmaPhase.cpp +++ b/src/plasma/PlasmaPhase.cpp @@ -170,10 +170,14 @@ void PlasmaPhase::compositionChanged() { Phase::compositionChanged(); m_f0_ok = false; +} + +void PlasmaPhase::checkSpeciesNoCrossSection() +{ // warn that a specific species needs cross-section data. for (size_t k : m_kOthers) { if (moleFraction(k) > m_moleFractionThreshold) { - writelog("Cantera::PlasmaPhase::update_C"); + writelog("Cantera::PlasmaPhase::checkMinorSpeciesMoleFraction"); writelog("\n"); writelog("Warning: The mole fraction of species {} is more than 0.01", speciesName(k)); diff --git a/src/plasma/WeaklyIonizedGas.cpp b/src/plasma/WeaklyIonizedGas.cpp index 0164c825061..606705c2c15 100644 --- a/src/plasma/WeaklyIonizedGas.cpp +++ b/src/plasma/WeaklyIonizedGas.cpp @@ -79,6 +79,7 @@ void WeaklyIonizedGas::calculateDistributionFunction() return; } + checkSpeciesNoCrossSection(); calculateTotalCrossSection(); calculateTotalElasticCrossSection(); From f7b9d709e61681f26cccbbe96d341248797ba325 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 21 Apr 2020 14:28:36 -0400 Subject: [PATCH 103/139] [thermo, plasma] update calling electron temperature --- include/cantera/plasma/PlasmaPhase.h | 5 ----- src/thermo/Phase.cpp | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/include/cantera/plasma/PlasmaPhase.h b/include/cantera/plasma/PlasmaPhase.h index aa4dedbd389..1c6ba90debe 100644 --- a/include/cantera/plasma/PlasmaPhase.h +++ b/include/cantera/plasma/PlasmaPhase.h @@ -204,11 +204,6 @@ class PlasmaPhase: public IdealGasPhase m_init_kTe = init_kTe; } - //! Return electron temperature - virtual double electronTemperature() { - throw NotImplementedError("PlasmaPhase::electronTemperature"); - } - //! Set chemionization scattering-in rate //! Equal to the reaction rate divided by gas and electron number density virtual void setChemionScatRate(double rate) { diff --git a/src/thermo/Phase.cpp b/src/thermo/Phase.cpp index b3293b8fcd0..b26b39c733d 100644 --- a/src/thermo/Phase.cpp +++ b/src/thermo/Phase.cpp @@ -25,6 +25,7 @@ Phase::Phase() : m_xml(new XML_Node("phase")), m_id(""), m_temp(0.001), + m_electron_temp(0.001), m_dens(0.001), m_mmw(0.0), m_stateNum(-1), From a92955e3f4f7344e64fe17a53e925e815b6c828f Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 21 Apr 2020 15:07:14 -0400 Subject: [PATCH 104/139] [interface] update electron temp --- interfaces/cython/cantera/_cantera.pxd | 5 +++++ interfaces/cython/cantera/thermo.pyx | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 9b200fc19c9..22b46041f3d 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -293,6 +293,11 @@ cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera": double equivalenceRatio() except +translate_exception double stoichAirFuelRatio(const double* fuelComp, const double* oxComp, ThermoBasis basis) except +translate_exception + # non-equilibrium properties + double electronTemperature() except +translate_exception + void setElectronTemperature(double) except +translate_exception + + cdef extern from "cantera/thermo/IdealGasPhase.h": cdef cppclass CxxIdealGasPhase "Cantera::IdealGasPhase": CxxIdealGasPhase() diff --git a/interfaces/cython/cantera/thermo.pyx b/interfaces/cython/cantera/thermo.pyx index 414f7f7fa5e..9159a4f495a 100644 --- a/interfaces/cython/cantera/thermo.pyx +++ b/interfaces/cython/cantera/thermo.pyx @@ -1636,6 +1636,13 @@ cdef class ThermoPhase(_SolutionBase): def __set__(self, double value): self.thermo.setElectricPotential(value) + property electron_temperature: + """Get/Set the electron temperature [K] for this phase.""" + def __get__(self): + return self.thermo.electronTemperature() + def __set__(self, double value): + self.thermo.setElectronTemperature(value) + cdef class InterfacePhase(ThermoPhase): """ A class representing a surface or edge phase""" From ffaf84ac6e8f0b1b3e0b8dc6d12f66e51340adf9 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 21 Apr 2020 16:04:31 -0400 Subject: [PATCH 105/139] [test,data] add test_electron_arrhenius_rate and electron-temperature-test.yaml --- .../cython/cantera/test/test_kinetics.py | 6 +++ test/data/electron-temperature-test.yaml | 44 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 test/data/electron-temperature-test.yaml diff --git a/interfaces/cython/cantera/test/test_kinetics.py b/interfaces/cython/cantera/test/test_kinetics.py index 9dec4d4b5d2..a0758f99dad 100644 --- a/interfaces/cython/cantera/test/test_kinetics.py +++ b/interfaces/cython/cantera/test/test_kinetics.py @@ -1072,6 +1072,12 @@ def test_interface(self): self.assertNear(surf1.net_rates_of_progress[1], surf2.net_rates_of_progress[0]) + def test_electron_arrhenius_rate(self): + gas = ct.Solution('electron-temperature-test.yaml') + gas.TP = 300, ct.one_atm + gas.electron_temperature = 300 + self.assertNear(gas.forward_rate_constants[0], gas.forward_rate_constants[1]) + def test_plasma(self): gas = ct.Plasma('oxygen_plasma.yaml') gas.TPX = 1000, ct.one_atm, 'O2:1.0' diff --git a/test/data/electron-temperature-test.yaml b/test/data/electron-temperature-test.yaml new file mode 100644 index 00000000000..0e9653566b4 --- /dev/null +++ b/test/data/electron-temperature-test.yaml @@ -0,0 +1,44 @@ +units: {length: cm, quantity: molec, activation-energy: K} + +phases: +- name: gas + thermo: ideal-gas + elements: [O, E] + species: + - species: [O2^-] + - gri30_ion.yaml/species: [O2, E] + + kinetics: gas + reactions: all + transport: mixture-averaged + state: + T: 300.0 + P: 1.01325e+05 + +species: +- name: O2^- + composition: {E: 1, O: 2} + thermo: + model: NASA7 + temperature-ranges: [298.15, 1000.0, 6000.0] + data: + - [3.66442522, -9.28741138e-04, 6.45477082e-06, -7.7470338e-09, 2.93332662e-12, + -6870.76983, 4.35140681] + - [3.95666294, 5.98141823e-04, -2.12133905e-07, 3.63267581e-11, -2.24989228e-15, + -7062.87229, 2.27871017] + transport: + model: gas + geometry: linear + diameter: 3.33 + well-depth: 136.5 + polarizability: 1.424 + note: L4/89 + +reactions: +- equation: E + O2 + O2 => O2^- + O2 + type: electron-temperature + rate-constant: {A: 4.2e-27, b: -1.0, Ea-T: -100, Ea-Te: 700} + duplicate: true +- equation: E + O2 + O2 => O2^- + O2 + rate-constant: {A: 4.2e-27, b: -1.0, Ea: 600} + duplicate: true From dd574b62e1b70af122d0fa619ce0eedf7df86120 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 26 Apr 2020 20:52:08 -0400 Subject: [PATCH 106/139] [example] add plasma-reactor.py --- .../cantera/examples/plasma/plasma-reactor.py | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 interfaces/cython/cantera/examples/plasma/plasma-reactor.py diff --git a/interfaces/cython/cantera/examples/plasma/plasma-reactor.py b/interfaces/cython/cantera/examples/plasma/plasma-reactor.py new file mode 100644 index 00000000000..a9fe468d779 --- /dev/null +++ b/interfaces/cython/cantera/examples/plasma/plasma-reactor.py @@ -0,0 +1,82 @@ +""" +This example uses custom.py as the template to simulate a constant pressure +constant temperature plasma reactor. +""" + +import cantera as ct +import numpy as np +import scipy.integrate + +class ReactorOde: + def __init__(self, gas): + # Parameters of the ODE system and auxiliary data are stored in the + # ReactorOde object. + self.gas = gas + self.P = gas.P + + def __call__(self, t, y): + """the ODE function, y' = f(t,y) """ + + # State vector is [T, Y_1, Y_2, ... Y_K] + self.gas.set_unnormalized_mass_fractions(y[1:]) + self.gas.TP = y[0], self.P + rho = self.gas.density + h = self.gas.partial_molar_enthalpies / self.gas.molecular_weights + Q_electron = ct.electron_charge * self.gas.electron_total_power_loss * self.gas.number_density("E") + wdot = self.gas.net_production_rates + + dTdt = (-np.dot(self.gas.partial_molar_enthalpies, wdot) / rho + Q_electron / rho + + 1.0 / t_res * (np.dot(Y0, h0) - np.dot(Y0, h))) / self.gas.cp + dYdt = wdot * self.gas.molecular_weights / rho + 1.0 / t_res * (Y0 - self.gas.Y) + + return np.hstack((dTdt, dYdt)) + +gas = ct.Plasma('oxygen_plasma.yaml') + +# Initial condition +P = ct.one_atm +gas.TPX = 1000, P, 'O2:1.0, E:1e-9, O2^+:1e-9' +gas.electric_field = 2e5 +gas.electric_field_freq = 1e9 +gas.set_electron_energy_grid(np.linspace(0, 50, 500)) +gas.set_initial_mean_electron_energy(2.0) +gas.set_reuse_EEDF(True) +y0 = np.hstack((gas.T, gas.Y)) + +# inlet composition +Y0 = gas.Y + +# init partial mass enthalpies +h0 = gas.partial_molar_enthalpies / gas.molecular_weights + +# residual time [s] +t_res = 1e-3 + +# Set up objects representing the ODE and the solver +ode = ReactorOde(gas) +solver = scipy.integrate.ode(ode) +solver.set_integrator('vode', method='bdf', with_jacobian=True) +solver.set_initial_value(y0, 0.0) + +# Integrate the equations, keeping T(t) and Y(k,t) +t_end = 1e-2 +states = ct.SolutionArray(gas, 1, extra={'t': [0.0]}) +dt = 1e-5 +while solver.successful() and solver.t < t_end: + solver.integrate(solver.t + dt) + gas.TPY = solver.y[0], P, solver.y[1:] + states.append(gas.state, t=solver.t) + +# Plot the results +try: + import matplotlib.pyplot as plt + L1 = plt.plot(states.t, states.T, color='r', label='T', lw=2) + plt.xlabel('time (s)') + plt.ylabel('Temperature (K)') + plt.twinx() + L2 = plt.plot(states.t, states('E').X, label='E', lw=2) + plt.ylabel('Mole Fraction') + plt.legend(L1+L2, [line.get_label() for line in L1+L2], loc='lower right') + plt.show() +except ImportError: + print('Matplotlib not found. Unable to plot results.') From ad3b1b4d86ed80c04d4d39519d772702ed71f17a Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 27 Apr 2020 21:08:55 -0400 Subject: [PATCH 107/139] [data] update oxgen_cross_sections.yaml --- data/inputs/oxygen_cross_sections.yaml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/data/inputs/oxygen_cross_sections.yaml b/data/inputs/oxygen_cross_sections.yaml index d48a87af077..cf41e977da5 100644 --- a/data/inputs/oxygen_cross_sections.yaml +++ b/data/inputs/oxygen_cross_sections.yaml @@ -3,9 +3,7 @@ cross-sections: - comment: Total Scattering - Table 1 of Itikawa (2009) kind: effective target: O2 - mass_ratio: 1.71e-05 data: - - [0.00, 3.83e-20] - [0.10, 3.83e-20] - [0.12, 4.02e-20] - [0.15, 4.22e-20] @@ -68,7 +66,6 @@ cross-sections: - [900.0, 2.26e-20] - [1000.0, 2.08e-20] - comment: Vibrational Excitation - Table 4 & 5 of Itikawa (2009) - equation: E + O2 => E + O2(v1) kind: excitation product: O2(v1) target: O2 @@ -95,7 +92,6 @@ cross-sections: - [10.0, 4.4e-21] - [15.0, 5.70e-22] - comment: Vibrational Excitation - Table 4 of Itikawa (2009) - equation: E + O2 => E + O2(v2) kind: excitation product: O2(v2) target: O2 @@ -116,7 +112,6 @@ cross-sections: - [10.0, 1.65e-21] - [15.0, 1.50e-22] - comment: Vibrational Excitation - Table 4 of Itikawa (2009) - equation: E + O2 => E + O2(v3) kind: excitation product: O2(v3) target: O2 @@ -130,7 +125,6 @@ cross-sections: - [10.0, 7.50e-22] - [15.0, 6.50e-23] - comment: Excitation of Electronic States - Table 7 of Itikawa (2009) - equation: E + O2 => E + O2(a1) kind: excitation product: O2(a1) target: O2 @@ -143,7 +137,6 @@ cross-sections: - [15.0, 4.20e-22] - [20.0, 2.30e-22] - comment: Excitation of Electronic States - Table 7 of Itikawa (2009) - equation: E + O2 => E + O2(a1) kind: excitation product: O2(a1) target: O2 @@ -156,7 +149,6 @@ cross-sections: - [15.0, 4.20e-22] - [20.0, 2.30e-22] - comment: Excitation of Electronic States - Table 7 of Itikawa (2009) - equation: E + O2 => E + O2(b1) kind: excitation product: O2(b1) target: O2 @@ -169,7 +161,6 @@ cross-sections: - [15.0, 7.80e-23] - [20.0, 5.50e-23] - comment: Excitation of Electronic States - Table 8 of Itikawa (2009) - equation: E + O2 => E + O2(A3) kind: excitation product: O2(A3) target: O2 @@ -181,7 +172,6 @@ cross-sections: - [20.0, 3.90e-22] - [30.0, 1.30e-22] - comment: Excitation of Electronic States - Table 8 of Itikawa (2009) - equation: E + O2 => E + O2(AP) kind: excitation product: O2(AP) target: O2 @@ -193,7 +183,6 @@ cross-sections: - [20.0, 3.90e-22] - [30.0, 1.30e-22] - comment: Excitation of Electronic States - Table 8 of Itikawa (2009) - equation: E + O2 => E + O2(c1) kind: excitation product: O2(c1) target: O2 @@ -205,7 +194,6 @@ cross-sections: - [20.0, 3.90e-22] - [30.0, 1.30e-22] - comment: Excitation of Electronic States - Table 9 of Itikawa (2009) - equation: E + O2 => E + O2(B3) kind: excitation product: O2(B3) target: O2 @@ -217,7 +205,6 @@ cross-sections: - [30.0, 5.98e-21] - [50.0, 2.764e-21] - comment: Dissociative Attachment - Table 13 of Itikawa (2009) - equation: E + O2 => O^- + O kind: attachment product: O^- + O target: O2 @@ -280,7 +267,6 @@ cross-sections: - [9.8, 3.52e-24] - [9.9, 3.52e-24] - comment: Total Dissociation for Neutral Products - Table 10 of Itikawa (2009) - equation: E + O2 => E + 2 O kind: excitation product: O + O target: O2 @@ -301,7 +287,6 @@ cross-sections: - [148.5, 2.96e-21] - [198.5, 2.91e-21] - comment: Ionization - Table 11 of Itikawa (2009) - equation: E + O2 => 2 E + O2^+ kind: ionization product: O2^+ target: O2 @@ -352,7 +337,6 @@ cross-sections: - [948.0, 6.17e-21] - [998.0, 5.97e-21] - comment: Ionization - Table 11 of Itikawa (2009) - equation: E + O2 => 2 E + O + O^+ kind: ionization product: O + O^+ target: O2 From 4d8cfd5765ad634990428f90e466162d83b37980 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 27 Apr 2020 22:19:46 -0400 Subject: [PATCH 108/139] [kinetics] add m_rkcn calculation for plasma --- src/kinetics/PlasmaKinetics.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/kinetics/PlasmaKinetics.cpp b/src/kinetics/PlasmaKinetics.cpp index 288549b7cd4..543ccaa9430 100644 --- a/src/kinetics/PlasmaKinetics.cpp +++ b/src/kinetics/PlasmaKinetics.cpp @@ -22,6 +22,10 @@ void PlasmaKinetics::update_rates_T() auto i = 0; for (auto k : m_plasmaProcessIndx) { m_rfn[m_plasmaIndx[i]] = m_plasma->rateCoefficient(k); + if (m_rkcn[m_plasmaIndx[i]] != 0.0) { + m_rkcn[m_plasmaIndx[i]] = m_plasma->reverseRateCoefficient(k) / + m_rfn[m_plasmaIndx[i]]; + } i++; } if (i != 0) { From a954dae46cd36265098d3006dcdb75081767cd0f Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 28 Apr 2020 10:08:14 -0400 Subject: [PATCH 109/139] [plasma] delete redundant codes --- src/plasma/PlasmaPhase.cpp | 1 + src/plasma/WeaklyIonizedGas.cpp | 13 ++++--------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/plasma/PlasmaPhase.cpp b/src/plasma/PlasmaPhase.cpp index 670b9df12b0..54d42247ed4 100644 --- a/src/plasma/PlasmaPhase.cpp +++ b/src/plasma/PlasmaPhase.cpp @@ -163,6 +163,7 @@ void PlasmaPhase::setGridCache() void PlasmaPhase::setTemperature(const double temp) { Phase::setTemperature(temp); + m_kT = Boltzmann * temp / ElectronCharge; m_f0_ok = false; } diff --git a/src/plasma/WeaklyIonizedGas.cpp b/src/plasma/WeaklyIonizedGas.cpp index 606705c2c15..d8206a51e44 100644 --- a/src/plasma/WeaklyIonizedGas.cpp +++ b/src/plasma/WeaklyIonizedGas.cpp @@ -60,12 +60,6 @@ void WeaklyIonizedGas::calculateTotalElasticCrossSection() void WeaklyIonizedGas::calculateDistributionFunction() { - // Check temperature and update temperature-dependent variables. - double kT = Boltzmann * temperature() / ElectronCharge; - if (m_kT != kT) { - m_kT = kT; - m_f0_ok = false; - } // Check density and update density-dependent properties double N = molarDensity() * Avogadro; if (m_N != N) { @@ -83,14 +77,15 @@ void WeaklyIonizedGas::calculateDistributionFunction() calculateTotalCrossSection(); calculateTotalElasticCrossSection(); + double kTe = m_kT; //! Use kTe for initial f0 if (m_init_kTe != 0.0) { - kT = m_init_kTe; + kTe = m_init_kTe; } for (size_t j = 0; j < m_points; j++) { - m_f0(j) = 2.0 * pow(1.0/Pi, 0.5) * pow(kT, -3./2.) * - std::exp(-m_gridCenter[j]/kT); + m_f0(j) = 2.0 * pow(1.0/Pi, 0.5) * pow(kTe, -3./2.) * + std::exp(-m_gridCenter[j]/kTe); } if (m_E != 0.0) { From 1e54f0758d980c11539f68c45d5f11c2e0f882be Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 28 Apr 2020 12:33:53 -0400 Subject: [PATCH 110/139] [plasma, interface] add feature of using old EEDF to improve comutational efficiency --- include/cantera/plasma/PlasmaPhase.h | 8 ++++++++ interfaces/cython/cantera/_cantera.pxd | 1 + interfaces/cython/cantera/plasma.pyx | 4 ++++ src/plasma/PlasmaPhase.cpp | 9 +++++++++ src/plasma/WeaklyIonizedGas.cpp | 11 +++++++---- 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/include/cantera/plasma/PlasmaPhase.h b/include/cantera/plasma/PlasmaPhase.h index 1c6ba90debe..483669642ef 100644 --- a/include/cantera/plasma/PlasmaPhase.h +++ b/include/cantera/plasma/PlasmaPhase.h @@ -204,6 +204,11 @@ class PlasmaPhase: public IdealGasPhase m_init_kTe = init_kTe; } + //! Set flag for reusing old EEDF + void setReuseEEDF(bool reuse) { + m_reuse_EEDF = reuse; + } + //! Set chemionization scattering-in rate //! Equal to the reaction rate divided by gas and electron number density virtual void setChemionScatRate(double rate) { @@ -292,6 +297,9 @@ class PlasmaPhase: public IdealGasPhase //! Initial electron mean energy double m_init_kTe; + //! flag of using old EEDF as initial EEDF + bool m_reuse_EEDF; + //! The threshold of mole fraction for showing warning of //! insufficient cross-section data. double m_moleFractionThreshold; diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 22b46041f3d..27ee4981b29 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -327,6 +327,7 @@ cdef extern from "cantera/plasma/PlasmaPhase.h": void setupBoltzmannSolver(size_t, double, double, double) void setMoleFractionThreshold(double) void setInitialMeanElectronEnergy(double) + void setReuseEEDF(cbool) string target(size_t) string kind(size_t) string product(size_t) diff --git a/interfaces/cython/cantera/plasma.pyx b/interfaces/cython/cantera/plasma.pyx index a2b3cb44815..c1f1bd7376e 100644 --- a/interfaces/cython/cantera/plasma.pyx +++ b/interfaces/cython/cantera/plasma.pyx @@ -89,6 +89,10 @@ cdef class PlasmaPhase(ThermoPhase): """ Set initial mean electron energy. [eV]""" self.plasma.setInitialMeanElectronEnergy(init_kTe) + def set_reuse_EEDF(self, reuse): + """ Set flag of reusing old EEDF as initial EEDF""" + self.plasma.setReuseEEDF(reuse) + property mean_electron_energy: """mean electron energy [eV]""" def __get__(self): diff --git a/src/plasma/PlasmaPhase.cpp b/src/plasma/PlasmaPhase.cpp index 54d42247ed4..e1b7a7e02dc 100644 --- a/src/plasma/PlasmaPhase.cpp +++ b/src/plasma/PlasmaPhase.cpp @@ -24,6 +24,7 @@ PlasmaPhase::PlasmaPhase() , m_delta0(1e14) , m_factorM(4.0) , m_init_kTe(0.0) + , m_reuse_EEDF(false) , m_moleFractionThreshold(0.01) { // default energy grid @@ -286,6 +287,9 @@ void PlasmaPhase::calculateElasticCrossSection() void PlasmaPhase::setupGrid(size_t n, const double* eps) { + // save old grid and EEDF + vector_fp grid_old = m_gridCenter; + vector_fp f0_old(m_f0.data(), m_f0.data() + m_f0.size()); m_points = n-1; m_gridCenter.resize(n-1); m_gridEdge.resize(n); @@ -295,6 +299,11 @@ void PlasmaPhase::setupGrid(size_t n, const double* eps) m_gridEdge[i] = eps[i]; m_gridCenter[i] = 0.5 * (eps[i] + eps[i+1]); } + // interpolate EEDF to the new grid + for (size_t i = 0; i < m_points; i++) { + m_f0(i) = linearInterp(m_gridCenter[i], grid_old, f0_old); + } + setGridCache(); m_f0_ok = false; } diff --git a/src/plasma/WeaklyIonizedGas.cpp b/src/plasma/WeaklyIonizedGas.cpp index d8206a51e44..c0e7165e71f 100644 --- a/src/plasma/WeaklyIonizedGas.cpp +++ b/src/plasma/WeaklyIonizedGas.cpp @@ -78,14 +78,17 @@ void WeaklyIonizedGas::calculateDistributionFunction() calculateTotalElasticCrossSection(); double kTe = m_kT; - //! Use kTe for initial f0 + // Use kTe for initial f0 if (m_init_kTe != 0.0) { kTe = m_init_kTe; } - for (size_t j = 0; j < m_points; j++) { - m_f0(j) = 2.0 * pow(1.0/Pi, 0.5) * pow(kTe, -3./2.) * - std::exp(-m_gridCenter[j]/kTe); + // Use old EEDF + if (!m_reuse_EEDF || m_f0(m_points-1) == 0.0) { + for (size_t j = 0; j < m_points; j++) { + m_f0(j) = 2.0 * pow(1.0/Pi, 0.5) * pow(kTe, -3./2.) * + std::exp(-m_gridCenter[j]/kTe); + } } if (m_E != 0.0) { From 80f0fddc60441d8ddd78be60c0a7a56b344c9bee Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 28 Apr 2020 15:08:34 -0400 Subject: [PATCH 111/139] [test] update test-plasma --- .../cython/cantera/test/test_kinetics.py | 2 +- interfaces/cython/cantera/test/test_plasma.py | 23 ++++++++----------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/interfaces/cython/cantera/test/test_kinetics.py b/interfaces/cython/cantera/test/test_kinetics.py index a0758f99dad..b7bc6bbda8e 100644 --- a/interfaces/cython/cantera/test/test_kinetics.py +++ b/interfaces/cython/cantera/test/test_kinetics.py @@ -1084,7 +1084,7 @@ def test_plasma(self): gas.set_electron_energy_grid(np.linspace(0, 50, 200)) gas.electric_field = 1e6 self.assertNear(gas.forward_rate_constants[1], - gas.plasma_process_rate_coefficient(13)) + gas.plasma_process_rate_coefficient(13) * ct.avogadro) def test_modify_invalid(self): # different reaction type diff --git a/interfaces/cython/cantera/test/test_plasma.py b/interfaces/cython/cantera/test/test_plasma.py index 2824aeb0443..6e97c45d2ca 100644 --- a/interfaces/cython/cantera/test/test_plasma.py +++ b/interfaces/cython/cantera/test/test_plasma.py @@ -8,12 +8,12 @@ class TestPlasma(utilities.CanteraTest): def setUp(self): self.gas = ct.PlasmaPhase(infile='oxygen_plasma.yaml') + self.gas.TPX = 1000, ct.one_atm, 'O2:1.0' + self.gas.electric_field = 1e5 self.gas.set_electron_energy_grid(np.linspace(0, 9.95, 200)) + self.gas.set_initial_mean_electron_energy(0.5) def test_electron_properties(self): - self.gas.TPX = 1000, ct.one_atm, 'O2:1.0, E:1e-10' - self.gas.electric_field = 1e5 - self.gas.electric_field_freq = 0.0 self.assertNear(self.gas.electron_temperature, 13113, 1e-3) self.assertNear(self.gas.electron_mobility, 0.3985, 1e-4) self.assertNear(self.gas.electron_diffusivity, 0.5268, 1e-4) @@ -25,10 +25,8 @@ def test_electron_properties(self): self.assertNear(self.gas.electric_field, 1e5, 1e-3) def test_change_electric_field_freq(self): - self.gas.TPX = 1000, ct.one_atm, 'O2:1.0' - self.gas.electric_field = 1e5 - self.gas.electric_field_freq = 0.0 Te0 = self.gas.electron_temperature + self.gas.set_reuse_EEDF(True) self.gas.electric_field_freq = 1e9 Te = self.gas.electron_temperature self.gas.electric_field_freq = 2e9 @@ -36,11 +34,10 @@ def test_change_electric_field_freq(self): self.assertLess(self.gas.electron_temperature, Te) self.assertNear(Te, Te0, 1e-3) self.assertNear(self.gas.electron_temperature, Te, 1e-3) + self.gas.electric_field_freq = 0.0 + self.gas.set_reuse_EEDF(False) def test_change_gas_temperature(self): - self.gas.TPX = 1000, ct.one_atm, 'O2:1.0' - self.gas.electric_field = 1e5 - self.gas.electric_field_freq = 0.0 Te0 = self.gas.electron_temperature self.gas.TP = 1100, ct.one_atm * 1.1 # The gas temperature is important only when E/N is small @@ -50,15 +47,15 @@ def test_change_gas_temperature(self): Te = self.gas.electron_temperature self.gas.TP = 1000, ct.one_atm self.assertLess(0.05, abs(self.gas.electron_temperature - Te) / Te) + # set conditions back self.gas.electric_field = 1e5 + self.gas.TPX = 1000, ct.one_atm, 'O2:1.0' def test_change_electric_field_strength(self): - self.gas.TPX = 1000, ct.one_atm, 'O2:1.0' - self.gas.electric_field = 1e5 - self.gas.electric_field_freq = 0.0 grid = np.linspace(0.0, 2.0, num=1000) self.gas.set_electron_energy_grid(grid) self.gas.electric_field = 1.0 # The electron temperature approach gas temperature when E is small self.assertNear(self.gas.electron_temperature, self.gas.T, 1e-3) - + # set conditions back + self.gas.electric_field = 1e5 From b0d8748a83ce465e11a54c31b0489cc4c448d7cf Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 28 Apr 2020 22:46:49 -0400 Subject: [PATCH 112/139] [thermo,interface] add number_density --- include/cantera/thermo/Phase.h | 10 ++++++++++ interfaces/cython/cantera/_cantera.pxd | 2 ++ interfaces/cython/cantera/thermo.pyx | 8 ++++++++ src/thermo/Phase.cpp | 10 ++++++++++ 4 files changed, 30 insertions(+) diff --git a/include/cantera/thermo/Phase.h b/include/cantera/thermo/Phase.h index 2c77c954bd2..d7cbd56a428 100644 --- a/include/cantera/thermo/Phase.h +++ b/include/cantera/thermo/Phase.h @@ -490,6 +490,16 @@ class Phase //! @return Map of species names to mole fractions compositionMap getMoleFractionsByName(double threshold=0.0) const; + //! Return the number density of a single species + //! @param k species index + //! @return Number density of the species + double numberDensity(size_t k) const; + + //! Return the number density of a single species + //! @param name String name of the species + //! @return Number density of the species + double numberDensity(const std::string& name) const; + //! Return the mole fraction of a single species //! @param k species index //! @return Mole fraction of the species diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 27ee4981b29..d5167e7c282 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -236,6 +236,8 @@ cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera": Composition getMoleFractionsByName(double) double moleFraction(size_t) except +translate_exception double moleFraction(string) except +translate_exception + double numberDensity(size_t) except +translate_exception + double numberDensity(string) except +translate_exception double concentration(size_t) except +translate_exception double elementalMassFraction(size_t) except +translate_exception diff --git a/interfaces/cython/cantera/thermo.pyx b/interfaces/cython/cantera/thermo.pyx index 9159a4f495a..7950c360bb3 100644 --- a/interfaces/cython/cantera/thermo.pyx +++ b/interfaces/cython/cantera/thermo.pyx @@ -1061,6 +1061,14 @@ cdef class ThermoPhase(_SolutionBase): X = self.thermo.getMoleFractionsByName(threshold) return {pystr(item.first):item.second for item in X} + def number_density(self, value): + if isinstance(value, str): + return self.thermo.numberDensity(value) + elif isinstance(value, int): + return self.thermo.numberDensity(value) + else: + return None + ######## Read-only thermodynamic properties ######## property P: diff --git a/src/thermo/Phase.cpp b/src/thermo/Phase.cpp index b26b39c733d..9f895a07b70 100644 --- a/src/thermo/Phase.cpp +++ b/src/thermo/Phase.cpp @@ -575,6 +575,16 @@ void Phase::getMoleFractions(double* const x) const scale(m_ym.begin(), m_ym.end(), x, m_mmw); } +double Phase::numberDensity(size_t k) const +{ + return moleFraction(k) * molarDensity() * Avogadro; +} + +double Phase::numberDensity(const std::string& nameSpec) const +{ + return moleFraction(nameSpec) * molarDensity() * Avogadro; +} + double Phase::moleFraction(size_t k) const { checkSpeciesIndex(k); From 86b194f48e6c8e2e71bf879e249996d4f8ea3aa3 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Wed, 29 Apr 2020 00:01:41 -0400 Subject: [PATCH 113/139] [plasma] add type --- include/cantera/plasma/PlasmaPhase.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/cantera/plasma/PlasmaPhase.h b/include/cantera/plasma/PlasmaPhase.h index 483669642ef..0b5c83dbe25 100644 --- a/include/cantera/plasma/PlasmaPhase.h +++ b/include/cantera/plasma/PlasmaPhase.h @@ -37,6 +37,10 @@ class PlasmaPhase: public IdealGasPhase public: PlasmaPhase(); + virtual std::string type() const { + return "Plasma"; + } + void addElectronCrossSections(const AnyValue& crossSections, const AnyValue& names); From 92591b99de25888905b3e8bdd17a5fb3aca52500 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Wed, 29 Apr 2020 11:21:03 -0400 Subject: [PATCH 114/139] [interface] add electron total power loss --- interfaces/cython/cantera/plasma.pyx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/interfaces/cython/cantera/plasma.pyx b/interfaces/cython/cantera/plasma.pyx index c1f1bd7376e..af2660bac86 100644 --- a/interfaces/cython/cantera/plasma.pyx +++ b/interfaces/cython/cantera/plasma.pyx @@ -54,18 +54,26 @@ cdef class PlasmaPhase(ThermoPhase): property electron_elastic_power_loss: """ - Electron elastic power loss. [eV/s] + The elastic power loss of one electron. [eV/s] """ def __get__(self): return self.plasma.elasticPowerLoss() property electron_inelastic_power_loss: """ - Electron inelastic power loss. [eV/s] + The inelastic power loss of one electron. [eV/s] """ def __get__(self): return self.plasma.inelasticPowerLoss() + property electron_total_power_loss: + """ + The total power loss of one electron. [eV/s] + """ + def __get__(self): + return (self.electron_elastic_power_loss + + self.electron_inelastic_power_loss) + def setup_boltzmann_solver(self, maxn=100, rtol=1e-5, delta0=1e14, m=4.0): """ From 3b3fe4531081286aee9d935f7e7a24c319b2bbbf Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Wed, 29 Apr 2020 11:42:34 -0400 Subject: [PATCH 115/139] [interface] fix number density --- interfaces/cython/cantera/thermo.pyx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/interfaces/cython/cantera/thermo.pyx b/interfaces/cython/cantera/thermo.pyx index 7950c360bb3..cd254aadd67 100644 --- a/interfaces/cython/cantera/thermo.pyx +++ b/interfaces/cython/cantera/thermo.pyx @@ -1061,13 +1061,14 @@ cdef class ThermoPhase(_SolutionBase): X = self.thermo.getMoleFractionsByName(threshold) return {pystr(item.first):item.second for item in X} - def number_density(self, value): - if isinstance(value, str): - return self.thermo.numberDensity(value) - elif isinstance(value, int): - return self.thermo.numberDensity(value) + def number_density(self, species): + if isinstance(species, (str, bytes)): + return self.thermo.numberDensity(stringify(species)) + elif isinstance(species, (int, float)): + return self.thermo.numberDensity(species) else: - return None + raise TypeError("'species' must be a string or a number." + " Got {!r}.".format(species)) ######## Read-only thermodynamic properties ######## From 8711356916c17bd3f5cabf2f85b48058faec09e0 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 30 Apr 2020 10:15:50 -0400 Subject: [PATCH 116/139] [kinetics] fix unit for plasma rate coefficients --- src/kinetics/PlasmaKinetics.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/kinetics/PlasmaKinetics.cpp b/src/kinetics/PlasmaKinetics.cpp index 543ccaa9430..8b5aa953df7 100644 --- a/src/kinetics/PlasmaKinetics.cpp +++ b/src/kinetics/PlasmaKinetics.cpp @@ -26,6 +26,8 @@ void PlasmaKinetics::update_rates_T() m_rkcn[m_plasmaIndx[i]] = m_plasma->reverseRateCoefficient(k) / m_rfn[m_plasmaIndx[i]]; } + // convert to kmol base + m_rfn[m_plasmaIndx[i]] *= Avogadro; i++; } if (i != 0) { From 03480a782537005203ea8158b15455d0b01c4d4a Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 30 Apr 2020 16:44:26 -0400 Subject: [PATCH 117/139] [data] update oxygen_plasma.yaml --- data/inputs/oxygen_plasma.yaml | 43 ++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/data/inputs/oxygen_plasma.yaml b/data/inputs/oxygen_plasma.yaml index e21ddeb793c..765f2f7efdd 100644 --- a/data/inputs/oxygen_plasma.yaml +++ b/data/inputs/oxygen_plasma.yaml @@ -5,13 +5,13 @@ phases: thermo: weakly-ionized-gas elements: [O, E] species: - - species: [O2^+] + - species: [O2^+, O2^-] - gri30_ion.yaml/species: [O2, E] - gri30.yaml/species: [O] kinetics: plasma reactions: all - transport: mixture-averaged + transport: Ion state: T: 300.0 P: 1.01325e+05 @@ -36,12 +36,47 @@ species: well-depth: 80.0 # Casey polarizability: 0.847 # Method: B3LYP cc-pVTZ from NIST note: Casey et al. (2016) doi.org/10.1016/j.proci.2016.08.083 +- name: O2^- + composition: {O: 2, E: 1} + thermo: + model: NASA7 + temperature-ranges: [298.15, 1000.0, 6000.0] + data: + - [3.66442522, -9.28741138e-04, 6.45477082e-06, -7.7470338e-09, 2.93332662e-12, + -6870.76983, 4.35140681] + - [3.95666294, 5.98141823e-04, -2.12133905e-07, 3.63267581e-11, -2.24989228e-15, + -7062.87229, 2.27871017] + transport: + model: gas + geometry: linear + diameter: 3.33 + well-depth: 136.5 + polarizability: 1.424 + note: L4/89 reactions: -- equation: O2^+ + E => O + O # Reaction 1 +# Kossyi et al. (1992) doi.org/10.1088/0963-0252/1/3/011 +# Kossyi (40) +- equation: O2^+ + E => O + O type: electron-temperature rate-constant: {A: 6.0e-5, b: -1.0, Ea-T: 0.0, Ea-Te: 0.0} - +# Kossyi (21) - equation: E + O2 => 2 E + O2^+ type: plasma process: {kind: ionization, target: O2, product: O2^+} +# Kossyi (92) +- equation: O + O + O2 <=> O2 + O2 + rate-constant: {A: 2.45e-31, b: -0.63, Ea: 0.0} +# Kossyi (45) +- equation: E + O2 + O2 => O2^- + O2 + type: electron-temperature + rate-constant: {A: 4.2e-27, b: -1.0, Ea-T: -100, Ea-Te: 700} +# Kossyi 2.7 Recombination of positive and negative ions (type 2) +- equation: O2^- + O2^+ <=> O2 + O + O + rate-constant: {A: 1.0e-07, b: 0.0, Ea: 0.0} +# Kossyi 2.7 Recombination of positive and negative ions (type 1) +- equation: O2^- + O2^+ <=> O2 + O2 + rate-constant: {A: 3.464e-06, b: -0.5, Ea: 0.0} +# Kossyi 2.7 Recombination of positive and negative ions (type 5) +- equation: O2^- + O2^+ + O2 <=> O2 + O2 + O2 + rate-constant: {A: 3.118e-19, b: -2.5, Ea: 0.0} \ No newline at end of file From 8fbac4f422cfd30fb82c4163a35c14f9e18c0bbe Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 30 Apr 2020 17:10:08 -0400 Subject: [PATCH 118/139] [plasma] add m_has_EEDF to make sure a validate initial EEDF --- include/cantera/plasma/PlasmaPhase.h | 3 +++ src/plasma/PlasmaPhase.cpp | 1 + src/plasma/WeaklyIonizedGas.cpp | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/cantera/plasma/PlasmaPhase.h b/include/cantera/plasma/PlasmaPhase.h index 0b5c83dbe25..cd68e4667a2 100644 --- a/include/cantera/plasma/PlasmaPhase.h +++ b/include/cantera/plasma/PlasmaPhase.h @@ -304,6 +304,9 @@ class PlasmaPhase: public IdealGasPhase //! flag of using old EEDF as initial EEDF bool m_reuse_EEDF; + //! flag of having an EEDF + bool m_has_EEDF; + //! The threshold of mole fraction for showing warning of //! insufficient cross-section data. double m_moleFractionThreshold; diff --git a/src/plasma/PlasmaPhase.cpp b/src/plasma/PlasmaPhase.cpp index e1b7a7e02dc..163a9aaaf3b 100644 --- a/src/plasma/PlasmaPhase.cpp +++ b/src/plasma/PlasmaPhase.cpp @@ -25,6 +25,7 @@ PlasmaPhase::PlasmaPhase() , m_factorM(4.0) , m_init_kTe(0.0) , m_reuse_EEDF(false) + , m_has_EEDF(false) , m_moleFractionThreshold(0.01) { // default energy grid diff --git a/src/plasma/WeaklyIonizedGas.cpp b/src/plasma/WeaklyIonizedGas.cpp index c0e7165e71f..29125c71b2e 100644 --- a/src/plasma/WeaklyIonizedGas.cpp +++ b/src/plasma/WeaklyIonizedGas.cpp @@ -84,7 +84,7 @@ void WeaklyIonizedGas::calculateDistributionFunction() } // Use old EEDF - if (!m_reuse_EEDF || m_f0(m_points-1) == 0.0) { + if (!m_reuse_EEDF || !m_has_EEDF) { for (size_t j = 0; j < m_points; j++) { m_f0(j) = 2.0 * pow(1.0/Pi, 0.5) * pow(kTe, -3./2.) * std::exp(-m_gridCenter[j]/kTe); @@ -103,6 +103,7 @@ void WeaklyIonizedGas::calculateDistributionFunction() } } } + m_has_EEDF = true; m_f0_ok = true; } From 19156664f9bde9974356af4e98c2cd8b247ccc1c Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 30 Apr 2020 19:00:24 -0400 Subject: [PATCH 119/139] [test] add TestPlasmaElectronTransport --- .../cython/cantera/test/test_transport.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/interfaces/cython/cantera/test/test_transport.py b/interfaces/cython/cantera/test/test_transport.py index 974f07c5318..bc105d9d7f1 100644 --- a/interfaces/cython/cantera/test/test_transport.py +++ b/interfaces/cython/cantera/test/test_transport.py @@ -193,6 +193,23 @@ def test_update_temperature(self): self.assertTrue(mobi != self.gas.mobilities[self.kH3Op]) +class TestPlasmaElectronTransport(utilities.CanteraTest): + def setUp(self): + self.gas = ct.Plasma('oxygen_plasma.yaml') + self.gas.TPX = 1000, ct.one_atm, 'O2:1.0' + self.gas.set_electron_energy_grid(np.linspace(0, 50, 200)) + self.gas.electric_field = 1e6 + self.kE = self.gas.species_index("E") + + def test_electron_mobility(self): + mobi = self.gas.mobilities[self.kE] + self.assertNear(mobi, self.gas.electron_mobility) + + def test_electron_diffusivity(self): + diff = self.gas.mix_diff_coeffs[self.kE] + self.assertNear(diff, self.gas.electron_diffusivity) + + class TestIonTransportYAML(TestIonTransport): def setUp(self): self.p = ct.one_atm From aa1b392b6cd40309e7eb04dba8c0aa08fcbaa878 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 30 Apr 2020 21:16:57 -0400 Subject: [PATCH 120/139] [example] update electron_properties.py --- .../examples/electron/electron_properties.py | 47 ------------------- .../examples/plasma/electron_properties.py | 24 ++++++++++ 2 files changed, 24 insertions(+), 47 deletions(-) delete mode 100644 interfaces/cython/cantera/examples/electron/electron_properties.py create mode 100644 interfaces/cython/cantera/examples/plasma/electron_properties.py diff --git a/interfaces/cython/cantera/examples/electron/electron_properties.py b/interfaces/cython/cantera/examples/electron/electron_properties.py deleted file mode 100644 index 537c7f48b77..00000000000 --- a/interfaces/cython/cantera/examples/electron/electron_properties.py +++ /dev/null @@ -1,47 +0,0 @@ -import cantera as ct -import numpy as np -import scipy.constants as co - -# Simulation parameters -p = ct.one_atm # pressure [Pa] -T = 2000.0 # temperature [K] -reactants = 'N2:3.76, O2:1' # air composition - -air = ct.Solution(infile='gri30_ion.cti', efile='lxcat.yaml') -air.TPX = T, p, reactants -air.electric_field = 1e5 - -# set up proper grid for the electric field -grid = np.linspace(0.0, 30, num=500) -air.set_electron_energy_grid(grid) - -print('electron diffusivity = {0:7f} [m^2/s]'.format(air.electron_diffusivity)) -print('electron mobility = {0:7f} [m^2/V/s]'.format(air.electron_mobility)) -print('electron total collision frequency = {0:7f} [Hz]'.format(air.electron_total_collision_frequency)) -print('electron power gain = {0:7f} [eV/s]'.format(air.electron_power_gain)) -print('electron elastic power loss = {0:7f} [eV/s]'.format(air.electron_elastic_power_loss)) -print('electron inelastic power loss = {0:7f} [eV/s]'.format(air.electron_inelastic_power_loss)) -print('mean electron energy = {0:7f} [eV]'.format(air.mean_electron_energy)) - -# Here, we demonstrate another way to initiate the gas for electron properties. -# This method enable we to use multiple files -ecs = ct.ElectronCrossSection.listFromFile('lxcat.yaml') -gas = ct.Solution('gri30_plasma.cti', electron='WeaklyIonizedGas', electron_cross_sections=ecs) -gas.TPX = T, p, reactants -gas.electric_field = 1e5 - -# set up proper grid for the electric field -grid = np.linspace(0.0, 30, num=500) -gas.set_electron_energy_grid(grid) - -# We can also use species index to find electron transport properties -gas.electron_transport_enabled = True -i = gas.species_index('E') -print('electron diffusivity = {0:7f} [m^2/s]'.format(gas.mix_diff_coeffs[i])) -print('electron mobility = {0:7f} [m^2/V/s]'.format(gas.mobilities[i])) - -# and reaction rate of electron reaction which depends on electron temperature -gas.electron_temperature_reactions_enabled = True -print(gas.reaction_equation(331)) -print('rate coefficient = {0:7f} [m^3/kmol/s]'.format(gas.forward_rate_constants[331])) - diff --git a/interfaces/cython/cantera/examples/plasma/electron_properties.py b/interfaces/cython/cantera/examples/plasma/electron_properties.py new file mode 100644 index 00000000000..a34c2523dcf --- /dev/null +++ b/interfaces/cython/cantera/examples/plasma/electron_properties.py @@ -0,0 +1,24 @@ +import cantera as ct +import numpy as np +import scipy.constants as co + +# Simulation parameters +p = ct.one_atm # pressure [Pa] +T = 1000.0 # temperature [K] +reactants = 'O2:1' # gas composition + +gas = ct.Plasma(infile='oxygen_plasma.yaml') +gas.TPX = T, p, reactants +gas.electric_field = 1e5 + +# set up proper grid for the electric field +grid = np.linspace(0.0, 50, num=500) +gas.set_electron_energy_grid(grid) + +print('electron diffusivity = {0:7f} [m^2/s]'.format(gas.electron_diffusivity)) +print('electron mobility = {0:7f} [m^2/V/s]'.format(gas.electron_mobility)) +print('electron total collision frequency = {0:7f} [Hz]'.format(gas.electron_total_collision_frequency)) +print('electron power gain = {0:7f} [eV/s]'.format(gas.electron_power_gain)) +print('electron elastic power loss = {0:7f} [eV/s]'.format(gas.electron_elastic_power_loss)) +print('electron inelastic power loss = {0:7f} [eV/s]'.format(gas.electron_inelastic_power_loss)) +print('mean electron energy = {0:7f} [eV]'.format(gas.mean_electron_energy)) From 40d8457a2b784114b05323beaaec14e828d09232 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 1 May 2020 11:27:00 -0400 Subject: [PATCH 121/139] [plasma] fill (0, 0) to cross section data --- src/plasma/ElectronCrossSection.cpp | 19 ++++++------------- src/plasma/PlasmaPhase.cpp | 5 +++++ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/plasma/ElectronCrossSection.cpp b/src/plasma/ElectronCrossSection.cpp index 2889117df35..4de5aea6309 100644 --- a/src/plasma/ElectronCrossSection.cpp +++ b/src/plasma/ElectronCrossSection.cpp @@ -16,21 +16,14 @@ ElectronCrossSection::~ElectronCrossSection() void ElectronCrossSection::validate() { - if (kind == "effective") { - if (data.size() > 0 && data[0].size() > 0) { - if (data[0][0] != 0.0) { - throw CanteraError("ElectronCrossSection::validate", - "Invalid energy value of type '{}' for '{}'. " - "Energy must starts at zero.", kind, target); - } - } - } else if (kind == "elastic") { - if (data[0][0] != 0.0) { + if (kind == "ionization" || kind == "attachment" || kind == "excitation") { + if (threshold < 0.0) { throw CanteraError("ElectronCrossSection::validate", - "Invalid energy value of type '{}' for '{}'. " - "Energy must starts at zero.", kind, target); + "The threshold of the process", + "(kind = '{}', target = '{}', product = '{}')", + "cannot be negative", kind, target, product); } - } else if (kind != "ionization" && kind != "attachment" && kind != "excitation"){ + } else if (kind != "effective" && kind != "elastic") { throw CanteraError("ElectronCrossSection::validate", "'{}' is an unknown type of cross section data.", kind); } diff --git a/src/plasma/PlasmaPhase.cpp b/src/plasma/PlasmaPhase.cpp index 163a9aaaf3b..e6c82bd03a5 100644 --- a/src/plasma/PlasmaPhase.cpp +++ b/src/plasma/PlasmaPhase.cpp @@ -228,6 +228,11 @@ bool PlasmaPhase::addElectronCrossSection(shared_ptr ecs) "Already contains a data of effective/ELASTIC cross section for '{}'.", ecs->target); } + // add (0, 0) to m_crossSection + if (m_crossSections[k][0][0] != 0.0) { + m_crossSections[k][0].insert(m_crossSections[k][0].begin(), 0.0); + m_crossSections[k][1].insert(m_crossSections[k][0].begin(), 0.0); + } } m_kElastic.push_back(m_ncs); } else { From ff36f101dacdccc62d9719ceb8cc4255bb58ceb9 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 1 May 2020 13:13:01 -0400 Subject: [PATCH 122/139] delete unused codes and add documentation --- include/cantera/clib/ct.h | 2 - include/cantera/cython/wrappers.h | 1 - include/cantera/oneD/StFlow.h | 2 +- include/cantera/plasma/ElectronCrossSection.h | 6 +-- include/cantera/plasma/PlasmaPhase.h | 39 +++++++++++-------- include/cantera/thermo/Phase.h | 8 ++-- include/cantera/transport/IonGasTransport.h | 1 + interfaces/cython/cantera/_cantera.pxd | 1 + interfaces/cython/cantera/composite.py | 9 +++++ interfaces/cython/cantera/plasma.pyx | 27 ++++++++++--- src/clib/ct.cpp | 3 -- 11 files changed, 63 insertions(+), 36 deletions(-) diff --git a/include/cantera/clib/ct.h b/include/cantera/clib/ct.h index 7799fd3dd59..7cc572cea65 100644 --- a/include/cantera/clib/ct.h +++ b/include/cantera/clib/ct.h @@ -157,8 +157,6 @@ extern "C" { CANTERA_CAPI int trans_getMassFluxes(int n, const double* state1, const double* state2, double delta, double* fluxes); - CANTERA_CAPI int elect_getNetPlasmaProductionRates(int n, size_t len, double* wdot); - CANTERA_CAPI int ct_getCanteraError(int buflen, char* buf); CANTERA_CAPI int ct_setLogWriter(void* logger); CANTERA_CAPI int ct_addCanteraDirectory(size_t buflen, const char* buf); diff --git a/include/cantera/cython/wrappers.h b/include/cantera/cython/wrappers.h index bb9d59af723..65225289a69 100644 --- a/include/cantera/cython/wrappers.h +++ b/include/cantera/cython/wrappers.h @@ -5,7 +5,6 @@ #include "cantera/thermo/ThermoPhase.h" #include "cantera/transport/TransportBase.h" #include "cantera/kinetics/Kinetics.h" -#include "cantera/plasma/PlasmaElectron.h" #include "Python.h" diff --git a/include/cantera/oneD/StFlow.h b/include/cantera/oneD/StFlow.h index 1a3f66d50f9..bfae2394f36 100644 --- a/include/cantera/oneD/StFlow.h +++ b/include/cantera/oneD/StFlow.h @@ -291,7 +291,7 @@ class StFlow : public Domain1D } //! Write the net production rates at point `j` into array `m_wdot` - virtual void getWdot(doublereal* x, size_t j) { + void getWdot(doublereal* x, size_t j) { setGas(x,j); m_kin->getNetProductionRates(&m_wdot(0,j)); } diff --git a/include/cantera/plasma/ElectronCrossSection.h b/include/cantera/plasma/ElectronCrossSection.h index ce3b1118beb..66a243cdf5e 100644 --- a/include/cantera/plasma/ElectronCrossSection.h +++ b/include/cantera/plasma/ElectronCrossSection.h @@ -26,6 +26,7 @@ class ElectronCrossSection ElectronCrossSection& operator=(const ElectronCrossSection& other) = delete; ~ElectronCrossSection(); + //! Validate the cross-section data. void validate(); //! The name of the kind of electron collision @@ -41,9 +42,6 @@ class ElectronCrossSection //! j=0 is the electron energy [eV], and j=1 is the cross section [m^2]. std::vector data; - //! The mass ratio of molecule to electron - double mass_ratio; - //! The threshold of a process double threshold; @@ -51,8 +49,10 @@ class ElectronCrossSection AnyMap extra; }; +//! create an ElectronCrossSection object to store data. unique_ptr newElectronCrossSection(const AnyMap& node); +//! Get a vector of ElectronCrossSection objects to access the data. std::vector> getElectronCrossSection(const AnyValue& items); } diff --git a/include/cantera/plasma/PlasmaPhase.h b/include/cantera/plasma/PlasmaPhase.h index cd68e4667a2..97f34b5d57e 100644 --- a/include/cantera/plasma/PlasmaPhase.h +++ b/include/cantera/plasma/PlasmaPhase.h @@ -19,7 +19,7 @@ namespace Cantera { unique_ptr newElectronCrossSection(const AnyMap& node); /** - * @defgroup electron + * @defgroup plasma * This class calculates the electron energy distribution function (EEDF) in a gas * by modeling collisions between electrons and other species represented by the * class ElectronCrossSection. EEDF is used to calculate reaction rate coefficient @@ -41,10 +41,11 @@ class PlasmaPhase: public IdealGasPhase return "Plasma"; } + //! add electron cross-section data from yaml input file. void addElectronCrossSections(const AnyValue& crossSections, const AnyValue& names); - //! Add an electron cross section to this Electron. Returns `true` if the electron cross section was + //! Add an electron cross section. Returns `true` if the electron cross section was //! successfully added, or `false` if the electron cross section was ignored. virtual bool addElectronCrossSection(shared_ptr ecs); @@ -58,7 +59,7 @@ class PlasmaPhase: public IdealGasPhase return m_points; } - //! energy grid + //! energy grid [eV] double grid(size_t i) const { return m_gridCenter[i]; } @@ -67,36 +68,37 @@ class PlasmaPhase: public IdealGasPhase //! eps is the vector of electron energy [eV]. void setupGrid(size_t n, const double* eps); - //! electron diffusivity + //! electron diffusivity [m^2/s] virtual double electronDiffusivity() { throw NotImplementedError("PlasmaPhase::electronDiffusivity"); } - //! electron mobility + //! electron mobility [m^2/V/s] virtual double electronMobility() { throw NotImplementedError("PlasmaPhase::electronMobility"); } - //! mean electron energy + //! mean electron energy [eV] virtual double meanElectronEnergy() { throw NotImplementedError("PlasmaPhase::meanElectronEnergy"); } + //! electron power gain of one electron [eV/s] virtual double powerGain() { throw NotImplementedError("PlasmaPhase::powerGain"); } - //! elastic power loss + //! elastic power loss of one electron [eV/s] virtual double elasticPowerLoss() { throw NotImplementedError("PlasmaPhase::elasticPowerLoss"); } - //! inelastic power loss + //! inelastic power loss of one electron [eV/s] virtual double inelasticPowerLoss() { throw NotImplementedError("PlasmaPhase::inelasticPowerLoss"); } - //! total collision frequency + //! total collision frequency [Hz] virtual double totalCollisionFreq() { throw NotImplementedError("PlasmaPhase::totalCollisionFreq"); } @@ -114,12 +116,12 @@ class PlasmaPhase: public IdealGasPhase //! initialize Plasma. virtual void initPlasma(const AnyMap& phaseNode, const AnyMap& rootNode); - //! Reduced electric field + //! electric field [V/m] double electricField() const { return m_E; } - //! Set reduced electric field + //! Set electric field in [V/m] void setElectricField(double E) { if (m_E != E) { m_E = E; @@ -127,12 +129,12 @@ class PlasmaPhase: public IdealGasPhase } } - //! Electric field frequency + //! Electric field frequency [Hz] double electricFieldFreq() const { return m_F; } - //! Set electric field frequency + //! Set electric field frequency in [Hz] void setElectricFieldFreq(double F) { if (m_F != F) { m_F = F; @@ -251,13 +253,13 @@ class PlasmaPhase: public IdealGasPhase //! number of points for energy grid size_t m_points; - //! Boltzmann constant times gas temperature + //! Boltzmann constant times gas temperature [eV] double m_kT; - //! reduced electric field + //! electric field [V/m] double m_E; - //! electric field freq + //! electric field freq [Hz] double m_F; //! normalized electron energy distribution function @@ -269,8 +271,11 @@ class PlasmaPhase: public IdealGasPhase //! Mole fractions of target species of each collision process vector_fp m_moleFractions; - //! shift factor + //! shift factor. This is used for calculating the collision term. std::vector m_shiftFactor; + + //! in factor. This is used for calculating the Q matrix of + //! scattering-in processes. std::vector m_inFactor; //! Indices of elastic collisions in m_crossSections diff --git a/include/cantera/thermo/Phase.h b/include/cantera/thermo/Phase.h index d7cbd56a428..73c9ea1f39c 100644 --- a/include/cantera/thermo/Phase.h +++ b/include/cantera/thermo/Phase.h @@ -669,21 +669,23 @@ class Phase m_ndim = ndim; } - //! Electron temperature (K) + //! Electron temperature [K] virtual double electronTemperature() { return m_electron_temp; } - //! Electron mobility + //! Electron mobility [m^2/V/s] virtual double electronMobility() { return Undef; } - //! Electron diffusivity + //! Electron diffusivity [m^2/s] virtual double electronDiffusivity() { return Undef; } + //! @name Thermodynamic Properties + //!@{ //! Temperature (K). //! @return The temperature of the phase doublereal temperature() const { diff --git a/include/cantera/transport/IonGasTransport.h b/include/cantera/transport/IonGasTransport.h index 0b44f8134a2..c46670841ce 100644 --- a/include/cantera/transport/IonGasTransport.h +++ b/include/cantera/transport/IonGasTransport.h @@ -119,6 +119,7 @@ class IonGasTransport : public MixTransport //! polynomial of the collision integral for O2/O2- vector_fp m_om11_O2; + //! electron mobility which can be manually set to a value. double m_electronMobility; }; diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index d5167e7c282..c232396cea2 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -146,6 +146,7 @@ cdef extern from "cantera/plasma/ElectronCrossSection.h" namespace "Cantera": string kind string target string product + double threshold vector[vector[double]] data cdef shared_ptr[CxxElectronCrossSection] CxxNewElectronCrossSection "newElectronCrossSection" (CxxAnyMap&) except +translate_exception diff --git a/interfaces/cython/cantera/composite.py b/interfaces/cython/cantera/composite.py index 1155cfcfece..d777eadd1e0 100644 --- a/interfaces/cython/cantera/composite.py +++ b/interfaces/cython/cantera/composite.py @@ -99,6 +99,15 @@ class Solution(ThermoPhase, Kinetics, Transport): class Plasma(PlasmaPhase, Kinetics, Transport): + """ + A class for plasma-reacting solutions. Class `Plasma` derives from classes `PlasmaPhase`, `Kinetics`, and + `Transport`. + + The most common way to instantiate `Plasma` objects is by using a phase + definition, species and reactions defined in an input file:: + + gas = ct.Plasma('oxygen_plasma.yaml') + """ __slots__ = () diff --git a/interfaces/cython/cantera/plasma.pyx b/interfaces/cython/cantera/plasma.pyx index af2660bac86..e3656bcf259 100644 --- a/interfaces/cython/cantera/plasma.pyx +++ b/interfaces/cython/cantera/plasma.pyx @@ -23,7 +23,7 @@ cdef class PlasmaPhase(ThermoPhase): return self.plasma.electronTemperature() property electron_mobility: - """electron mobility [m^2/V/s)]""" + """electron mobility [m^2/V/s]""" def __get__(self): return self.plasma.electronMobility() @@ -38,11 +38,17 @@ cdef class PlasmaPhase(ThermoPhase): return self.plasma.totalCollisionFreq() def plasma_process_rate_coefficient(self, k): - """rate coefficient of process k""" + """ + rate coefficient of process k in inverse + number density [m^3/s]. + """ return self.plasma.rateCoefficient(k) def plasma_process_reverse_rate_coefficient(self, k): - """reverse rate coefficient of process k""" + """ + reverse rate coefficient of process k in inverse + number density [m^3/s]. + """ return self.plasma.reverseRateCoefficient(k) property electron_power_gain: @@ -121,15 +127,19 @@ cdef class PlasmaPhase(ThermoPhase): self.plasma.setElectricFieldFreq(F) def electron_collision_target(self, k): + """ The target of the collision process. """ return pystr(self.plasma.target(k)) def electron_collision_kind(self, k): + """ The kind of the collision process. """ return pystr(self.plasma.kind(k)) def electron_collision_product(self,k): + """ The product of the collision. process """ return pystr(self.plasma.product(k)) def electron_collision_threshold(self, k): + """ The threhols of the collision process. """ return self.plasma.threshold(k) @@ -192,20 +202,25 @@ cdef class ElectronCrossSection: return cross_section property kind: - """ The kind of the collision. """ + """ The kind of the collision process. """ def __get__(self): return pystr(self.electron_cross_section.kind) property target: - """ The target of the collision. """ + """ The target of the collision process. """ def __get__(self): return pystr(self.electron_cross_section.target) property product: - """ The product of the collision. """ + """ The product of the collision process. """ def __get__(self): return pystr(self.electron_cross_section.product) + property threshold: + """ The threhols of the collision process. """ + def __get__(self): + return self.electron_cross_section.threshold + property process: """ The process of the collision. Ex. "O2 => O2^+" (ionization) diff --git a/src/clib/ct.cpp b/src/clib/ct.cpp index 442a228cb44..a9c40a2cb24 100644 --- a/src/clib/ct.cpp +++ b/src/clib/ct.cpp @@ -17,7 +17,6 @@ // Cantera includes #include "cantera/kinetics/KineticsFactory.h" #include "cantera/transport/TransportFactory.h" -#include "cantera/plasma/PlasmaElectronFactory.h" #include "cantera/base/ctml.h" #include "cantera/kinetics/importKinetics.h" #include "cantera/thermo/ThermoFactory.h" @@ -31,13 +30,11 @@ using namespace Cantera; typedef Cabinet ThermoCabinet; typedef Cabinet KineticsCabinet; typedef Cabinet TransportCabinet; -typedef Cabinet ElectronCabinet; typedef Cabinet XmlCabinet; template<> ThermoCabinet* ThermoCabinet::s_storage = 0; template<> KineticsCabinet* KineticsCabinet::s_storage = 0; template<> TransportCabinet* TransportCabinet::s_storage = 0; -template<> ElectronCabinet* ElectronCabinet::s_storage = 0; /** * Exported functions. From 16119ea90e5c63fd78a5beb8c5a1198c7bc8d7f4 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Fri, 1 May 2020 13:23:42 -0400 Subject: [PATCH 123/139] [interface] delete parsing of electron_reaction --- interfaces/cython/cantera/ctml_writer.py | 110 ----------------------- 1 file changed, 110 deletions(-) diff --git a/interfaces/cython/cantera/ctml_writer.py b/interfaces/cython/cantera/ctml_writer.py index 90b2add3864..3eb2b6f2cd0 100644 --- a/interfaces/cython/cantera/ctml_writer.py +++ b/interfaces/cython/cantera/ctml_writer.py @@ -1088,79 +1088,6 @@ def build(self, p, name='', a=None): c.addChild('m', repr(cov[2])) addFloat(c, 'e', cov[3], fmt = '%f', defunits = _ue) -class ElectronArrhenius(rate_expression): - def __init__(self, - A = 0.0, - b = 0.0, - E1 = 0.0, - E2 = 0.0, - coverage = []): - """ - :param A: - The pre-exponential coefficient. Required input. If entered without - units, the units will be computed considering all factors that - affect the units. The resulting units string is written to the CTML - file individually for each reaction pre-exponential coefficient. - :param b: - The temperature exponent. Dimensionless. Default: 0.0. - :param E: - Activation energy. Default: 0.0. - :param coverage: For a single coverage dependency, a list with four - elements: the species name followed by the three coverage - parameters. For multiple coverage dependencies, a list of lists - containing the individual sets of coverage parameters. Only used for - surface and edge reactions. - """ - - self._c = [A, b, E1, E2] - - if coverage: - if isinstance(coverage[0], basestring): - self._cov = [coverage] - else: - self._cov = coverage - for cov in self._cov: - if len(cov) != 4: - raise CTI_Error("Incorrect number of coverage parameters") - else: - self._cov = None - - - def build(self, p, name='', a=None): - if a is None: - a = p.addChild('ElectronArrhenius') - if name: - a['name'] = name - - # if a pure number is entered for A, multiply by the conversion - # factor to SI and write it to CTML as a pure number. Otherwise, - # pass it as-is through to CTML with the unit string. - if isnum(self._c[0]): - addFloat(a,'A',self._c[0]*self.unit_factor, fmt = '%14.6E') - elif len(self._c[0]) == 2 and self._c[0][1] == '/site': - addFloat(a,'A',self._c[0][0]/self.rxn_phase._sitedens, - fmt = '%14.6E') - else: - addFloat(a,'A',self._c[0], fmt = '%14.6E') - - # The b coefficient should be dimensionless, so there is no - # need to use 'addFloat' - a.addChild('b', repr(self._c[1])) - - # If a pure number is entered for the activation energy, - # add the default units, otherwise use the supplied units. - addFloat(a,'E1', self._c[2], fmt = '%f', defunits = _ue) - addFloat(a,'E2', self._c[3], fmt = '%f', defunits = _ue) - - # for surface reactions, a coverage dependence may be specified. - if self._cov: - for cov in self._cov: - c = a.addChild('coverage') - c['species'] = cov[0] - addFloat(c, 'a', cov[1], fmt = '%f') - c.addChild('m', repr(cov[2])) - addFloat(c, 'e', cov[3], fmt = '%f', defunits = _ue) - class stick(Arrhenius): """ A rate expression for a surface reaction given as a sticking probability, @@ -1376,8 +1303,6 @@ def build(self, p): kfnode = r.addChild('rateCoeff') if self._type == '': self._kf = [self._kf] - elif self._type == 'electron': - self._kf = [self._kf] elif self._type == 'surface': self._kf = [self._kf] if self._rate_coeff_type: @@ -1401,11 +1326,6 @@ def build(self, p): for kf in self._kf: if isinstance(kf, rate_expression): k = kf - elif self._type == 'electron': - if len(kf) == 4: - k = ElectronArrhenius(A = kf[0], b = kf[1], E1 = kf[2], E2 = kf[3]) - else: - k = ElectronArrhenius(A = kf[0], b = kf[1], E1 = kf[2]) else: k = Arrhenius(A = kf[0], b = kf[1], E = kf[2]) if isinstance(kf, stick): @@ -1435,36 +1355,6 @@ def build(self, p): #------------------- -class electron_reaction(reaction): - """ - An electron reaction. - """ - def __init__(self, - equation = '', - kf = None, - id = '', - order = '', - options = []): - r""" - :param equation: - A string specifying the chemical equation. The reaction can be - written in either the association or dissociation directions, and - may be reversible or irreversible. - :param kf: - The rate coefficient for the forward direction. If a sequence of - three numbers is given, these will be interpreted as [A, b, E1, E2] in - the modified Arrhenius function :math:`A T^b exp(-E1/\hat{R}T) exp(-E2/\hat{R}Te)`. - :param id: - An optional identification string. If omitted, it defaults to a - four-digit numeric string beginning with 0001 for the first - reaction in the file. - :param options: Processing options, as described in - `Options `__. - """ - reaction.__init__(self, equation, kf, id, '', options) - self._type = 'electron' - - class three_body_reaction(reaction): """ A three-body reaction. From 6406b7a714eaec74ceb7796eaed80304eda0f13c Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 3 May 2020 14:16:09 -0400 Subject: [PATCH 124/139] [plasma] add warn_user --- src/plasma/PlasmaPhase.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/plasma/PlasmaPhase.cpp b/src/plasma/PlasmaPhase.cpp index e6c82bd03a5..63ac16b2cc9 100644 --- a/src/plasma/PlasmaPhase.cpp +++ b/src/plasma/PlasmaPhase.cpp @@ -180,12 +180,9 @@ void PlasmaPhase::checkSpeciesNoCrossSection() // warn that a specific species needs cross-section data. for (size_t k : m_kOthers) { if (moleFraction(k) > m_moleFractionThreshold) { - writelog("Cantera::PlasmaPhase::checkMinorSpeciesMoleFraction"); - writelog("\n"); - writelog("Warning: The mole fraction of species {} is more than 0.01", - speciesName(k)); - writelog(" but it has no data of cross section."); - writelog("\n"); + warn_user("Cantera::PlasmaPhase::checkSpeciesNoCrossSection", + "Warning: The mole fraction of species {} is more than 0.01 " + "but it has no cross-section data", speciesName(k)); } } } From 7939f5271fea76650efbb02b1a7f34d27c0ce76b Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 3 May 2020 18:57:48 -0400 Subject: [PATCH 125/139] [plasma] update documentation --- include/cantera/plasma/PlasmaPhase.h | 15 ++++++--------- include/cantera/plasma/WeaklyIonizedGas.h | 10 +++++++--- interfaces/cython/cantera/base.pyx | 2 +- interfaces/cython/cantera/plasma.pyx | 2 +- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/include/cantera/plasma/PlasmaPhase.h b/include/cantera/plasma/PlasmaPhase.h index 97f34b5d57e..0f7e0513f45 100644 --- a/include/cantera/plasma/PlasmaPhase.h +++ b/include/cantera/plasma/PlasmaPhase.h @@ -18,19 +18,16 @@ namespace Cantera { unique_ptr newElectronCrossSection(const AnyMap& node); + /** - * @defgroup plasma - * This class calculates the electron energy distribution function (EEDF) in a gas - * by modeling collisions between electrons and other species represented by the - * class ElectronCrossSection. EEDF is used to calculate reaction rate coefficient - * for plasma reaction and electron temperature for electron-temperature reaction - * used in kinetics, and diffusivity/mobility of electron in transport. - */ + * Base class for a phase with plasma properties. This class manages the + * computational grid, grid cache, cross-section data, and updating + * independent variables such as gas temperature and pressure. + * variables -/*! * Class Plasma is the base class which manages the grid and grid cache, * cross-section data, and updating temperature and gas composition. - * @ingroup electron + * @ingroup phase */ class PlasmaPhase: public IdealGasPhase { diff --git a/include/cantera/plasma/WeaklyIonizedGas.h b/include/cantera/plasma/WeaklyIonizedGas.h index 5b6f268157a..958096297f6 100644 --- a/include/cantera/plasma/WeaklyIonizedGas.h +++ b/include/cantera/plasma/WeaklyIonizedGas.h @@ -17,7 +17,11 @@ namespace Cantera typedef Eigen::SparseMatrix SparseMat; /** - * This class calculates the properties of electron in a weakly ionized gas. + * This class calculates the electron energy distribution function (EEDF) in a weakly + * ionized gas by modeling collisions between electrons and other species represented + * by the class ElectronCrossSection. EEDF is used to calculate reaction rate coefficient + * for plasma reaction and electron temperature for electron-temperature reaction + * used in kinetics, and diffusivity/mobility of electron in transport. * Only electron-neutral collisions are considered for calculating the * electron energy distribution function (EEDF). Equation of EEDF becomes, * \f[ @@ -78,7 +82,7 @@ typedef Eigen::SparseMatrix SparseMat; * "The umist database for astrochemistry 2012," * Astronomy & Astrophysics 550 (2013) A36. * doi: https://doi.org/10.1051/0004-6361/201220465 - * @ingroup electron + * @ingroup plasma */ class WeaklyIonizedGas: public PlasmaPhase { @@ -86,7 +90,7 @@ class WeaklyIonizedGas: public PlasmaPhase WeaklyIonizedGas(); virtual std::string type() const { - return "WeakIonizedGas"; + return "WeaklyIonizedGas"; } virtual double electronDiffusivity(); diff --git a/interfaces/cython/cantera/base.pyx b/interfaces/cython/cantera/base.pyx index e49607aebc0..42b75c21939 100644 --- a/interfaces/cython/cantera/base.pyx +++ b/interfaces/cython/cantera/base.pyx @@ -134,7 +134,7 @@ cdef class _SolutionBase: raise NotImplementedError(msg) # Plasma - if pystr(self.thermo.type()) in ("WeakIonizedGas"): + if pystr(self.thermo.type()) in ("WeaklyIonizedGas"): self.thermo.initPlasma(phaseNode, root) # Kinetics diff --git a/interfaces/cython/cantera/plasma.pyx b/interfaces/cython/cantera/plasma.pyx index e3656bcf259..6658b998b00 100644 --- a/interfaces/cython/cantera/plasma.pyx +++ b/interfaces/cython/cantera/plasma.pyx @@ -7,7 +7,7 @@ import weakref cdef class PlasmaPhase(ThermoPhase): """ A class representing a plasma phase""" def __cinit__(self, *args, **kwargs): - if pystr(self.thermo.type()) not in ("WeakIonizedGas"): + if pystr(self.thermo.type()) not in ("WeaklyIonizedGas"): raise TypeError('Underlying ThermoPhase object is of the wrong type.') self.plasma = (self.thermo) From f3dfd6b694f94bd2961f68b146b44aacf8a30a30 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 4 May 2020 17:30:14 -0400 Subject: [PATCH 126/139] update warn meg --- src/kinetics/PlasmaKinetics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kinetics/PlasmaKinetics.cpp b/src/kinetics/PlasmaKinetics.cpp index 8b5aa953df7..674c63f1721 100644 --- a/src/kinetics/PlasmaKinetics.cpp +++ b/src/kinetics/PlasmaKinetics.cpp @@ -52,7 +52,7 @@ void PlasmaKinetics::addPlasmaReaction(PlasmaReaction& r) } if (!found) { throw CanteraError("PlasmaKinetics::addPlasmaReaction", - "Cannot find corresponding electron ", + "Cannot find corresponding electron " "collision process for {}", r.equation()); } } From a6d95763989365c4d497bd2e6e6b24fdd72d25b5 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 4 May 2020 20:24:33 -0400 Subject: [PATCH 127/139] update warn msg --- src/plasma/PlasmaPhase.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/plasma/PlasmaPhase.cpp b/src/plasma/PlasmaPhase.cpp index 63ac16b2cc9..842146b02a6 100644 --- a/src/plasma/PlasmaPhase.cpp +++ b/src/plasma/PlasmaPhase.cpp @@ -221,15 +221,10 @@ bool PlasmaPhase::addElectronCrossSection(shared_ptr ecs) for (size_t k = 0; k < m_ncs; k++) { if (target(k) == ecs->target) if (kind(k) == "elastic" || kind(k) == "effective") { - throw CanteraError("PlasmaPhase::addElectronCrossSection", + throw CanteraError("PlasmaPhase::addElectronCrossSection" "Already contains a data of effective/ELASTIC cross section for '{}'.", ecs->target); } - // add (0, 0) to m_crossSection - if (m_crossSections[k][0][0] != 0.0) { - m_crossSections[k][0].insert(m_crossSections[k][0].begin(), 0.0); - m_crossSections[k][1].insert(m_crossSections[k][0].begin(), 0.0); - } } m_kElastic.push_back(m_ncs); } else { From abf6c37edf456ed03ed67d95e27cfef45d9b99ab Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Mon, 4 May 2020 20:44:15 -0400 Subject: [PATCH 128/139] fix add (0,0) --- src/plasma/PlasmaPhase.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/plasma/PlasmaPhase.cpp b/src/plasma/PlasmaPhase.cpp index 842146b02a6..6f1341daf27 100644 --- a/src/plasma/PlasmaPhase.cpp +++ b/src/plasma/PlasmaPhase.cpp @@ -226,6 +226,11 @@ bool PlasmaPhase::addElectronCrossSection(shared_ptr ecs) ecs->target); } } + // add (0, 0) to m_crossSection + if (m_crossSections[m_ncs][0][0] != 0.0) { + m_crossSections[m_ncs][0].insert(m_crossSections[m_ncs][0].begin(), 0.0); + m_crossSections[m_ncs][1].insert(m_crossSections[m_ncs][1].begin(), 0.0); + } m_kElastic.push_back(m_ncs); } else { m_kInelastic.push_back(m_ncs); From f68659cf18af43be6d6fabf303ce9df32c6efa41 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Tue, 5 May 2020 08:48:48 -0400 Subject: [PATCH 129/139] [test, data] update test_plasma.py and oxygen_plasma.yaml --- data/inputs/oxygen_plasma.yaml | 2 +- interfaces/cython/cantera/test/test_plasma.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data/inputs/oxygen_plasma.yaml b/data/inputs/oxygen_plasma.yaml index 765f2f7efdd..245b65786ea 100644 --- a/data/inputs/oxygen_plasma.yaml +++ b/data/inputs/oxygen_plasma.yaml @@ -1,4 +1,4 @@ -units: {length: cm, quantity: mol, activation-energy: K} +units: {length: cm, quantity: molec, activation-energy: K} phases: - name: gas diff --git a/interfaces/cython/cantera/test/test_plasma.py b/interfaces/cython/cantera/test/test_plasma.py index 6e97c45d2ca..96426086b2a 100644 --- a/interfaces/cython/cantera/test/test_plasma.py +++ b/interfaces/cython/cantera/test/test_plasma.py @@ -15,9 +15,9 @@ def setUp(self): def test_electron_properties(self): self.assertNear(self.gas.electron_temperature, 13113, 1e-3) - self.assertNear(self.gas.electron_mobility, 0.3985, 1e-4) - self.assertNear(self.gas.electron_diffusivity, 0.5268, 1e-4) - self.assertNear(self.gas.plasma_process_rate_coefficient(5), 1.55e-16, 1e-4) + self.assertNear(self.gas.electron_mobility, 0.3985, 1e-3) + self.assertNear(self.gas.electron_diffusivity, 0.5279, 1e-3) + self.assertNear(self.gas.plasma_process_rate_coefficient(5), 1.55e-16, 1e-3) self.assertNear(self.gas.electron_total_collision_frequency, 3.433e11, 1e-3) self.assertNear(self.gas.electron_power_gain, 3.9811e9, 1e-3) self.assertNear(self.gas.electron_elastic_power_loss, 2.4114e7, 1e-3) From bf1889ce35e5660abdbc1e94442af84a6b9a7d22 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Wed, 13 May 2020 23:09:56 -0400 Subject: [PATCH 130/139] change the license url to https://cantera.org/license.txt --- include/cantera/kinetics/PlasmaKinetics.h | 2 +- include/cantera/plasma/ElectronCrossSection.h | 2 +- include/cantera/plasma/PlasmaPhase.h | 2 +- include/cantera/plasma/WeaklyIonizedGas.h | 2 +- src/kinetics/PlasmaKinetics.cpp | 2 +- src/plasma/ElectronCrossSection.cpp | 2 +- src/plasma/PlasmaPhase.cpp | 2 +- src/plasma/WeaklyIonizedGas.cpp | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/cantera/kinetics/PlasmaKinetics.h b/include/cantera/kinetics/PlasmaKinetics.h index 75add494b93..7216674322a 100644 --- a/include/cantera/kinetics/PlasmaKinetics.h +++ b/include/cantera/kinetics/PlasmaKinetics.h @@ -4,7 +4,7 @@ */ // This file is part of Cantera. See License.txt in the top-level directory or -// at http://www.cantera.org/license.txt for license and copyright information. +// at https://cantera.org/license.txt for license and copyright information. #ifndef CT_PLASMAKINETICS_H #define CT_PLASMAKINETICS_H diff --git a/include/cantera/plasma/ElectronCrossSection.h b/include/cantera/plasma/ElectronCrossSection.h index 66a243cdf5e..7766e7d0a79 100644 --- a/include/cantera/plasma/ElectronCrossSection.h +++ b/include/cantera/plasma/ElectronCrossSection.h @@ -1,7 +1,7 @@ //! @file ElectronCrossSection.h Declaration for class Cantera::ElectronCrossSection. // This file is part of Cantera. See License.txt in the top-level directory or -// at https://www.cantera.org/license.txt for license and copyright information. +// at https://cantera.org/license.txt for license and copyright information. #ifndef CT_ELECTRONCROSSSECTION_H #define CT_ELECTRONCROSSSECTION_H diff --git a/include/cantera/plasma/PlasmaPhase.h b/include/cantera/plasma/PlasmaPhase.h index 0f7e0513f45..db539fca641 100644 --- a/include/cantera/plasma/PlasmaPhase.h +++ b/include/cantera/plasma/PlasmaPhase.h @@ -4,7 +4,7 @@ */ // This file is part of Cantera. See License.txt in the top-level directory or -// at https://www.cantera.org/license.txt for license and copyright information. +// at https://cantera.org/license.txt for license and copyright information. #ifndef CT_PLASMAPHASE_H #define CT_PLASMAPHASE_H diff --git a/include/cantera/plasma/WeaklyIonizedGas.h b/include/cantera/plasma/WeaklyIonizedGas.h index 958096297f6..bcd4737c139 100644 --- a/include/cantera/plasma/WeaklyIonizedGas.h +++ b/include/cantera/plasma/WeaklyIonizedGas.h @@ -4,7 +4,7 @@ */ // This file is part of Cantera. See License.txt in the top-level directory or -// at https://www.cantera.org/license.txt for license and copyright information. +// at https://cantera.org/license.txt for license and copyright information. #ifndef CT_WEAKLYIONIZEDGAS_H #define CT_WEAKLYIONIZEDGAS_H diff --git a/src/kinetics/PlasmaKinetics.cpp b/src/kinetics/PlasmaKinetics.cpp index 674c63f1721..606eb71f8a0 100644 --- a/src/kinetics/PlasmaKinetics.cpp +++ b/src/kinetics/PlasmaKinetics.cpp @@ -3,7 +3,7 @@ */ // This file is part of Cantera. See License.txt in the top-level directory or -// at http://www.cantera.org/license.txt for license and copyright information. +// at https://cantera.org/license.txt for license and copyright information. #include "cantera/kinetics/PlasmaKinetics.h" diff --git a/src/plasma/ElectronCrossSection.cpp b/src/plasma/ElectronCrossSection.cpp index 4de5aea6309..415a1aa6e4c 100644 --- a/src/plasma/ElectronCrossSection.cpp +++ b/src/plasma/ElectronCrossSection.cpp @@ -1,5 +1,5 @@ // This file is part of Cantera. See License.txt in the top-level directory or -// at https://www.cantera.org/license.txt for license and copyright information. +// at https://cantera.org/license.txt for license and copyright information. #include "cantera/plasma/ElectronCrossSection.h" diff --git a/src/plasma/PlasmaPhase.cpp b/src/plasma/PlasmaPhase.cpp index 6f1341daf27..15f8bba3405 100644 --- a/src/plasma/PlasmaPhase.cpp +++ b/src/plasma/PlasmaPhase.cpp @@ -1,5 +1,5 @@ // This file is part of Cantera. See License.txt in the top-level directory or -// at https://www.cantera.org/license.txt for license and copyright information. +// at https://cantera.org/license.txt for license and copyright information. #include "cantera/plasma/PlasmaPhase.h" #include "cantera/base/stringUtils.h" diff --git a/src/plasma/WeaklyIonizedGas.cpp b/src/plasma/WeaklyIonizedGas.cpp index 29125c71b2e..3006f247701 100644 --- a/src/plasma/WeaklyIonizedGas.cpp +++ b/src/plasma/WeaklyIonizedGas.cpp @@ -1,5 +1,5 @@ // This file is part of Cantera. See License.txt in the top-level directory or -// at https://www.cantera.org/license.txt for license and copyright information. +// at https://cantera.org/license.txt for license and copyright information. #include "cantera/plasma/WeaklyIonizedGas.h" #include "cantera/base/utilities.h" From eb87a6514f881c13eb14697a275982edc9f64ce7 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 14 May 2020 11:14:37 -0400 Subject: [PATCH 131/139] [plasma] fix newElectronCrossSection --- src/plasma/ElectronCrossSection.cpp | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/plasma/ElectronCrossSection.cpp b/src/plasma/ElectronCrossSection.cpp index 415a1aa6e4c..aaf103a4121 100644 --- a/src/plasma/ElectronCrossSection.cpp +++ b/src/plasma/ElectronCrossSection.cpp @@ -36,21 +36,8 @@ unique_ptr newElectronCrossSection(const AnyMap& node) ecs->kind = node["kind"].asString(); ecs->target = node["target"].asString(); ecs->data = node["data"].asVector(); - if (ecs->kind != "effective" && ecs->kind != "elastic") { - ecs->threshold = node["threshold"].asDouble(); - ecs->product = node["product"].asString(); - } - - // Store all unparsed keys in the "extra" map - const static std::set known_keys{ - "kind", "target", "product", "data", "threshold" - }; - - for (const auto& item : node) { - if (known_keys.count(item.first) == 0) { - ecs->extra[item.first] = item.second; - } - } + ecs->threshold = node.getDouble("threshold", 0.0); + ecs->product = node.getString("product", ecs->target); return ecs; } From af89a53abcedcafa42ca1461140550a929537376 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 14 May 2020 13:24:57 -0400 Subject: [PATCH 132/139] move yaml files to correct folder --- data/{inputs => }/oxygen_cross_sections.yaml | 0 data/{inputs => }/oxygen_plasma.yaml | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename data/{inputs => }/oxygen_cross_sections.yaml (100%) rename data/{inputs => }/oxygen_plasma.yaml (100%) diff --git a/data/inputs/oxygen_cross_sections.yaml b/data/oxygen_cross_sections.yaml similarity index 100% rename from data/inputs/oxygen_cross_sections.yaml rename to data/oxygen_cross_sections.yaml diff --git a/data/inputs/oxygen_plasma.yaml b/data/oxygen_plasma.yaml similarity index 100% rename from data/inputs/oxygen_plasma.yaml rename to data/oxygen_plasma.yaml From ac9638fd32837ed4022726ba4422ef54b302fdd9 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 14 May 2020 22:29:59 -0400 Subject: [PATCH 133/139] [interface] update plasma.pyx --- interfaces/cython/cantera/plasma.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interfaces/cython/cantera/plasma.pyx b/interfaces/cython/cantera/plasma.pyx index 6658b998b00..6f727d739c0 100644 --- a/interfaces/cython/cantera/plasma.pyx +++ b/interfaces/cython/cantera/plasma.pyx @@ -7,7 +7,7 @@ import weakref cdef class PlasmaPhase(ThermoPhase): """ A class representing a plasma phase""" def __cinit__(self, *args, **kwargs): - if pystr(self.thermo.type()) not in ("WeaklyIonizedGas"): + if pystr(self.thermo.type()) != "WeaklyIonizedGas": raise TypeError('Underlying ThermoPhase object is of the wrong type.') self.plasma = (self.thermo) From 2d83a56fa6d1ed62c94e9eb2686e788df3a0f8d5 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 14 May 2020 22:36:08 -0400 Subject: [PATCH 134/139] [plasma] fix mass ratio --- src/plasma/WeaklyIonizedGas.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plasma/WeaklyIonizedGas.cpp b/src/plasma/WeaklyIonizedGas.cpp index 3006f247701..a97b4b4f301 100644 --- a/src/plasma/WeaklyIonizedGas.cpp +++ b/src/plasma/WeaklyIonizedGas.cpp @@ -51,7 +51,7 @@ void WeaklyIonizedGas::calculateTotalElasticCrossSection() vector_fp& x = m_crossSections[k][0]; vector_fp& y = m_crossSections[k][1]; for (size_t i = 0; i < m_points; i++) { - double mass_ratio = ElectronMass / (Dalton * molecularWeight(m_kTargets[k])); + double mass_ratio = ElectronMass / (molecularWeight(m_kTargets[k]) / Avogadro); m_sigmaElastic[i] += 2.0 * mass_ratio * moleFraction(m_kTargets[k]) * linearInterp(m_gridEdge[i], x, y); } From 72ef8e439bb8172ff3ae1ffdc579003e506ba47e Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Thu, 14 May 2020 22:59:48 -0400 Subject: [PATCH 135/139] [plasma] delete m_chemionRate --- include/cantera/plasma/WeaklyIonizedGas.h | 3 --- src/plasma/WeaklyIonizedGas.cpp | 6 +----- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/include/cantera/plasma/WeaklyIonizedGas.h b/include/cantera/plasma/WeaklyIonizedGas.h index bcd4737c139..68a1bbfd66c 100644 --- a/include/cantera/plasma/WeaklyIonizedGas.h +++ b/include/cantera/plasma/WeaklyIonizedGas.h @@ -211,9 +211,6 @@ class WeaklyIonizedGas: public PlasmaPhase //! vector of total elastic cross section weighted with mass ratio vector_fp m_sigmaElastic; - - //! Set chemionization scattering-in rate - double m_chemionScatRate; }; } diff --git a/src/plasma/WeaklyIonizedGas.cpp b/src/plasma/WeaklyIonizedGas.cpp index a97b4b4f301..eabcadd4c93 100644 --- a/src/plasma/WeaklyIonizedGas.cpp +++ b/src/plasma/WeaklyIonizedGas.cpp @@ -21,7 +21,6 @@ double norm(const Eigen::VectorXd& f, const vector_fp& grid) } WeaklyIonizedGas::WeaklyIonizedGas() - : m_chemionScatRate(0.0) { } @@ -257,9 +256,6 @@ Eigen::VectorXd WeaklyIonizedGas::iterate(Eigen::VectorXd& f0, double delta) A *= delta; A += I; - // add chemionization scattering-in rate at the first grid - f0(0) += m_chemionScatRate; - // solve f0 Eigen::SparseLU solver(A); Eigen::VectorXd f1 = solver.solve(f0); @@ -295,7 +291,7 @@ Eigen::VectorXd WeaklyIonizedGas::converge(Eigen::VectorXd& f0) double WeaklyIonizedGas::netProductionFreq(Eigen::VectorXd& f0) { - double nu = m_chemionScatRate; + double nu = 0.0; vector_fp g = vector_g(f0); for (size_t k = 0; k < m_ncs; k++) { From 75a327bc02d4896594e723eec3482a6b20f36863 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 16 May 2020 14:44:18 -0400 Subject: [PATCH 136/139] [plasma] fix reverseRateCoefficient --- include/cantera/plasma/PlasmaPhase.h | 3 +++ src/plasma/PlasmaPhase.cpp | 11 +++++++++++ src/plasma/WeaklyIonizedGas.cpp | 9 +++------ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/include/cantera/plasma/PlasmaPhase.h b/include/cantera/plasma/PlasmaPhase.h index db539fca641..3f65537b91f 100644 --- a/include/cantera/plasma/PlasmaPhase.h +++ b/include/cantera/plasma/PlasmaPhase.h @@ -328,6 +328,9 @@ class PlasmaPhase: public IdealGasPhase //! The energy boundaries of the overlap of cell i and j std::vector> m_eps; + //! The cross section at the center of a cell + std::vector m_sigma_offset; + //! cross section data. m_crossSections[i][j][k] where i is the specific process, //! j=0 is the vector of electron energy [eV], j=1 is the vector of cross section, and // k is the index of vector. diff --git a/src/plasma/PlasmaPhase.cpp b/src/plasma/PlasmaPhase.cpp index 15f8bba3405..6e096b09dc5 100644 --- a/src/plasma/PlasmaPhase.cpp +++ b/src/plasma/PlasmaPhase.cpp @@ -101,6 +101,8 @@ void PlasmaPhase::setGridCache() { m_sigma.clear(); m_sigma.resize(m_ncs); + m_sigma_offset.clear(); + m_sigma_offset.resize(m_ncs); m_eps.clear(); m_eps.resize(m_ncs); m_j.clear(); @@ -159,6 +161,15 @@ void PlasmaPhase::setGridCache() vector_fp eps{nodes[i], nodes[i+1]}; m_eps[k].push_back(eps); } + + // construct sigma_offset + vector_fp x_offset = m_crossSections[k][0]; + for (auto& element : x_offset) { + element -= threshold(k); + } + for (size_t i = 0; i < m_points; i++) { + m_sigma_offset[k].push_back(linearInterp(m_gridCenter[i], x_offset, y)); + } } } diff --git a/src/plasma/WeaklyIonizedGas.cpp b/src/plasma/WeaklyIonizedGas.cpp index eabcadd4c93..088a802877b 100644 --- a/src/plasma/WeaklyIonizedGas.cpp +++ b/src/plasma/WeaklyIonizedGas.cpp @@ -425,14 +425,11 @@ double WeaklyIonizedGas::rateCoefficient(size_t k) double WeaklyIonizedGas::reverseRateCoefficient(size_t k) { calculateDistributionFunction(); - vector_fp g = vector_g(m_f0); - SparseMat Q = matrix_Q(g, k); - Eigen::VectorXd s = Q * m_f0; - double sum = 0.0; + vector_fp y(m_points, 0.0); for (size_t i = 0; i < m_points; i++) { - sum += s(i); + y[i] = (m_gridCenter[i] + threshold(k)) * m_sigma_offset[k][i] * m_f0(i); } - return sum; + return m_gamma * simpsonQuadrature(m_gridCenter, y); } double WeaklyIonizedGas::meanElectronEnergy() From 6f67fc857d1e86df7f71d310b3c26992c2503e55 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 16 May 2020 19:49:55 -0400 Subject: [PATCH 137/139] [plasma] add documentation --- include/cantera/plasma/WeaklyIonizedGas.h | 145 ++++++++++++++++++---- 1 file changed, 122 insertions(+), 23 deletions(-) diff --git a/include/cantera/plasma/WeaklyIonizedGas.h b/include/cantera/plasma/WeaklyIonizedGas.h index 68a1bbfd66c..11a25a85cf0 100644 --- a/include/cantera/plasma/WeaklyIonizedGas.h +++ b/include/cantera/plasma/WeaklyIonizedGas.h @@ -47,41 +47,49 @@ typedef Eigen::SparseMatrix SparseMat; * \f$ \tilde{C}_{0,k} \f$ represents the rate of change in EEDF due to collisions, * and \f$ F_0 \f$ is the normalized EEDF. * - * The collision terms are, + * The inelastic collision terms are, * \f[ - * \tilde{C}_{0,k=elastic} = \gamma X_k \frac{2 m}{M_k} \frac{d}{d \epsilon} - * \left[\epsilon^2 \sigma_k \left( F_0 + \frac{k_B T}{e} \frac{d F_0}{\epsilon} \right) \right], - * \f] - * \f[ - * \tilde{C}_{0,k=inelastic} = -\gamma X_k \epsilon \sigma_k F_0 - * \big|^{\epsilon=\epsilon}_{\epsilon=\epsilon + u_k} + * \tilde{C}_{0,k=excitation} = -\gamma X_k \epsilon \sigma_k F_0 + * \big|^{\epsilon=\epsilon}_{\epsilon=\epsilon + u_k}, * \f] * \f[ * \tilde{C}_{0,k=ionization} = -\gamma X_k \epsilon \sigma_k F_0 - * \big|^{\epsilon=\epsilon}_{\epsilon=2\epsilon + u_k} + * \big|^{\epsilon=\epsilon}_{\epsilon=2\epsilon + u_k}, * \f] * \f[ - * \tilde{C}_{0,k=attachment} = -\gamma X_k \epsilon \sigma_k F_0 + * \tilde{C}_{0,k=attachment} = -\gamma X_k \epsilon \sigma_k F_0. * \f] - * For exponential temporal growth model, + * The exponential temporal growth model is used to calculate G. * \f[ * G = \left[ \int_0^\infty \left(\sum_{k=ionization} X_k \sigma_k - \sum_{k=attachment} X_k \sigma_k \right) - * \epsilon F_0 d \epsilon \right] \epsilon^{1/2} F_0 + * \epsilon F_0 d \epsilon \right] \epsilon^{1/2} F_0, * \f] * where \f$ X_k \f$ is the mole fraction of the target species, and \f$ \sigma_k \f$ is the cross section. * - * Reference: + * The numerical method: \n + * For each cell i, + * \f[ + * \left[ \tilde{W} F_0 - \tilde{D} \frac{d F_0}{d \epsilon} \right]_{i+1/2} - + * \left[ \tilde{W} F_0 - \tilde{D} \frac{d F_0}{d \epsilon} \right]_{i-1/2} = + * \int_{\epsilon-1/2}^{\epsilon+1/2}\tilde{S}d\epsilon. + * \f] + * The left-hand side is discretized as shown in matrix_A(), and the right-hand side is discritized as, + * \f[ + * \int_{\epsilon - 1/2}^{\epsilon + 1/2} \tilde{S} d\epsilon = + * -\sum_{k=inelastic} X_k P_{i,k} F_{0,i} + \sum_{k=inelastic} X_k \sum_j Q_{i,j,k} F_{0,j}, + * \f] + * where \f$ P_{i,k} \f$ and \f$ Q_{i,j,k} \f$ are defined in matrix_P() and matrix_Q(), respectively. \n + * Note that references [1] and [2] are used as the blueprint of this class. Reference [1] provides the physics and + * the methametical model (govening equations), and reference [2] provides the implementation of the numerical scheme. + * + * Reference: \n * [1] G. J. M. Hagelaar and L. C. Pitchford * "Solving the Boltzmann equation to obtain electron transport * coefficients and rate coefficients for fluid models." * Plasma Sources Science and Technology 14.4 (2005): 722. - * doi: https://doi.org/10.1088/0963-0252/14/4/011 + * doi: https://doi.org/10.1088/0963-0252/14/4/011 \n * [2] A. Luque, "BOLOS: An open source solver for the Boltzmann equation," * https://github.com/aluque/bolos. - * [3] D. McElroy, C. Walsh, A. Markwick, M. Cordiner, K. Smith, T. Millar, - * "The umist database for astrochemistry 2012," - * Astronomy & Astrophysics 550 (2013) A36. - * doi: https://doi.org/10.1051/0004-6361/201220465 * @ingroup plasma */ class WeaklyIonizedGas: public PlasmaPhase @@ -93,20 +101,111 @@ class WeaklyIonizedGas: public PlasmaPhase return "WeaklyIonizedGas"; } + //! Electron diffusivity \f$ D_e \f$ in [m2/s]. + /** + * \f[ + * D_e = \frac{\gamma}{3 N} \int_0^{\infty} \frac{\epsilon} + * {\sigma_m + \bar{\nu}_i / N \gamma \epsilon^{1/2}} f_0 d\epsilon, + * \f] + * where \f$ \sigma_m \f$ is the total cross section (#m_totalCrossSectionCenter) calculated by + * calculateTotalCrossSection() and \f$ \bar{\nu}_i/N \f$ is the reduced net production frequency + * calculated by netProductionFreq(). + */ virtual double electronDiffusivity(); + + //! Electron mobility \f$ \mu_e \f$ in [m2/V/s]. + /** + * \f[ + * \mu_e = -\frac{\gamma}{3 N} \int_0^{\infty} \frac{\epsilon} + * {\sigma_m + \bar{\nu}_i / N \gamma \epsilon^{1/2}} \frac{df_0}{d\epsilon} d\epsilon, + * \f] + * where \f$ \sigma_m \f$ is the total cross section (#m_totalCrossSectionEdge) calculated by + * calculateTotalCrossSection() and \f$ \bar{\nu}_i/N \f$ is the reduced net production frequency + * calculated by netProductionFreq(). + */ virtual double electronMobility(); + + //! Mean electron energy in [eV]. + /** + * \f[ + * <\epsilon> = \int_0^{\infty} \epsilon^{3/2} f_0 d\epsilon, + * \f] + */ virtual double meanElectronEnergy(); + + //! Electron power gain of one electron in [eV/s]. + /** + * DC electric field (#m_F = 0.0): + * \f[ + * P_e = E^2 \mu_e, + * \f] + * where E is electric field strength (#m_E) and \f$ \mu_{e} \f$ is calculated by electronMobility(). + * AC electric field: + * \f[ + * P_e = E^2 \mu_{e, real}, + * \f] + * where \f$ \mu_{e, real} \f$ is calculated by realMobility(). + */ virtual double powerGain(); + + //! Elastic power loss of one electron to the gas in [eV/s]. + /** + * \f[ + * P_{elastic loss} = N \sum_{k=elastic} \gamma X_k \frac{2m_e}{M_k} \int_0^\infty + * \sigma_k \left(\epsilon^2 f_0 + \frac{k_B T}{e} \frac{df_0}{\epsilon} \right) d\epsilon, + * \f] + * where \f$ \frac{m_e}{M_k} \f$ is the mass ratio of electron to the molecule, \f$ \frac{k_B T}{e} \f$ is + * the gas temperature in eV (#m_kT). + */ virtual double elasticPowerLoss(); + + //! Inelastic power loss of one electron to the gas in [eV/s]. + /** + * \f[ + * P_{inelastic loss} = N \sum_{k=inelastic} U_k X_k \left( y_k^{low} \text{k}_k - y_k^{up} \text{k}^{rev}_k \right) + * \f] + * where \f$ U_k \f$ is the threshold energy, \f$ y_k^{up/low} \f$ is the fractional populations of the upper and lower states from bi-Maxwellian + * Boltzmann factors, and \f$ \text{k}^{rev} \f$ is the reverse rate coefficient. + */ virtual double inelasticPowerLoss(); + + //! virtual double totalCollisionFreq(); + + //! Reverse rate coefficient for the electron collision process k in [m3/s]. + /** + * \f[ + * \text{k}_{rev} = \gamma \int_0^{\infty} (\epsilon + U_k) \sigma_k(\epsilon + U_k) f_0(\epsilon) d\epsilon, + * \f] + * which can be calculated by interpolating the cross-section data on the energy grid with the offset equal + * to the threshold energy. + */ virtual double reverseRateCoefficient(size_t k); + + //! Rate coefficient for the electron collision process k in [m3/s]. + /** + * \f[ + * \text{k} = \gamma \int_0^{\infty} \epsilon \sigma_k(\epsilon) f_0(\epsilon) d\epsilon, + * \f] + * which can be calculated using matrix_P() and EEDF. + */ virtual double rateCoefficient(size_t k); - //! The real part of the mobility. This is used in power gain for case of AC. + //! The real part of the mobility \f$ \mu_{e,real} \f$. This is used in power gain for case of AC. + /** + * \f[ + * \mu_{e,real} = -\frac{\gamma}{3 N} \int_0^{\infty} \frac{Q \epsilon}{Q^2 + q^2} + * \frac{df_0}{d\epsilon} d\epsilon, \\ + * Q = \sigma_m + \frac{\bar{\nu}_i}{N \gamma \epsilon^{1/2}}, \\ + * q = \frac{\omega}{N \gamma \epsilon^{1/2}}, + * \f] + * where \f$ \sigma_m \f$ is the total cross section (#m_totalCrossSectionEdge) calculated by + * calculateTotalCrossSection(), \f$ \bar{\nu}_i/N \f$ is the reduced net production frequency + * calculated by netProductionFreq(), and \f$ \omega \f$ is the angular frequency (\f$ 2 \pi \f$ #m_F). + */ double realMobility(); - //! electron temperature + //! Electron temperature in Kelvin. //! If the reduced electric field is set, electron temperature is calculated //! from EEDF. virtual double electronTemperature(); @@ -135,7 +234,7 @@ class WeaklyIonizedGas: public PlasmaPhase double integralPQ(double a, double b, double u0, double u1, double g, double x0); - //! Vector g is used by matrix_PQ. + //! Vector g is used by matrix_P() and matrix_Q(). /** * \f[ * g_i = \frac{1}{\epsilon_{i+1} - \epsilon_{i-1}} \ln(\frac{F_{0, i+1}}{F_{0, i-1}}) @@ -146,7 +245,7 @@ class WeaklyIonizedGas: public PlasmaPhase //! The matrix of scattering-out. /** * \f[ - * P_i = \sum_{k=inelastic} \gamma X_k \int_{\epsilon_i - 1/2}^{\epsilon_i + 1/2} + * P_{i,k} = \gamma \int_{\epsilon_i - 1/2}^{\epsilon_i + 1/2} * \epsilon \sigma_k exp[(\epsilon_i - \epsilon)g_i] d \epsilon * \f] */ @@ -155,12 +254,12 @@ class WeaklyIonizedGas: public PlasmaPhase //! The matrix of scattering-in /** * \f[ - * Q_{i,j} = \sum_{k=inelastic} \gamma X_k \int_{\epsilon_1}^{\epsilon_2} + * Q_{i,j,k} = \gamma \int_{\epsilon_1}^{\epsilon_2} * \epsilon \sigma_k exp[(\epsilon_j - \epsilon)g_j] d \epsilon * \f] */ //! where the interval \f$[\epsilon_1, \epsilon_2]\f$ is the overlap of cell j, - //! and cell i shifted by the threshold energy u_k: + //! and cell i shifted by the threshold energy: /** * \f[ * \epsilon_1 = \min(\max(\epsilon_{i-1/2}+u_k, \epsilon_{j-1/2}),\epsilon_{j+1/2}), From d86054e485f010dfb8cc11d7ac5fe85b6ff88c51 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sat, 16 May 2020 21:58:48 -0400 Subject: [PATCH 138/139] [data, test] update for plasma test --- data/oxygen_plasma.yaml | 24 ++++++++++++++++++- .../cython/cantera/test/test_kinetics.py | 6 +++-- interfaces/cython/cantera/test/test_plasma.py | 4 +++- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/data/oxygen_plasma.yaml b/data/oxygen_plasma.yaml index 245b65786ea..a0645bb47fb 100644 --- a/data/oxygen_plasma.yaml +++ b/data/oxygen_plasma.yaml @@ -5,7 +5,7 @@ phases: thermo: weakly-ionized-gas elements: [O, E] species: - - species: [O2^+, O2^-] + - species: [O2^+, O2^-, O2(a1)] - gri30_ion.yaml/species: [O2, E] - gri30.yaml/species: [O] @@ -53,9 +53,31 @@ species: well-depth: 136.5 polarizability: 1.424 note: L4/89 +- name: O2(a1) + composition: {O: 2} + thermo: + model: NASA7 + temperature-ranges: [200.0, 1000.0, 6000.0] + data: + - [3.78535371, -3.2192854e-03, 1.12323443e-05, -1.17254068e-08, 4.17659585e-12, + 1.02922572e+04, 3.27320239] + - [3.45852381, 1.04045351e-03, -2.79664041e-07, 3.11439672e-11, -8.55656058e-16, + 1.02229063e+04, 4.15264119] + transport: + model: gas + geometry: linear + diameter: 2.769 + well-depth: 1836.0 + polarizability: 1.434 + rotational-relaxation: 3.8 + note: singletATcT reactions: # Kossyi et al. (1992) doi.org/10.1088/0963-0252/1/3/011 +# Kossyi (5) +- equation: E + O2 <=> E + O2(a1) + type: plasma + process: {kind: excitation, target: O2, product: O2(a1)} # Kossyi (40) - equation: O2^+ + E => O + O type: electron-temperature diff --git a/interfaces/cython/cantera/test/test_kinetics.py b/interfaces/cython/cantera/test/test_kinetics.py index b7bc6bbda8e..0cbeb6d61e7 100644 --- a/interfaces/cython/cantera/test/test_kinetics.py +++ b/interfaces/cython/cantera/test/test_kinetics.py @@ -1083,8 +1083,10 @@ def test_plasma(self): gas.TPX = 1000, ct.one_atm, 'O2:1.0' gas.set_electron_energy_grid(np.linspace(0, 50, 200)) gas.electric_field = 1e6 - self.assertNear(gas.forward_rate_constants[1], - gas.plasma_process_rate_coefficient(13) * ct.avogadro) + self.assertNear(gas.forward_rate_constants[0], + gas.plasma_process_rate_coefficient(5) * ct.avogadro) + self.assertNear(gas.reverse_rate_constants[0], + gas.plasma_process_reverse_rate_coefficient(5) * ct.avogadro) def test_modify_invalid(self): # different reaction type diff --git a/interfaces/cython/cantera/test/test_plasma.py b/interfaces/cython/cantera/test/test_plasma.py index 96426086b2a..84aafeaff9c 100644 --- a/interfaces/cython/cantera/test/test_plasma.py +++ b/interfaces/cython/cantera/test/test_plasma.py @@ -17,10 +17,12 @@ def test_electron_properties(self): self.assertNear(self.gas.electron_temperature, 13113, 1e-3) self.assertNear(self.gas.electron_mobility, 0.3985, 1e-3) self.assertNear(self.gas.electron_diffusivity, 0.5279, 1e-3) - self.assertNear(self.gas.plasma_process_rate_coefficient(5), 1.55e-16, 1e-3) + self.assertNear(self.gas.plasma_process_rate_coefficient(5), 1.55e-16, rtol=1e-5, atol=1e-17) + self.assertNear(self.gas.plasma_process_reverse_rate_coefficient(5), 4.16e-16, rtol=1e-5, atol=1e-17) self.assertNear(self.gas.electron_total_collision_frequency, 3.433e11, 1e-3) self.assertNear(self.gas.electron_power_gain, 3.9811e9, 1e-3) self.assertNear(self.gas.electron_elastic_power_loss, 2.4114e7, 1e-3) + self.assertNear(self.gas.electron_total_power_loss, 3.88e9, 1e-3) self.assertNear(self.gas.mean_electron_energy, 1.6949, 1e-3) self.assertNear(self.gas.electric_field, 1e5, 1e-3) From 4e4a91363b44e3296e7608de7f2d7f634d860af3 Mon Sep 17 00:00:00 2001 From: bangshiuh Date: Sun, 17 May 2020 00:08:12 -0400 Subject: [PATCH 139/139] [kinetics] add validate to PlasmaReaction --- include/cantera/kinetics/Reaction.h | 1 + src/kinetics/Reaction.cpp | 46 +++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/include/cantera/kinetics/Reaction.h b/include/cantera/kinetics/Reaction.h index e158c00195c..fa02863a9a0 100644 --- a/include/cantera/kinetics/Reaction.h +++ b/include/cantera/kinetics/Reaction.h @@ -111,6 +111,7 @@ class PlasmaReaction : public Reaction PlasmaReaction(); PlasmaReaction(const Composition& reactants, const Composition& products, const std::map& process); + virtual void validate(); std::map process; }; diff --git a/src/kinetics/Reaction.cpp b/src/kinetics/Reaction.cpp index 9a01ba3f82b..5a26aad8be7 100644 --- a/src/kinetics/Reaction.cpp +++ b/src/kinetics/Reaction.cpp @@ -154,6 +154,52 @@ PlasmaReaction::PlasmaReaction() { } +void PlasmaReaction::validate() +{ + Reaction::validate(); + bool reactants_ok = false; + bool found_electron = false; + if (reactants.size() == 2) { + double sum = 0.0; + for (auto species : reactants) { + if (species.first == "E") { + found_electron = true; + } + sum += species.second; + } + if (sum == 2.0 && found_electron) { + reactants_ok = true; + } + } + if (reactants_ok == false) { + throw CanteraError("PlasmaReaction::validate", + "The type of the reaction {} is not suitable to be plasma." + "The reactants have to be one electron plus one molecule", equation()); + } + + bool products_ok = false; + found_electron = false; + if (reversible) { + if (products.size() == 2) { + double sum = 0.0; + for (auto species : products) { + if (species.first == "E") { + found_electron = true; + } + sum += species.second; + } + if (sum == 2.0 && found_electron) { + products_ok = true; + } + } + if (products_ok == false) { + throw CanteraError("PlasmaReaction::validate", + "The reaction {} is not suitable to be reversible." + "The products have to be one electron plus one molecule", equation()); + } + } +} + ThirdBody::ThirdBody(double default_eff) : default_efficiency(default_eff) {