diff --git a/data/critical-properties.yaml b/data/critical-properties.yaml index 525dfd6af6..024628710b 100644 --- a/data/critical-properties.yaml +++ b/data/critical-properties.yaml @@ -6295,3 +6295,14 @@ species: source: |- The acentric factor is calculated using the pure fluid saturation data from Lemmon et al. (2022). +- name: H2 + descriptive-name: hydrogen + molecular-weight: 2.016 + critical-parameters: + critical-temperature: 32.98 + critical-pressure: 1.293e6 + critical-molar-volume: 0.0642 + critical-compressibility: 0.303 + acentric-factor: -0.217 + source: |- + Properties of Gases and Liquids, 5th edition, Poling. diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile index e2f006a640..dfe7f111d6 100644 --- a/doc/doxygen/Doxyfile +++ b/doc/doxygen/Doxyfile @@ -1725,7 +1725,7 @@ FORMULA_FONTSIZE = 10 # to create new LaTeX commands to be used in formulas as building blocks. See # the section "Including formulas" for details. -FORMULA_MACROFILE = +FORMULA_MACROFILE = doc/doxygen/macros.tex # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # https://www.mathjax.org) which uses client side JavaScript for the rendering diff --git a/doc/doxygen/cantera.bib b/doc/doxygen/cantera.bib index bbc55aa99a..7c077a098d 100644 --- a/doc/doxygen/cantera.bib +++ b/doc/doxygen/cantera.bib @@ -60,6 +60,26 @@ @article{dixon-lewis1968 year = {1968}, doi = {10.1098/rspa.1968.0178}, URL = {https://royalsocietypublishing.org/doi/abs/10.1098/rspa.1968.0178}} +@article{ely-hanley1981, + author = {Ely, James F. and Hanley, H. J. M.}, + title = {Prediction of transport properties. 1. Viscosity of fluids and mixtures}, + journal = {Industrial \& Engineering Chemistry Fundamentals}, + volume = {20}, + number = {4}, + pages = {323-332}, + year = {1981}, + doi = {10.1021/i100004a004}, + URL = {https://doi.org/10.1021/i100004a004}} +@article{ely-hanley1983, + author = {Ely, James F. and Hanley, H. J. M.}, + title = {Prediction of transport properties. 2. Thermal conductivity of pure fluids and mixtures}, + journal = {Industrial \& Engineering Chemistry Fundamentals}, + volume = {22}, + number = {1}, + pages = {90-97}, + year = {1983}, + doi = {10.1021/i100009a016}, + URL = {https://doi.org/10.1021/i100009a016}} @article{gilbert1983, author = {R.~G.~Gilbert and K.~Luther and J.~Troe}, journal = {Berichte der Bunsengesellschaft für physikalische Chemie}, diff --git a/doc/doxygen/macros.tex b/doc/doxygen/macros.tex new file mode 100644 index 0000000000..cb5d02e57a --- /dev/null +++ b/doc/doxygen/macros.tex @@ -0,0 +1,3 @@ +% Macros defined here should also be defined in Sphinx conf.py +\newcommand{\t}[1]{\mathrm{#1}} +\newcommand{\pxpy}[2]{\frac{\partial #1}{\partial #2}} diff --git a/doc/example-keywords.txt b/doc/example-keywords.txt index d8da59667d..df6d4db8c2 100644 --- a/doc/example-keywords.txt +++ b/doc/example-keywords.txt @@ -40,9 +40,9 @@ reaction path analysis reactor network saving output sensitivity analysis +shock tube strained flame surface chemistry -shock tube thermodynamic cycle thermodynamics transport diff --git a/doc/sphinx/conf.py b/doc/sphinx/conf.py index 473b8e622d..52d242bc08 100644 --- a/doc/sphinx/conf.py +++ b/doc/sphinx/conf.py @@ -220,6 +220,7 @@ def escape_splats(app, what, name, obj, options, lines): "attrs_block", ] +# For Doxygen pages, these macros are also defined in doc/doxygen/macros.tex mathjax3_config = { 'tex': { 'macros': { diff --git a/doc/sphinx/reference/transport/index.md b/doc/sphinx/reference/transport/index.md index 046750c768..5afd1bd526 100644 --- a/doc/sphinx/reference/transport/index.md +++ b/doc/sphinx/reference/transport/index.md @@ -45,11 +45,20 @@ Mixture-averaged to `mixture-averaged`. Implemented by class {ct}`MixTransport`. High-pressure Gas -: A model for high-pressure gas transport properties based on a method of corresponding - states {cite:p}`takahashi1975,poling2001`. The high-pressure gas transport model can - be specified in the YAML format by setting the [`transport`](sec-yaml-phase-transport) - field of the phase entry to `high-pressure`. Implemented by - class {ct}`HighPressureGasTransport`. +: A model for high-pressure gas transport properties that uses the Lucas method of + corresponding states {cite:p}`poling2001` for viscosity and thermal + conductivity and the Takahashi method {cite:p}`takahashi1975,poling2001` for the + diffusion coefficient. This high-pressure gas transport model can be specified in + the YAML format by setting the [`transport`](sec-yaml-phase-transport) field of the + phase entry to `high-pressure`. Implemented by class {ct}`HighPressureGasTransport`. + +Chung high-pressure Gas +: A model for high-pressure gas transport properties that uses the method of Chung + {cite:p}`poling2001` for viscosity and thermal conductivity and the Takahashi method + {cite:p}`takahashi1975,poling2001` for the diffusion coefficient. This high-pressure + gas transport model can be specified in the YAML format by setting the + [`transport`](sec-yaml-phase-transport) field of the phase entry to + `high-pressure-Chung`. Implemented by class {ct}`ChungHighPressureGasTransport`. Ionized Gas : A model implementing the Stockmayer-(n,6,4) model for transport of ions in a gas. The diff --git a/doc/sphinx/yaml/phases.md b/doc/sphinx/yaml/phases.md index 857f970858..d61abb129b 100644 --- a/doc/sphinx/yaml/phases.md +++ b/doc/sphinx/yaml/phases.md @@ -142,6 +142,8 @@ are: - `none` - `high-pressure`: A model for high-pressure gas transport properties based on a method of corresponding states ({ct}`details `) + - `high-pressure-Chung`: A model for high-pressure gas transport properties based on + the method of Chung ({ct}`details `) - `ionized-gas`: A model implementing the Stockmayer-(n,6,4) model for transport of ions in a gas ({ct}`details `) - `mixture-averaged`: The mixture-averaged transport model for ideal gases diff --git a/include/cantera/transport/GasTransport.h b/include/cantera/transport/GasTransport.h index f845836de6..ac8374dd69 100644 --- a/include/cantera/transport/GasTransport.h +++ b/include/cantera/transport/GasTransport.h @@ -54,12 +54,20 @@ class GasTransport : public Transport std::copy(m_visc.begin(), m_visc.end(), visc); } - //! Returns the matrix of binary diffusion coefficients. - /*! - * d[ld*j + i] = rp * m_bdiff(i,j); + /** + * Computes the matrix of binary diffusion coefficients. Units are m^2/s. + * + * The matrix is dimension m_nsp x m_nsp, where m_nsp is the number of + * species. The matrix is stored in row-major order, so that d[ld*j + i] + * contains the binary diffusion coefficient of species i with respect to + * species j. + * + * d[ld*j + i] = m_bdiff(i,j) / p * - * @param ld offset of rows in the storage - * @param d output vector of diffusion coefficients. Units of m**2 / s + * @param ld Inner stride for writing the two dimension diffusion + * coefficients into a one dimensional vector + * @param d Diffusion coefficient matrix (must be at least m_nsp * m_nsp + * in length. */ void getBinaryDiffCoeffs(const size_t ld, double* const d) override; @@ -205,7 +213,7 @@ class GasTransport : public Transport * name of a file containing transport property parameters and a list of * species names. */ - void getTransportData(); + virtual void getTransportData(); //! Corrections for polar-nonpolar binary diffusion coefficients /*! diff --git a/include/cantera/transport/HighPressureGasTransport.h b/include/cantera/transport/HighPressureGasTransport.h index c5e6e7c08c..b5e6198379 100644 --- a/include/cantera/transport/HighPressureGasTransport.h +++ b/include/cantera/transport/HighPressureGasTransport.h @@ -11,81 +11,1387 @@ // Cantera includes #include "GasTransport.h" -#include "cantera/numerics/DenseMatrix.h" -#include "cantera/transport/MultiTransport.h" +#include "cantera/transport/MixTransport.h" namespace Cantera { -//! Class MultiTransport implements transport properties for -//! high pressure gas mixtures. -/*! - * @attention This class currently does not have any test cases or examples. Its - * implementation may be incomplete, and future changes to %Cantera may - * unexpectedly cause this class to stop working. If you use this class, - * please consider contributing examples or test cases. In the absence of - * new tests or examples, this class may be deprecated and removed in a - * future version of %Cantera. See - * https://github.com/Cantera/cantera/issues/267 for additional information. +/** + * The implementation employs a method of corresponding states, using the Takahashi + * @cite takahashi1975 approach for binary diffusion coefficients (using mixture + * averaging rules for the mixture properties), the Lucas method for the viscosity, and + * a method from Ely and Hanley for the thermal conductivity. All methods are described + * in Poling et al. @cite poling2001 (viscosity in Ch. 9, thermal conductivity in + * Ch. 10, and diffusion coefficients in Ch. 11). + * + * @ingroup tranprops + */ +class HighPressureGasTransport : public MixTransport +{ +protected: + //! default constructor + HighPressureGasTransport()=default; + +public: + string transportModel() const override { + return "high-pressure"; + } + + void init(ThermoPhase* thermo, int mode=0, int log_level=0) override; + + /** + * Returns the mixture high-pressure thermal conductivity in W/m/K + * using a method of corresponding states by Ely and Hanley. + * + * This method for computing the thermal conductivity is described in + * @cite ely-hanley1983 . There are references to earlier work in + * @cite ely-hanley1981 in the description of the model for thermal conductivity. + * The equations referenced in this description primarily are from + * @cite ely-hanley1983 , and equations that come from @cite ely-hanley1981 are + * marked as such. The equations referenced here are the same as the ones from + * the papers from Ely and Hanley. + * + * The thermal conductivity is assumed to have two components: a + * translational/collisional part and an internal part that is related to the + * transfer of energy to internal degrees of freedom. + * + * @f[ + * \lambda_{mix}(\rho, T) = \lambda^{''}_{mix}(T) + \lambda^{'}_{mix}(\rho, T) + * @f] + * + * The first term on the right-hand side is the internal part and the second term + * is the translational part. The internal part is only a function of temperature, + * and the translational part is a function of both temperature and density. + * + * The internal component of the thermal conductivity is defined by Equation 2 + * in @cite ely-hanley1983 : + * + * @f[ + * \lambda^{''}_{mix}(T) = \sum_i \sum_j X_i X_j \lambda^{''}_{ij}(T) + * @f] + * + * The mixing rule for combining pure-species internal thermal conductivity + * components is given by Equation 3 in @cite ely-hanley1983 : + * + * @f[ + * (\lambda^{''}_{ij})^{-1} = 2[(\lambda^{''}_{i})^{-1} + * + (\lambda^{''}_{j})^{-1}] + * @f] + * + * The pure species internal thermal conductivity is given by Equation 1 in + * @cite ely-hanley1983 : + * + * @f[ + * \lambda^{''}_{i} = \frac{\eta_i^*}{MW_i}f_{int} \left(C_{p,i}^0 - 2.5R \right) + * @f] + * + * Where @f$ \eta_i^* @f$ is the referred to as the dilute gas viscosity and is the + * component that is temperature dependent described in @cite ely-hanley1981 + * (see elyHanleyDilutePureSpeciesViscosity() ), + * @f$ MW_i @f$ is the molecular weight of species i, @f$ f_{int} @f$ is a constant + * and is 1.32, @f$ C_{p,i}^0 @f$ is the ideal gas heat capacity of species i, + * and R is the gas constant (J/kmol/K). + * + * For the translational component of the thermal conductivity, Equation 5 in + * @cite ely-hanley1983 is used: + * + * @f[ + * \lambda^{'}_{mix}(\rho, T) = \lambda^{'}_{0}(\rho_0, T_0) F_{\lambda} + * @f] + * + * Where @f$ \lambda^{'}_{0}(\rho_0, T_0) @f$ is the internal component of the + * thermal conductivity of a reference fluid that is at a reference temperature + * and density, @f$ T_0 @f$ and @f$ \rho_0 @f$. These reference conditions are not + * the same as the conditions that the mixture is at (@f$ T @f$ and @f$ \rho @f$). + * The subscript 0 refers to the reference fluid. The term @f$ F_{\lambda} @f$ is + * defined by Equation 6 in @cite ely-hanley1983 : + * + * @f[ + * F_{\lambda} = \left( \frac{MW_0}{MW_m} \right)^{1/2} f_{m,0}^{1/2} + * h_{m,0}^{-2/3} + * @f] + * + * Where @f$ MW_0 @f$ is the molecular weight of the reference fluid, @f$ MW_m @f$ + * is the molecular weight of the mixture. + * + * @note: @f$ MW_m @f$ is an effective mixture molecular weight and should not be + * confused with a mole-weighted average of the molecular weights of the + * species in the mixture. + * + * The terms @f$ f_{m,0} @f$ and @f$ h_{m,0} @f$ are called reducing ratios. The + * @f$ h_{m,0} @f$ quantity is defined by Equation 9 in @cite ely-hanley1983 : + * + * @f[ + * h_{m,0} = \sum_i \sum_j X_i X_j h_{ij} + * @f] + * + * with @f$ h_{ij} @f$ defined by Equation 11 in @cite ely-hanley1983 : + * + * @f[ + * h_{ij} = \frac{1}{8} \left( h_i^{1/3} + h_j^{1/3} \right)^3 (1 - l_{ij}) + * @f] + * + * The variable @f$ l_{ij} @f$ is a binary interaction parameter and is assumed to + * be zero as is done by Ely and Hanley. The pure species reducing ratio @f$ h_i @f$ + * is defined by Equation 13 in @cite ely-hanley1983 : + * + * @f[ + * h_i = \frac{V_c^i}{V_c^0} \phi_i(T_R^i, V_R^i, \omega_i) + * @f] + * + * Where @f$ \phi_i @f$ is a shape factor of Leach and Leland (see phiShapeFactor()), + * @f$ T_R^i @f$ is the reduced temperature of species i, @f$ V_R^i @f$ is the + * reduced volume of species i, and @f$ \omega_i @f$ is the acentric factor of + * species i. + * + * At this point, the value of @f$ h_{m,0} @f$ can be computed. This + * leaves the other reducing ratio, @f$ f_{m,0} @f$, to be computed. The value of + * that reducing ratio is defined by Equation 8 in @cite ely-hanley1983 : + * + * @f[ + * f_{m,0} = \frac{1}{h_{m,0}} \sum_i \sum_j X_i X_j f_{ij} h_{ij} + * @f] + * + * + * The value of @f$ h_{ij} @f$ is the same as the one defined earlier. The + * combining rule for @f$ f_{ij} @f$ is given by Equation 10 in + * @cite ely-hanley1983 : + * + * @f[ + * f_{ij} = (f_i f_j)^{1/2} (1-\kappa_{ij}) + * @f] + * + * @f$ \kappa_{ij} @f$ is binary interaction parameters and is assumed to be zero + * as was done in the work of Ely and Hanley. The species-specific value of + * @f$ f_i @f$ is defined by Equation 12 in @cite ely-hanley1983 : + * + * @f[ + * f_i = \frac{T_c^i}{T_c^0} \theta_i(T_R^i, V_R^i, \omega_i) + * @f] + * + * Where @f$ \theta_i @f$ is a shape factor of Leach and Leland + * (see thetaShapeFactor()), @f$ T_c^i @f$ is the critical temperature of species + * i, and @f$ T_c^0 @f$ is the critical temperature of the reference fluid. + * + * The value of @f$ h_{m,0} @f$ can be computed from + * the equation that defined the value of @f$ f_{m,0} h_{m,0} @f$. The value of + * @f$ h_{m,0} @f$ must be computed first and then the value of @f$ f_{m,0} @f$ + * can be computed. + * + * The expression for @f$ MW_m @f$ is somewhat complex, but keep in mind that all + * terms except @f$ MW_m @f$ are known at this point and so simple algebra can be + * used to isolate the molecular weight of the mixture. The expression for the + * mixture molecular weight is given by Equation 14 in @cite ely-hanley1983 : + * + * @f[ + * MW_m^{1/2} f_{m,0}^{1/2} h_{m,0}^{-4/3} = \sum_i \sum_j X_i X_j MW_{ij}^{-1/2} + * f_{ij}^{1/2} h_{ij}^{-4/3} + * @f] + * + * where the mixing rule for the molecular weight of the mixture is given by + * Equation 15 in @cite ely-hanley1983 : + * + * @f[ + * MW_{ij} = \frac{1}{2} (MW_i^{-1} + MW_j^{-1}) + * @f] + * + * For clarity, if we assume the right-hand-side of the molecular weight mixture + * equation is A, then the mixture molecular weight is given by: + * + * @f[ + * MW_m = A^{-2} f_{m,0} h_{m,0}^{-8/3} + * @f] + * + * All of the above descriptions allow for the calculation of @f$ F_{\lambda} @f$ + * in the expression for the mixture value of the translational component of the + * thermal conductivity. The reference fluid value of the translational component + * of the thermal conductivity ( @f$ \lambda^{'}_{0}(\rho_0, T_0) @f$ ) is still + * needed, which requires the the temperature and density of the reference fluid. + * + * The reference fluid density is computed using Equation 7 in + * @cite ely-hanley1983 : + * + * @f[ + * \rho_0 = \rho h_{m,0} + * @f] + * + * The reference fluid temperature is computed using Equation 7 in + * @cite ely-hanley1983 : + * + * @f[ + * T_0 = \frac{T}{f_{m,0}} + * @f] + * + * The reference fluid translational component of thermal conductivity can now be + * computed using Equation 18 in @cite ely-hanley1983. + * See elyHanleyReferenceThermalConductivity(). + * + * @note The correlations for the reference fluid viscosity return a value of + * micro-grams/cm/s and the parts of the thermal conductivity that utilize + * the correlation fit parameters give values in units of mW/m/K. Appropriate + * conversions were made in the relevant functions: + * elyHanleyDiluteReferenceViscosity() and + * elyHanleyReferenceThermalConductivity() + */ + double thermalConductivity() override; + + /** + * Returns the mixture high-pressure viscosity in Pa*s using the Lucas method. + * + * This uses the approach described in chapter 9-7. In this method, the mixture + * viscosity at high pressure is computed using the pure-fluid high pressure + * relation of Lucas with the difference being that mixture values of the + * model parameters are used. These mixture values are computed using the mixing + * rules described in see computeMixtureParameters() . + * + * The mixture pseudo-critical temperature and pressure are calculated using + * Equations 9-5.18 and 9-5.19. The mixture molecular weight is computed using + * Equation 9-5.20. The mixture values of the low-pressure polarity and quantum + * correction factors are computed using Equations 9-5.21 and 9-5.22. + */ + double viscosity() override; + + /** + * Computes the matrix of binary diffusion coefficients using the Takahashi + * correction factor. Units are m^2/s. + * + * The matrix is dimension m_nsp x m_nsp, where m_nsp is the number of + * species. The matrix is stored in row-major order, so that d[ld*j + i] + * contains the binary diffusion coefficient of species i with respect to + * species j. + * + * d[ld*j + i] = (DP)_R * m_bdiff(i,j) / p + * + * @param ld Inner stride for writing the two dimension diffusion + * coefficients into a one dimensional vector + * @param d Diffusion coefficient matrix (must be at least m_nsp * m_nsp + * in length. + */ + void getBinaryDiffCoeffs(const size_t ld, double* const d) override; + + /** + * Returns the Mixture-averaged diffusion coefficients [m^2/s]. + * + * This method is the same as GasTransport::getMixDiffCoeffs() with the exception + * that the binary diffusion coefficients are multiplied by the Takahashi correction + * factor, which is described in takahashiCorrectionFactor() . + * + * @param[out] d Vector of mixture diffusion coefficients, @f$ D_{km}' @f$ , + * for each species (m^2/s). length m_nsp + */ + void getMixDiffCoeffs(double* const d) override; + + /** + * Returns the mixture-averaged diffusion coefficients [m^2/s]. + * + * This method is the same as GasTransport::getMixDiffCoeffsMole() with the exception + * that the binary diffusion coefficients are multiplied by the Takahashi correction + * factor, which is described in takahashiCorrectionFactor() . + * + * @param[out] d vector of mixture-averaged diffusion coefficients for + * each species, length m_nsp. + */ + void getMixDiffCoeffsMole(double* const d) override; + + /** + * Returns the mixture-averaged diffusion coefficients [m^2/s]. + * + * This method is the same as GasTransport::getMixDiffCoeffsMass() with the exception + * that the binary diffusion coefficients are multiplied by the Takahashi correction + * factor, which is described in takahashiCorrectionFactor() . + * + * @param[out] d vector of mixture-averaged diffusion coefficients for + * each species, length m_nsp. + */ + void getMixDiffCoeffsMass(double* const d) override; + + /** + * Updates the matrix of species-pair Takahashi correction factors for use in + * computing the binary diffusion coefficients, see takahashiCorrectionFactor() + */ + void updateCorrectionFactors(); + + friend class TransportFactory; + +protected: + + /** + * Obtain required parameters from the 'critical-parameters' species input section, + * and checks the critical-properties.yaml file if an acentric factor is not + * specified. + * + * The way that GasTransport parses the input file is that if an acentric + * factor is not specified, it is quietly set to 0.0. A user may have the proper + * acentric factor in the critical-properties.yaml file, so that file is checked if + * a zero value is present. + */ + void getTransportData() override; + + /** + * Computes and stores the estimate of the critical properties for each species. + * + * This method sets the species composition vector to unity for species i and zero + * for all other species, and then queries the thermo object for the critical + * properties and stores them. It then resets the composition vector to the original + * state. This method only needs to be called once, as the critical properties for + * the pure species do not change. + * + * All species must have critical properties defined in the input file, either via + * critical properties or by specific values of the equation of state that are + * not zero. + */ + void initializeCriticalProperties(); + + //! Returns the stored value of the critical temperature for species 'i'. + double Tcrit_i(size_t i); + + //! Returns the stored value of the critical pressure for species 'i'. + double Pcrit_i(size_t i); + + //! Returns the stored value of the critical volume for species 'i'. + double Vcrit_i(size_t i); + + //! Returns the stored value of the critical compressibility for species 'i'. + double Zcrit_i(size_t i); + + /** + * Returns the viscosity of a pure species using the method of Ely and Hanley. + * Units are Pa*s + * + * Uses the method outlined in @cite ely-hanley1981 to compute the viscosity of a + * pure species. + * + * The primary equation is given by Equation 1 in @cite ely-hanley1981 : + * + * @f[ + * \eta_i(\rho,T) = \eta_0(\rho_0, T_0) F_{\eta} + * @f] + * + * Where @f$ F_{\eta} @f$ is defined by Equation 2 in @cite ely-hanley1981 : + * + * @f[ + * F_{\eta} = \left( \frac{MW_i}{MW_0} \right)^{1/2} f_{i,0}^{1/2} h_{i,0}^{-2/3} + * @f] + * + * The `0` subscripts refer to the reference fluid, which is methane in this case, + * and the `i` subscripts refer to the species of interest. No mixing rules + * need to be used here because this is for a pure species. As such, the terms + * @f$ f_{i,0} @f$ and @f$ h_{i,0} @f$ have simpler expressions. The value of + * @f$ f_{i,0} @f$ is given by Equation 7 in @cite ely-hanley1981 : + * + * @f[ + * f_{i,0} = \frac{T_c^i}{T_c^0} \theta_i(T_R^i, V_R^i, \omega_i) + * @f] + * + * and the value of @f$ h_{i,0} @f$ is given by Equation 8 in @cite ely-hanley1981 : + * + * @f[ + * h_{i,0} = \frac{V_c^i}{V_c^0} \phi_i(T_R^i, V_R^i, Z_{c,i}, \omega_i) + * @f] + * + * Where @f$ \theta_i @f$ and @f$ \phi_i @f$ are shape factors of Leach and Leland + * ( see thetaShapeFactor() and phiShapeFactor() ), @f$ T_c^i @f$ is the critical + * temperature of species i, @f$ T_c^0 @f$ is the critical temperature of the + * reference fluid, @f$ V_c^i @f$ is the critical volume of species i, + * @f$ V_c^0 @f$ is the critical volume of the reference fluid, @f$ Z_{c,i} @f$ + * is the critical compressibility of species i, and @f$ \omega_i @f$ + * is the acentric factor of species i. + * + * @param V Molar volume of the species + * @param Tc Critical temperature of the species + * @param Vc Critical volume of the species + * @param Zc Critical compressibility of the species + * @param acentric_factor Acentric factor of the species + * @param mw Molecular weight of the species + */ + double elyHanleyDilutePureSpeciesViscosity(double V, double Tc, double Vc, + double Zc, double acentric_factor, + double mw); + + + /** + * Returns the theta shape factor of Leach and Leland for a pure species. + * + * The shape factor @f$ \theta_i @f$ is defined by Equation 11 in @cite ely-hanley1981 + * as follows: + * + * @f[ + * \theta_i(T_R^i, V_R^i, \omega_i) = 1 + (\omega_i - \omega_0)F(T_R^i, V_R^i)] + * @f] + * + * Where @f$ \omega_i @f$ is the acentric factor of species i, @f$ \omega_0 @f$ is + * the acentric factor of the reference fluid, and @f$ F(T_R^i, V_R^i) @f$ is a + * function of the reduced temperature and reduced volume of species i. The + * function @f$ F(T_R^i, V_R^i) @f$ is defined by Equation 13 in + * @cite ely-hanley1981 : + * + * @f[ + * F(T_R^i, V_R^i) = a_1 + b_1 ln(T_+^i) + (c_1 + d_1/T_+^i) (V_+^i - 0.5) + * @f] + * + * Where @f$ T_+^i @f$ and @f$ V_+^i @f$ are limited values of the reduced + * temperature and pressure. The limited temperature is defined by Equation 15 in + * @cite ely-hanley1981 : + * + * @f[ + * T_+^i = \text{min}(2, \text{max}(T_R^i, 0.5)) + * @f] + * + * and the limited pressure is defined by Equation 16 in @cite ely-hanley1981 : + * + * @f[ + * V_i^+ = \text{min}(2, \text{max}(V_R^i, 0.5)) + * @f] + * + * The values of @f$ a_1 @f$, @f$ b_1 @f$, @f$ c_1 @f$, and @f$ d_1 @f$ are + * given in Table II of @cite ely-hanley1981. They are: + * + * @f[ + * a_1 = 0.090569, b_1 = -0.862762, c_1 = 0.316636, d_1 = -0.465684 + * @f] + * + * @param Tr Reduced temperature + * @param Vr Reduced volume + * @param acentric_factor Acentric factor + */ + double thetaShapeFactor(double Tr, double Vr, double acentric_factor); + + + /** + * Returns the phi shape factor of Leach and Leland for a pure species. + * + * The shape factor @f$ \phi_i @f$ is defined by Equation 12 in + * @cite ely-hanley1981 as follows: + * + * @f[ + * \phi_i(T_R^i, V_R^i, \omega_i, Z_c^i) = \frac{Z_c^0}{Z_c^i} [1 + (\omega_i - + * \omega_0)G(T_R^i, V_R^i)] + * @f] + * + * Where @f$ Z_c^0 @f$ is the critical compressibility of the reference fluid, + * @f$ Z_c^i @f$ is the critical compressibility of species i, @f$ \omega_0 @f$ + * is the acentric factor of the reference fluid, and @f$ G(T_R^i, V_R^i) @f$ is a + * function of the reduced temperature and reduced volume of species i. The + * function @f$ G(T_R^i, V_R^i) @f$ is defined by Equation 14 in + * @cite ely-hanley1981 : + * + * @f[ + * G(T_R^i, V_R^i) = a_2(V_+^i + b_2) + c_2(V_+^i + d_2)ln(T_+^i) + * @f] + * + * Where @f$ T_+^i @f$ and @f$ V_+^i @f$ are limited values of the reduced + * temperature and pressure. The limited temperature is defined by Equation 15 in + * @cite ely-hanley1981 : + * + * @f[ + * T_+^i = \text{min}(2, \text{max}(T_R^i, 0.5)) + * @f] + * + * and the limited pressure is defined by Equation 16 in @cite ely-hanley1981 : + * + * @f[ + * V_i^+ = \text{min}(2, \text{max}(V_R^i, 0.5)) + * @f] + * + * The values of @f$ a_2 @f$, @f$ b_2 @f$, @f$ c_2 @f$, and @f$ d_2 @f$ are + * given in Table II of @cite ely-hanley1981. They are: + * + * @f[ + * a_2 = 0.394901, b_2 = -1.023545, c_2 = -0.932813, d_2 = -0.754639 + * @f] + * + * @param Tr Reduced temperature + * @param Vr Reduced volume + * @param Zc Critical compressibility + * @param acentric_factor Acentric factor + */ + double phiShapeFactor(double Tr, double Vr, double Zc, double acentric_factor); + + /** + * Returns the viscosity of for the reference fluid of methane for low pressures. + * Units are Pa*s + * + * Computes the temperature dependent (referred to as the dilute viscosity in the + * reference) component only (eta_0) from the expression in Table III in + * @cite ely-hanley1981 . Prevents inputs larger than 10,000 Kelvin by just + * returning the value at 10,000 Kelvin. + * + * @param T0 Temperature of the reference fluid + */ + double elyHanleyDiluteReferenceViscosity(double T0); + + /** + * Returns the thermal conductivity of for the reference fluid of methane + * in units of W/m/K. + * + * Computes the temperature and density dependent reference fluid thermal + * conductivity from the expression in Table I in @cite ely-hanley1983 . + * + * The reference fluid translational component of thermal conductivity is computed + * using Equation 18 in @cite ely-hanley1983 : + * + * @f[ + * \lambda^{'}_{0}(\rho_0, T_0) = \frac{15R}{4MW_0} \eta_0^* + + * \lambda_0^{(1)}\rho_0 + + * \Delta\lambda_0(\rho_0, T_0) + * @f] + * + * Where @f$ \eta_0^* @f$ is the dilute reference gas viscosity, + * @f$ \lambda_0^{(1)} @f$ is the first density correction to the thermal + * conductivity, and @f$ \Delta\lambda_0 @f$ is the high-density contribution. + * Ely and Hanley provide a correlation equation to solve for this quantity for + * the methane reference fluid. The details of the correlation and the parameters + * are shown in Table I of @cite ely-hanley1983. + * + * For completeness, the relations are reproduced here. + * + * @f[ + * \lambda_0^*(T_0) = \frac{15R}{4MW_0} \eta_0^* + * @f] + * + * @f[ + * \eta_0^* = \sum_{n=1}^{9} C_n T_0^{(n-4)/3} + * @f] + * + * @f[ + * \lambda_0^{(1)} = b_1 + b_2[b_3 - ln(T_0 / b_4)]^2 + * @f] + * + * @f[ + * \Delta\lambda_0 = \text{exp}[a_1 + a_2/T_0] + * (exp[(a_3 + a_4/T_0^{3/4})\rho_0^{0.1} + * + (\rho_0 / \rho_0,c - 1)\rho_0^{0.5} + * (a_5 + a_6/T_0 + a_7/T_0^2) ] - 1) + * @f] + * + * The constants a, b, and C are not related to any ones used in the previous + * equations, their values are defined in Table I of @cite ely-hanley1983. + * + * @param rho0 Density of the reference fluid + * @param T0 Temperature of the reference fluid + */ + double elyHanleyReferenceThermalConductivity(double rho0, double T0); + + /** + * Computes the composition-dependent values of parameters that are needed for the + * Lucas viscosity model. + * + * The equations for the mixing rules defined on page 9.23 of @cite poling2001 for + * the Lucas method's composition dependent parameters. The primary mixing rules + * are defined below, and the reduced properties are just the properties divided + * by the pseudo-critical mixture properties defined below. + * + * @note Equation numbers are from @cite poling2001 + * + * @f[ + * T_{\text{c,m}} = \sum_i X_i T_{\text{c,i}} + * + * \quad \text{( Equation 9-5.18)} + * @f] + * + * Where @f$ T_{\text{c,i}} @f$ is the critical temperature of species i, + * and @f$ X_i @f$ is the mole fraction of species i. + * + * @f[ + * P_{\text{c,m}} = R T_{\text{c,m}} + * \frac{\sum_i X_i Z_{\text{c,i}}}{\sum_i X_i V_{\text{c,i}}} + * + * \quad \text{(Equation 9-5.19)} + * @f] + * + * Where @f$ Z_{\text{c,i}} @f$ is the critical compressibility of species i, and + * @f$ V_{\text{c,i}} @f$ is the critical volume of species i. + * + * @f[ + * M_m = \sum X_i M_i + * + * \quad \text{(Equation 9-5.20)} + * @f] + * + * Where @f$ M_i @f$ is the molecular weight of species i. + * + * @f[ + * F_{P,m}^{\text{o}} = \sum X_i F_{P,i}^{\text{o}} + * + * \quad \text{(Equation 9-5.21)} + * @f] + * + * Where @f$ F_{P,i}^{\text{o}} @f$ is the low-pressure polarity correction + * factor of species i from equation 9-4.18. + * + * @f[ + * F_{Q,m}^{\text{o}} = \left ( \sum X_i F_{Q,i}^{\text{o}} \right ) A + * + * \quad \text{(Equation 9-5.22)} + * @f] + * + * Where @f$ F_{Q,i}^{\text{o}} @f$ is the low-pressure quantum correction factor + * of species i from equation 9-4.19, and A is defined below. + * + * @f[ + * A = 1 - 0.01 \left ( \frac{M_H}{M_L} \right )^{0.87} + * + * \quad \text{(Equation 9-5.23)} + * @f] + * + * For @f$ \frac{M_H}{M_L} > 9 @f$ and @f$ 0.05 < X_H < 0.7 @f$, otherwise A = 1. + * In the above equation, $M_H$ and $M_L$ are the molecular weights of the + * heaviest and lightest components in the mixture, and @f$ X_H @f$ is the mole + * fraction of the heaviest component. + * + * While it isn't returned as a parameter, the species-specific reduced dipole + * moment (@f$ \mu_r @f$) is used to compute the mixture polarity correction factor. + * It is defined as: + * + * @f[ + * \mu_r = 52.46 \frac{\mu^2 P_{\text{c,i}}}{T_{\text{c,i}}} + * + * \quad \text{(Equation 9-4.17)} + * @f] + */ + void computeMixtureParameters(); + + /** + * Returns the non-dimensional low-pressure mixture viscosity in using the Lucas + * method. + * + * @f[ + * \eta \xi = F_P^{\text{o}} F_Q^{\text{o}} [0.807 T_r^{0.618} + * - 0.357 e^{-0.449 T_r} + * + 0.340e^{-4.058 T_r} + 0.018] + * + * \quad \text{(Equation 9-4.16)} + * @f] + * + * This function is structured such that it can be used for pure species or + * mixtures, with the only difference being the values that are passed to the + * function (pure values versus mixture values). + * + * For the definition of the mixture rules, see computeMixtureParameters() . + * + * @param Tr Reduced temperature [unitless] + * @param FP Polarity correction factor [unitless] + * @param FQ Quantum correction factor [unitless] + */ + double lowPressureNondimensionalViscosity(double Tr, double FP, double FQ); + + /** + * Returns the non-dimensional high-pressure mixture viscosity in using the Lucas + * method. + * + * @f[ + * \eta \xi = Z_2 F_P F_Q + * + * \quad \text{(Equation 9-6.12)} + * @f] + * + * This returns the value of η*ξ (by multiplying both sides of 9-6.12 by ξ and + * returning the right-side of the resulting equation). + * + * This function is structured such that it can be used for pure species or + * mixtures, with the only difference being the values that are passed to the + * function (pure values versus mixture values). + * + * For the definition of the mixture rules, see computeMixtureParameters() . + * + * @param Tr Reduced temperature [unitless] + * @param Pr Reduced pressure [unitless] + * @param FP_low Low-pressure polarity correction factor [unitless] + * @param FQ_low Low-pressure quantum correction factor [unitless] + * @param P_vap Vapor pressure [Pa] + * @param P_crit Critical pressure [Pa] + */ + double highPressureNondimensionalViscosity(double Tr, double Pr, double FP_low, + double FQ_low, double P_vap, + double P_crit); + + /** + * Calculates quantum correction term of the Lucas method for a species based + * on the reduced temperature(Tr) and molecular weight(MW), used in viscosity + * calculation. + * + * @f[ + * F_{Q}^{\text{o}} = 1.22 Q^{0.15} {1 + 0.00385[ (T_r - 12)^2 ]^{\frac{1}{MW}} + * \text{sign} (T_r - 12 )} + * + * \quad \text{(Equation 9-4.19)} + * @f] + * + * @param Q Species-specific constant + * @param Tr Reduced temperature [unitless] + * @param MW Molecular weight [kg/kmol] + */ + double quantumCorrectionFactor(double Q, double Tr, double MW); + + /** + * Returns the polarity correction term for a species based on reduced temperature, + * reduced dipole moment, and critical compressibility. Used in the calculation of + * viscosity. + * + * Calculates polarity correction term of the Lucas method for a species based + * on the reduced temperature(Tr) and molecular weight(MW). Equation 9.4.18. + * + * @f[ + * \begin{equation} + * F_P^0 = + * \begin{cases} + * 1 & 0 \leq \mu_r < 0.022 \\ + * 1 + 30.55(0.292 - Z_c)^{1.72} & 0.022 \leq \mu_r < 0.075 \\ + * 1 + 30.55(0.292 - Z_c)^{1.72} \times 0.96 + 0.1(T_r - 0.7) & 0.075 \leq \mu_r + * \end{cases} + * \end{equation} + * @f] + * + * @note The original description in Poling(2001) neglects to mention what happens + * when the quantity raised to the 1.72 power goes negative. That is an undefined + * operation that generates real and imaginary numbers. For now, only positive + * values are allowed. + * + * @param mu_r Species Reduced dipole moment + * @param Tr Reduced temperature + * @param Z_c Species Critical compressibility + */ + double polarityCorrectionFactor(double mu_r, double Tr, double Z_c); + + +private: + vector m_Tcrit; //!< Critical temperature [K] of each species + vector m_Pcrit; //!< Critical pressure [Pa] of each species + vector m_Vcrit; //!< Critical volume [m^3/kmol] of each species + vector m_Zcrit; //!< Critical compressibility [unitless] of each species + + //! Matrix of Takaishi binary diffusion coefficient corrections. Size is nsp x nsp. + DenseMatrix m_P_corr_ij; + + /** + * @name Reference fluid properties + * These are the properties of the reference fluid, which is methane in this case. + * These are used by the thermalConductivity() method. + * @{ + */ + const double m_ref_MW = 16.04; //!< Molecular weight [kg/kmol] + const double m_ref_Tc = 190.4; //!< Critical temperature [K] + const double m_ref_Vc = 0.0986; //!< Critical volume [m^3/kmol] + const double m_ref_Zc = 0.288; //!< Critical compressibility [unitless] + const double m_ref_rhoc = 0.1628; //!< Critical density [g/cm^3] + const double m_ref_acentric_factor = 0.011; //!< Acentric factor [unitless] + /** @} */ + + /** + * @name Lucas method viscosity parameters + * These are the parameters that are needed to calculate the viscosity using the + * Lucas method. + * @{ + */ + double m_FQ_mix_o; //!< Quantum correction factor + double m_FP_mix_o; //!< Polarity correction factor + double m_Tr_mix; //!< Reduced temperature + double m_Pr_mix; //!< Reduced pressure + double m_Pc_mix; //!< Critical pressure + double m_Tc_mix; //!< Critical temperature + double m_MW_mix; //!< Molecular weight + double m_P_vap_mix; //!< Vapor pressure + /** @} */ +}; + +/** + * Transport properties for high pressure gas mixtures using the Chung method for + * viscosity and thermal conductivity. * * The implementation employs a method of corresponding states, using the Takahashi - * @cite takahashi1975 approach for binary diffusion coefficients (using multicomponent - * averaging rules for the mixture properties), and the Lucas method for the viscosity - * of a high-pressure gas mixture. All methods are described in Poling et al. - * @cite poling2001 (viscosity in Ch. 9, thermal conductivity in Ch. 10, and diffusion - * coefficients in Ch. 11). + * @cite takahashi1975 approach for binary diffusion coefficients (using mixture + * averaging rules for the mixture properties), and the Chung method for the viscosity + * and thermal conductivity of a high-pressure gas mixture. All methods are described + * in Poling et al. @cite poling2001 (viscosity in Ch. 9, thermal conductivity in + * Ch. 10, and diffusion coefficients in Ch. 11). + * + * @note All equations that are cited in this implementation are from the 5th edition + * of the book "The Properties of Gases and Liquids" by Poling, Prausnitz, and + * O'Connell. * * @ingroup tranprops */ -class HighPressureGasTransport : public MultiTransport +class ChungHighPressureGasTransport : public MixTransport { protected: //! default constructor - HighPressureGasTransport() = default; + ChungHighPressureGasTransport()=default; public: string transportModel() const override { - return "HighPressureGas"; + return "high-pressure-Chung"; } - //! Return the thermal diffusion coefficients (kg/m/s) - /*! - * Currently not implemented for this model + void init(ThermoPhase* thermo, int mode=0, int log_level=0) override; + + /** + * Returns the high-pressure mixture viscosity in Pa*s using the Chung method. + * + * Based on the high-pressure gas mixture viscosity model of Chung described in + * chapter 9-7 of Poling. This method uses the pure species high-pressure viscosity + * relation of Chung with the difference being that mixture values of the model + * are computed using a set of mixing rules given by Chung + * (see computeMixtureParameters() ). The mixing rules are defined in section + * 9-5 of @cite poling2001. + * + * Because this method is using the high-pressure viscosity model with mixture + * parameters, see highPressureViscosity() for details on the model. */ - void getThermalDiffCoeffs(double* const dt) override; + double viscosity() override; + /** + * Calculates the high-pressure mixture thermal conductivity using the Chung method. + * + * This method obtains appropriate mixture values of the parameters needed for the + * Chung model and then calls the highPressureThermalConductivity() method to + * obtain the mixture thermal conductivity. + * + * The mixture values of the pseudo-critical temperature and other model parameters + * are calculated using the Chung mixing rules defined on page 9.25 + * (see computeMixtureParameters() ). + * + * The mixture value of the specific heat is computed using equation 10-6.6, which + * is the mole fraction weighted sum of the pure species specific heats. This value + * is not directly computed by the computeMixtureParameters() method. + * + * @f[ + * C_{v,m} = \sum_i X_i C_{v,i} + * + * \quad \text{(Equation 10-6.6)} + * @f] + * + * Where @f$ C_{v,i} @f$ is the specific heat of species i, and @f$ X_i @f$ is the + * mole fraction of species i. + */ double thermalConductivity() override; /** - * Returns the matrix of binary diffusion coefficients + * Computes the matrix of binary diffusion coefficients using the Takahashi + * correction factor. Units are m^2/s. * - * d[ld*j + i] = rp*m_bdiff(i,j)*(DP)_R; + * The matrix is dimension m_nsp x m_nsp, where m_nsp is the number of + * species. The matrix is stored in row-major order, so that d[ld*j + i] + * contains the binary diffusion coefficient of species i with respect to + * species j. * - * @param ld offset of rows in the storage - * @param d output vector of diffusion coefficients. Units of m**2 / s + * d[ld*j + i] = (DP)_R * m_bdiff(i,j) / p + * + * @param ld Inner stride for writing the two dimension diffusion + * coefficients into a one dimensional vector + * @param d Diffusion coefficient matrix (must be at least m_nsp * m_nsp + * in length. */ void getBinaryDiffCoeffs(const size_t ld, double* const d) override; - void getMultiDiffCoeffs(const size_t ld, double* const d) override; + /** + * Returns the Mixture-averaged diffusion coefficients [m^2/s]. + * + * This method is the same as GasTransport::getMixDiffCoeffs() with the exception + * that the binary diffusion coefficients are multiplied by the Takahashi correction + * factor, which is described in takahashiCorrectionFactor() . + * + * @param[out] d Vector of mixture diffusion coefficients, @f$ D_{km}' @f$ , + * for each species (m^2/s). length m_nsp + */ + void getMixDiffCoeffs(double* const d) override; + + /** + * Returns the mixture-averaged diffusion coefficients [m^2/s]. + * + * This method is the same as GasTransport::getMixDiffCoeffsMole() with the exception + * that the binary diffusion coefficients are multiplied by the Takahashi correction + * factor, which is described in takahashiCorrectionFactor() . + * + * @param[out] d vector of mixture-averaged diffusion coefficients for + * each species, length m_nsp. + */ + void getMixDiffCoeffsMole(double* const d) override; - double viscosity() override; + /** + * Returns the mixture-averaged diffusion coefficients [m^2/s]. + * + * This method is the same as GasTransport::getMixDiffCoeffsMass() with the exception + * that the binary diffusion coefficients are multiplied by the Takahashi correction + * factor, which is described in takahashiCorrectionFactor() . + * + * @param[out] d vector of mixture-averaged diffusion coefficients for + * each species, length m_nsp. + */ + void getMixDiffCoeffsMass(double* const d) override; + + /** + * Updates the matrix of species-pair Takahashi correction factors for use in + * computing the binary diffusion coefficients, see takahashiCorrectionFactor() + */ + void updateCorrectionFactors(); friend class TransportFactory; protected: + + /** + * Obtain required parameters from the 'critical-parameters' species input section, + * and checks the critical-properties.yaml file if an acentric factor is not + * specified. + * + * The way that GasTransport parses the input file is that if an acentric + * factor is not specified, it is quietly set to 0.0. A user may have the proper + * acentric factor in the critical-properties.yaml file, so that file is checked if + * a zero value is present. + */ + void getTransportData() override; + + /** + * Computes and stores the estimate of the critical properties for each species. + * + * This method sets the species composition vector to unity for species i and zero + * for all other species, and then queries the thermo object for the critical + * properties and stores them. It then resets the composition vector to the original + * state. This method only needs to be called once, as the critical properties for + * the pure species do not change. + * + * All species must have critical properties defined in the input file, either via + * critical properties or by specific values of the equation of state that are + * not zero. + */ + void initializeCriticalProperties(); + + //! Computes and stores pure-fluid specific properties each species. + void initializePureFluidProperties(); + + //! Returns the stored value of the critical temperature for a species 'i'. double Tcrit_i(size_t i); + //! Returns the stored value of the critical pressure for a species 'i'. double Pcrit_i(size_t i); + //! Returns the stored value of the critical volume for a species 'i'. double Vcrit_i(size_t i); + //! Returns the stored value of the critical compressibility for a species 'i'. double Zcrit_i(size_t i); - vector store(size_t i, size_t nsp); + /** + * Computes the composition-dependent values of the parameters needed for + * the Chung viscosity model. + * + * The equations for the mixing rules defined on page 9.25 for the Chung method's + * composition dependent parameters. The primary mixing rules are defined below. + * + * @f[ + * \sigma_m^3 = \sum_{i} \sum_{j} X_i X_j \sigma_{ij}^3 + * + * \quad \text{(Equation 9-5.25)} + * @f] + * + * Where @f$ \sigma_{ij} @f$ is the molecular diameter + * + * @f[ + * T_m^* = \frac{T}{\left( \frac{\epsilon}{k} \right )_m} + * + * \quad \text{(Equation 9-5.26)} + * @f] + * + * Where @f$ k @f$ is the Boltzmann constant and @f$ \epsilon @f$ is the minimum + * of the pair-potential energy. In these equations, we do not need to worry about + * what the values of @f$ \epsilon @f$ and @f$ k @f$ are. + * + * @f[ + * \left( \frac{\epsilon}{k} \right)_m = \frac{\sum_{i} \sum_{j} X_i X_j + * \left( \frac{\epsilon_{ij}}{k} \right) + * \sigma_{ij}^3}{\sigma_m^3} + * + * \quad \text{(Equation 9-5.27)} + * @f] + * + * @f[ + * MW_m = \left[ \frac{\sum_{i} \sum_{j} X_i X_j \left( \frac{\epsilon_{ij}}{k} \right) + * \sigma_{ij}^2 MW_{ij}^{\frac{1}{2}}}{\left( \frac{\epsilon}{k} \right)_m + * \sigma_m^2} \right]^2 + * + * \quad \text{(Equation 9-5.28)} + * @f] + * + * Where MW is the molecular weight. + * + * @f[ + * \omega_m = \frac{\sum_{i} \sum_{j} X_i X_j \omega_{ij} \sigma{ij}^3}{\sigma_m^3} + * + * \quad \text{(Equation 9-5.29)} + * @f] + * + * Where @f$ \omega @f$ is the acentric factor. + * + * @f[ + * \mu_m^4 = \sigma_m^3 \sum_{i} \sum_{j} \left( \frac{X_i X_j \mu_i^2 \mu_j^2} + * {\sigma_{ij}^3} \right) + * + * \quad \text{(Equation 9-5.30)} + * @f] + * + * Where @f$ \mu @f$ is the dipole moment. + * + * @f[ + * \kappa_m = \sum_{i} \sum_{j} X_i X_j \kappa_{ij} + * + * \quad \text{(Equation 9-5.31)} + * @f] + * + * Where @f$ \kappa @f$ is the association factor, which is used for highly polar + * molecules. In this work, the value is assumed to be zero for all species. + * + * The combining rules for species-species values (subscripted with ij in the above + * equations) are defined below. + * + * @f[ + * \sigma_{i} = 0.809 V_{c,i}^{1/3} + * + * \quad \text{(Equation 9-5.32)} + * @f] + * + * Where @f$ V_{c,i} @f$ is the critical volume of species i. + * + * @f[ + * \sigma_{ij} = \xi_{ij} \left( \sigma_{i} \sigma_{j} \right)^{1/2} + * + * \quad \text{(Equation 9-5.33)} + * @f] + * + * Where @f$ \xi @f$ is a binary interaction parameter. + * + * @f[ + * \left( \frac{\epsilon_i}{k} \right) = \frac{T_{c,i}}{1.2593} + * + * \quad \text{(Equation 9-5.34)} + * @f] + * + * @f[ + * \frac{\epsilon_{ij}}{k} = \zeta_{ij} \left( \right)^{\frac{1}{2}} + * + * \quad \text{(Equation 9-5.35)} + * @f] + * + * Where @f$ \zeta @f$ is a binary interaction parameter. + * + * @f[ + * \omega_{ij} = \frac{\omega_i + \omega_j}{2} + * + * \quad \text{(Equation 9-5.37)} + * @f] + * + * Where @f$ \omega @f$ is the acentric factor. + * + * @f[ + * \kappa_{ij} = \left( \kappa_i \kappa_j \right)^{1/2} + * + * \quad \text{(Equation 9-5.39)} + * @f] + * + * Where @f$ \kappa @f$ is the association factor. + * + * @f[ + * MW_{ij} = \frac{2 MW_i MW_j}{MW_i + MW_j} + * + * \quad \text{(Equation 9-5.40)} + * @f] + * + * @f$ \xi @f$ and @f$ \zeta @f$ are the binary interaction parameters, and are + * assumed to be unity in this implementation, in keeping with the Chung method. + * + * The Chung viscosity correction factor is defined as: + * + * @f[ + * F_{c,m} = 1 - 0.275 \omega_m + 0.059035 \mu_{r,m}^4 + \kappa_m + * + * \quad \text{(Equation 9-5.41)} + * @f] + * + * Where @f$ \omega_m @f$ is the mixture acentric factor, @f$ \mu_{r,m} @f$ is the + * mixture reduced dipole moment, and @f$ \kappa_m @f$ is the mixture association + * factor. + * + * The mixture reduced dipole moment is computed using: + * + * @f[ + * \mu_{r,m} = \frac{131.3 \mu_m}{( V_{c,m} T_{c,m})^{\frac{1}{2}}} + * + * \quad \text{(Equation 9-5.42)} + * @f] + * + * Where @f$ V_{c,m} @f$ and @f$ T_{c,m} @f$ are computed using the following + * equations. + * + * @f[ + * V_{c,m} = \left( \frac{\sigma_m}{0.809} \right)^3 + * + * \quad \text{(Equation 9-5.43)} + * @f] + * + * @f[ + * T_{c,m} = 1.2593 \left( \frac{\epsilon}{k} \right)_m + * + * \quad \text{(Equation 9-5.44)} + * @f] + * + * In the equations, @f$ T_c @f$ must be in units of K, @f$ V_c @f$ must be in + * units of cm^3/mol, and @f$ \mu @f$ must be in units of Debye. + */ + void computeMixtureParameters(); - double FQ_i(double Q, double Tr, double MW); + /** + * Returns the low-pressure mixture viscosity in Pa*s using the Chung method. + * + * @f[ + * \eta = 26.69 F_c \frac{(MW*T)^(1/2)}{\sigma^2 \Omega} + * + * \quad \text{(Equation 9-4.10)} + * @f] + * + * T must be in units of K, MW must be units of kg/kmol, and @f$ \sigma @f$ must + * be in units of Angstroms. The viscosity is computed in micropoise, but the + * return value is in standard SI units (Pa*s). + * + * This function is structured such that it can be used for pure species or + * mixtures, with the only difference being the values that are passed to the + * function (pure values versus mixture values). + * + * @param T Temperature [K] + * @param T_star Reduced temperature [unitless] + * @param MW Molecular weight [kg/kmol] + * @param acentric_factor Acentric factor [unitless] + * @param mu_r Dipole moment [Debye] + * @param sigma Lennard-Jones collision diameter [Angstroms] + * @param kappa Polar correction factor [unitless] + */ + double lowPressureViscosity(double T, double T_star, double MW, + double acentric_factor, double mu_r, + double sigma, double kappa); + + /** + * Returns the high-pressure mixture viscosity in micropoise using the Chung + * method. + * + * @f[ + * \eta = \eta^* \frac{36.344 (M*T_c)^(1/2)}{V^{\frac{2}{3}}} + * + * \quad \text{(Equation 9-6.18)} + * @f] + * + * where: + * + * @f[ + * \begin{align*} + * \eta &= \text{viscosity, } \mu P \\ + * M &= \text{molecular weight, kg/kmol} \\ + * T_c &= \text{critical temperature, K} \\ + * V_c &= \text{critical molar volume, cm}^3 / \text{mol} \\ + * \end{align*} + * @f] + * + * and, + * + * @f[ + * \eta^* = \frac{(T^*)^{\frac{1}{2}}}{\Omega_v} {F_c[(G_2)^{-1} + E_6 y]} + * + \eta^{**} + * + * \quad \text{(Equation 9-6.19)} + * @f] + * + * The values of @f$ T^* @f$ and @f$ F_c @f$ are defined as follows. + * + * @f[ + * T^* = 1.2593 T_r + * + * \quad \text{(Equation 9-4.9)} + * @f] + * + * @f[ + * F_c = 1 - 0.275 \omega + 0.059035 \mu_r^4 + \kappa + * + * \quad \text{(Equation 9-4.11)} + * @f] + * + * The value of @f$ \Omega_v @f$ is the viscosity collision integral evaluated at + * the non-dimensional reduced temperature @f$ T^* @f$. For details on the + * collision integral see neufeldCollisionIntegral() . + * + * This function is structured such that it can be used for pure species or + * mixtures, with the only difference being the values that are passed to the + * function (pure values versus mixture values). + * + * @param T_star Reduced temperature [unitless] + * @param MW Molecular weight [kg/kmol] + * @param rho Density [mol/cm^3] + * @param Vc Critical volume [cm^3/mol] + * @param Tc Critical temperature [K] + * @param acentric_factor Acentric factor [unitless] + * @param mu_r Dipole moment [Debye] + * @param kappa Polar correction factor [unitless] + */ + double highPressureViscosity(double T_star, double MW, double rho, double Vc, + double Tc, double acentric_factor, double mu_r, double kappa); + + /** + * Computes the high-pressure thermal conductivity using the Chung method in units + * of W/m/K + * + * The Chung method for computing high-pressure thermal conductivity is described + * on page 10.23 of @cite poling2001 . + * + * @f[ + * \lambda = \frac{31.2 \eta^0 \Psi}{M'} \left( G_2^{-1} + B_6 y \right) + * + q B_7 y^2 T_r^{1/2} G_2 + * + * \quad \text{(Equation 10-5.5)} + * @f] + * + * where: + * + * @f[ + * \begin{align*} + * \lambda &= \text{thermal conductivity, W/(m·K)} \\ + * \eta^0 &= \text{low-pressure gas viscosity, N·s/m}^2 \\ + * M' &= \text{molecular weight, kg/mol} \\ + * \Psi &= f(C_v, \omega, T_r) \text{ [as defined under Eq. (10-3.14)]} \\ + * q &= 3.586 \times 10^{-3} \left( \frac{T_c}{M'} \right)^{1/2} V_c^{2/3} \\ + * T &= \text{temperature, K} \\ + * T_c &= \text{critical temperature, K} \\ + * T_r &= \text{reduced temperature, } \frac{T}{T_c} \\ + * V_c &= \text{critical molar volume, cm}^3/\text{mol} \\ + * \end{align*} + * @f] + * + * where, + * + * @f[ + * y = \frac{V_c}{6V} + * + * \quad \text{(Equation 10-5.6)} + * @f] + * + * V is the molar volume of the fluid in cm^3/mol. + * + * @f[ + * G_1 = \frac{1 - 0.5y}{(1-y)^3} + * + * \quad \text{(Equation 10-5.7)} + * @f] + * + * @f[ + * G_2 = \frac{(B_1 / y)[1 - \text{exp}(-B_4 y)] + * + B_2 G_1 \text{exp}(B_5 y) + B_3 G_1}{B_1 B_4 + B_2 + B_3} + * + * \quad \text{(Equation 10-5.8)} + * @f] + * + * The coefficients @f$ B_1 @f$, through @f$ B_7 @f$ are functions of the + * acentric factor, reduced dipole moment and the association factor. + * + * @f[ + * B_i = a_i + b_i \omega + c_i \mu_r^4 + d_i \kappa + * + * \quad \text{(Equation 10-5.9)} + * @f] + * + * The constants in the above equation are from table 10-3 on page 10.23 of + * @cite poling2001. + * + * The definition of the @f$ \Psi @f$ function is given by: + * + * @f[ + * \Psi = 1 + \alpha {\frac{0.215 + 0.28288\alpha - 1.061\beta + 0.26665Z}{0.6366 + * + \beta Z + 1.061 \alpha \beta}} + * @f] + * + * with, + * + * @f[ + * \alpha = \frac{C_v}{R} - \frac{3}{2} + * @f] + * + * @f[ + * \beta = 0.7862 - 0.7109 \omega + 1.3168 \omega^2 + * @f] + * + * @f[ + * Z = 2.0 + 10.5 T_r^2 + * @f] + * + * These functions are from page 10.12 of @cite poling2001 . + * + * This method utilizes the low-pressure Chung viscosity as that is a required + * parameter in the model, and thus calls the low pressure viscosity + * implementation. This is why it requires parameters typically associated with + * the viscosity calculation. + * + * This function is structured such that it can be used for pure species or + * mixtures, with the only difference being the values that are passed to the + * function (pure values versus mixture values). + * + * For mixtures, the mixture values of the input variables are computed using the + * mixing rules of Chung, see computeMixtureParameters() . + * + * @param T Temperature [K] + * @param T_star Reduced temperature [unitless] + * @param MW Molecular weight [kg/kmol] + * @param rho Density [mol/cm^3] + * @param Cv Specific heat [J/kg/K] + * @param Vc Critical volume [cm^3/mol] + * @param Tc Critical temperature [K] + * @param sigma Lennard-Jones collision diameter [Angstroms] + * @param acentric_factor Acentric factor [unitless] + * @param mu_r Dipole moment [Debye] + * @param kappa Polar correction factor [unitless] + * @return High pressure thermal conductivity [W/m/K] + */ + double highPressureThermalConductivity(double T, double T_star, double MW, + double rho, double Cv, double Vc, double Tc, double sigma, + double acentric_factor, double mu_r, double kappa); + +private: + vector m_Tcrit; //!< Critical temperature [K] of each species + vector m_Pcrit; //!< Critical pressure [Pa] of each species + vector m_Vcrit; //!< Critical volume [m^3/kmol] of each species + vector m_Zcrit; //!< Critical compressibility of each species + + //! Matrix of Takaishi binary diffusion coefficient corrections. Size is nsp x nsp. + DenseMatrix m_P_corr_ij; + + /** + * @name Pure fluid properties + * These are the pure fluid properties of each species that are needed to compute + * the mixture properties for the Chung viscosity and thermal conductivity models. + */ + vector m_sigma_i; //!< Effective molecular diameter [Angstroms] + vector m_epsilon_over_k_i; //!< Characteristic temperature [K] + vector m_MW_i; //!< Molecular weight [kg/kmol] + vector m_acentric_factor_i; //!< Acentric factor [unitless] + vector m_kappa_i; //!< Association factor [unitless] + /** @} */ + + + /** + * @name Chung mixture parameters + * These are the parameters that are needed to calculate the viscosity and thermal + * conductivity using the Chung method. + * @{ + */ + double m_Vc_mix = 0; //!< Mixture critical volume [m^3/kmol] + double m_Tc_mix = 0; //!< Mixture critical temperature [K] + + double m_sigma_mix = 0; //!< Effective mixture molecular diameter [Angstroms] + double m_epsilon_over_k_mix = 0; //!< Mixture characteristic temperature [K] + double m_MW_mix = 0; //!< Effective mixture molecular weight [kg/kmol] + + // These are used to compute the Fc factor in the Chung viscosity model + double m_mu_mix = 0; //!< Mixture dipole moment [Debye] + double m_mu_r_mix = 0; //!< Mixture reduced dipole moment [unitless] + double m_acentric_factor_mix = 0; //!< Mixture acentric factor [unitless] + double m_kappa_mix = 0; //!< Mixture association factor [unitless] + + /** @} */ - double setPcorr(double Pr, double Tr); }; + } #endif diff --git a/samples/python/transport/high_pressure_transport.py b/samples/python/transport/high_pressure_transport.py new file mode 100644 index 0000000000..ef361156c2 --- /dev/null +++ b/samples/python/transport/high_pressure_transport.py @@ -0,0 +1,116 @@ +""" +High-Pressure transport using two models +======================================== + +Two high-pressure gas transport models are available in Cantera: the 'high-pressure' +and the 'high-pressure-Chung' models. These models utilize critical fluid properties +and other fluid-specific parameters to calculate transport properties at high pressures. +These models are useful for fluids that are supercritical where ideal gas assumptions +do not yield accurate results. + +Requires: cantera >= 3.1.0 + +.. tags:: Python, transport, non-ideal fluid +""" +import matplotlib.pyplot as plt +import numpy as np +import cantera as ct + + +# Nist data for Methane at 350 K. +nist_pressures = np.array([ + 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., 17., 18., 19., 20., 21., + 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32., 33., 34., 35., 36., 37., 38., + 39., 40., 41., 42., 43., 44., 45., 46., 47., 48., 49., 50., 51., 52., 53., 54., 55., + 56., 57., 58., 59., 60.]) + +nist_viscosities = np.array([ + 1.3460e-05, 1.3660e-05, 1.3875e-05, 1.4106e-05, 1.4352e-05, 1.4613e-05, 1.4889e-05, + 1.5179e-05, 1.5482e-05, 1.5798e-05, 1.6125e-05, 1.6463e-05, 1.6811e-05, 1.7167e-05, + 1.7531e-05, 1.7901e-05, 1.8276e-05, 1.8656e-05, 1.9040e-05, 1.9426e-05, 1.9813e-05, + 2.0202e-05, 2.0591e-05, 2.0980e-05, 2.1368e-05, 2.1755e-05, 2.2140e-05, 2.2523e-05, + 2.2904e-05, 2.3283e-05, 2.3659e-05, 2.4032e-05, 2.4403e-05, 2.4771e-05, 2.5135e-05, + 2.5497e-05, 2.5855e-05, 2.6211e-05, 2.6563e-05, 2.6913e-05, 2.7259e-05, 2.7603e-05, + 2.7944e-05, 2.8281e-05, 2.8616e-05, 2.8949e-05, 2.9278e-05, 2.9605e-05, 2.9929e-05, + 3.0251e-05, 3.0571e-05, 3.0888e-05, 3.1202e-05, 3.1514e-05, 3.1824e-05, 3.2132e-05]) + +nist_thermal_conductivities = np.array([ + 0.044665, 0.045419, 0.046217, 0.047063, 0.047954, 0.048891, 0.04987, 0.050891, + 0.051949, 0.05304, 0.05416, 0.055304, 0.056466, 0.057641, 0.058824, 0.06001, + 0.061194, 0.062374, 0.063546, 0.064707, 0.065855, 0.066988, 0.068106, 0.069208, + 0.070293, 0.071362, 0.072415, 0.073451, 0.074472, 0.075477, 0.076469, 0.077446, + 0.07841, 0.079361, 0.0803, 0.081227, 0.082143, 0.083048, 0.083944, 0.084829, + 0.085705, 0.086573, 0.087431, 0.088282, 0.089124, 0.089959, 0.090787, 0.091607, + 0.092421, 0.093228, 0.094029, 0.094824, 0.095612, 0.096395, 0.097172, 0.097944]) + +# %% +# Create the gas object for the methane-CO2 system using reference state thermo from +# the gri30 mechanism, species critical properties from `critical-properties.yaml`, +# and the Peng-Robinson equation of state. +phasedef = """ + phases: + - name: methane_co2 + species: + - gri30.yaml/species: [CH4, CO2] + thermo: Peng-Robinson + transport: mixture-averaged + state: {T: 300, P: 1 atm} +""" +gas = ct.Solution(yaml=phasedef) + +# Plot the difference between the high-pressure viscosity and thermal conductivity +# models and the ideal gas model for Methane. + +pressures = np.linspace(101325, 6e7, 100) +# Collect ideal viscosities and thermal conductivities +ideal_viscosities = [] +ideal_thermal_conductivities = [] +for pressure in pressures: + gas.TPX = 350, pressure, 'CH4:1.0' + ideal_viscosities.append(gas.viscosity) + ideal_thermal_conductivities.append(gas.thermal_conductivity) + +# Collect real viscosities using the high-pressure-Chung +gas.transport_model = 'high-pressure-Chung' +real_viscosities_1 = [] +real_thermal_conductivities_1 = [] +for pressure in pressures: + gas.TPX = 350, pressure, 'CH4:1.0' + real_viscosities_1.append(gas.viscosity) + real_thermal_conductivities_1.append(gas.thermal_conductivity) + +# Collect real viscosities using the high-pressure model +gas.transport_model = 'high-pressure' +real_viscosities_2 = [] +real_thermal_conductivities_2 = [] +for pressure in pressures: + gas.TPX = 350, pressure, 'CH4:1.0' + real_viscosities_2.append(gas.viscosity) + real_thermal_conductivities_2.append(gas.thermal_conductivity) + +# %% +# Plot the data +# ------------- +mpa_to_pa = 1e6 # conversion factor from MPa to Pa +fig, ax = plt.subplots() +ax.plot(pressures, ideal_viscosities, label='Ideal Viscosity') +ax.plot(pressures, real_viscosities_1, label='High-Pressure Viscosity (Chung)') +ax.plot(pressures, real_viscosities_2, label='High-Pressure Viscosity') +ax.plot(nist_pressures*mpa_to_pa, nist_viscosities, 'o', label='NIST Data') +ax.set(xlabel='Pressure (Pa)', ylabel ='Viscosity (Pa·s)', + title='Methane Viscosity Model Comparison') +ax.legend() +ax.grid(True) +plt.show() + +# %% +fig, ax = plt.subplots() +ax.plot(pressures, ideal_thermal_conductivities, label='Ideal Thermal Conductivity') +ax.plot(pressures, real_thermal_conductivities_1, label='High-Pressure Thermal Conductivity (Chung)') +ax.plot(pressures, real_thermal_conductivities_2, label='High-Pressure Thermal Conductivity') +ax.plot(nist_pressures*mpa_to_pa, nist_thermal_conductivities, 'o', label='NIST Data') +ax.set(xlabel='Pressure (Pa)', ylabel ='Thermal Conductivity (W/m·K)', + title='Methane Thermal Conductivity Model Comparison') +ax.legend() +ax.grid(True) +plt.show() diff --git a/src/transport/HighPressureGasTransport.cpp b/src/transport/HighPressureGasTransport.cpp index 0463fbd77d..cd84a3cb7b 100644 --- a/src/transport/HighPressureGasTransport.cpp +++ b/src/transport/HighPressureGasTransport.cpp @@ -7,314 +7,622 @@ // at https://cantera.org/license.txt for license and copyright information. #include "cantera/transport/HighPressureGasTransport.h" -#include "cantera/numerics/ctlapack.h" #include "cantera/base/utilities.h" #include "cantera/thermo/IdealGasPhase.h" #include "cantera/transport/TransportFactory.h" #include "cantera/base/stringUtils.h" -#include "cantera/transport/MultiTransport.h" +#include "cantera/thermo/Species.h" +#include + using namespace std; namespace Cantera { +/** + * @brief Returns interpolated value of (DP)_R obtained from the data in Table 2 of + * the Takahashi 1975 paper, given a value of the reduced pressure (Pr) and reduced + * temperature (Tr). + * + * @param Pr Reduced pressure + * @param Tr Reduced temperature + */ +double takahashiCorrectionFactor(double Pr, double Tr) +{ + // In the low pressure limit, no correction is needed. Interpolate + // the value towards 1 as pressure drops below the 0.1 threshold. + if (Pr < 0.1) { + return 1.0; + } + + // Data from Table 2 of Takahashi 1975 paper: + const static double Pr_lookup[17] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.8, 1.0, + 1.2, 1.4, 1.6, 1.8, 2.0, 2.5, 3.0, 4.0, 5.0}; + const static double DP_Rt_lookup[17] = {1.01, 1.01, 1.01, 1.01, 1.01, 1.01, + 1.01, 1.02, 1.02, 1.02, 1.02, 1.03, 1.03, 1.04, 1.05, 1.06, 1.07}; + const static double A_ij_lookup[17] = {0.038042, 0.067433, 0.098317, + 0.137610, 0.175081, 0.216376, 0.314051, 0.385736, 0.514553, 0.599184, + 0.557725, 0.593007, 0.696001, 0.790770, 0.502100, 0.837452, 0.890390}; + const static double B_ij_lookup[17] = {1.52267, 2.16794, 2.42910, 2.77605, + 2.98256, 3.11384, 3.50264, 3.07773, 3.54744, 3.61216, 3.41882, 3.18415, + 3.37660, 3.27984, 3.39031, 3.23513, 3.13001}; + const static double C_ij_lookup[17] = {0., 0., 0., 0., 0., 0., 0., 0.141211, + 0.278407, 0.372683, 0.504894, 0.678469, 0.665702, 0., 0.602907, 0., 0.}; + const static double E_ij_lookup[17] = {1., 1., 1., 1., 1., 1., 1., 13.45454, + 14., 10.00900, 8.57519, 10.37483, 11.21674, 1., 6.19043, 1., 1.}; + + // Interpolate to obtain the value of (DP)_R at + // the provided value of the reduced pressure (Pr). + int Pr_lower = 0; // Index of the lower bounding value of Pr + int Pr_upper = 0; // Index of the upper bounding value of Pr + double frac = 0.0; + + bool found = false; + for (int j = 1; j < 17; j++){ + if (Pr_lookup[j] > Pr) { + frac = (Pr - Pr_lookup[j-1])/(Pr_lookup[j] - Pr_lookup[j-1]); + found = true; + Pr_lower = j-1; + Pr_upper = j; + break; + } + } + // If this loop completes without finding a bounding value of Pr, use + // the final table value. + if (!found) { + Pr_lower = 16; + Pr_upper = 16; + frac = 1.0; + } + + // Compute the value of (DP)_R at the given Pr value by interpolating the + // bounding values of (DP)_R. + double A, B, C, E, DP_Rt, DP_R_lower, DP_R_upper; + DP_Rt = DP_Rt_lookup[Pr_lower]; + A = A_ij_lookup[Pr_lower]; + B = B_ij_lookup[Pr_lower]; + C = C_ij_lookup[Pr_lower]; + E = E_ij_lookup[Pr_lower]; + + DP_R_lower = DP_Rt*(1.0 - A*pow(Tr,-B))*(1.0 - C*pow(Tr,-E)); + + DP_Rt = DP_Rt_lookup[Pr_upper]; + A = A_ij_lookup[Pr_upper]; + B = B_ij_lookup[Pr_upper]; + C = C_ij_lookup[Pr_upper]; + E = E_ij_lookup[Pr_upper]; + + DP_R_upper = DP_Rt*(1.0 - A*pow(Tr,-B))*(1.0 - C*pow(Tr,-E)); + + // Linear interpolation of the two bounding values of (DP)_R. + return DP_R_lower*(1.0 - frac) + DP_R_upper*frac; +} + +void HighPressureGasTransport::init(ThermoPhase* thermo, int mode, int log_level) +{ + MixTransport::init(thermo, mode, log_level); + initializeCriticalProperties(); + m_P_corr_ij.resize(m_nsp, m_nsp); +} + +void HighPressureGasTransport::getTransportData() +{ + // Call the base class's method to fill the properties + GasTransport::getTransportData(); + + // Contents of 'critical-properties.yaml', loaded later if needed + AnyMap critPropsDb; + std::unordered_map dbSpecies; + + // If a species has a zero acentric factor, check the critical-properties.yaml + // database to see if it has a value specified for the species. + for (size_t k = 0; k < m_thermo->nSpecies(); k++) { + if (m_w_ac[k] == 0.0) { + // Load 'crit-properties.yaml' file if not already loaded + if (critPropsDb.empty()) { + critPropsDb = AnyMap::fromYamlFile("critical-properties.yaml"); + dbSpecies = critPropsDb["species"].asMap("name"); + } + + // All names in critical-properties.yaml are upper case + auto ucName = boost::algorithm::to_upper_copy(m_thermo->species(k)->name); + if (dbSpecies.count(ucName)) { + auto& spec = *dbSpecies.at(ucName); + auto& critProps = spec["critical-parameters"].as(); + if (critProps.hasKey("acentric-factor")) { + m_w_ac[k] = critProps.convert("acentric-factor", "1"); + } + } + } + } +} + +void HighPressureGasTransport::initializeCriticalProperties() +{ + size_t nSpecies = m_thermo->nSpecies(); + m_Tcrit.resize(nSpecies); + m_Pcrit.resize(nSpecies); + m_Vcrit.resize(nSpecies); + m_Zcrit.resize(nSpecies); + + std::vector molefracs(nSpecies); + m_thermo->getMoleFractions(&molefracs[0]); + + std::vector mf_temp(nSpecies, 0.0); + + for (size_t i = 0; i < nSpecies; ++i) { + mf_temp[i] = 1.0; + m_thermo->setMoleFractions(&mf_temp[0]); + + if (m_thermo->critTemperature() > 1e4) { + throw CanteraError("HighPressureGasTransport::initializeCriticalProperties", + "Species '{}' must have critical properties defined or non-zero cubic parameters. " + "Check the species definition or the thermo data file.", + m_thermo->species(i)->name); + } + m_Tcrit[i] = m_thermo->critTemperature(); + m_Pcrit[i] = m_thermo->critPressure(); + m_Vcrit[i] = m_thermo->critVolume(); + m_Zcrit[i] = m_thermo->critCompressibility(); + + mf_temp[i] = 0.0; // Reset for the next iteration + } + + // Restore actual mole fractions + m_thermo->setMoleFractions(&molefracs[0]); +} + double HighPressureGasTransport::thermalConductivity() { - // Method of Ely and Hanley: update_T(); - double Lprime_m = 0.0; - const double c1 = 1./16.04; - size_t nsp = m_thermo->nSpecies(); - vector molefracs(nsp); + vector molefracs(m_nsp); m_thermo->getMoleFractions(&molefracs[0]); - vector cp_0_R(nsp); - m_thermo->getCp_R_ref(&cp_0_R[0]); + vector cp_0_R(m_nsp); + m_thermo->getCp_R_ref(&cp_0_R[0]); // Cp/R - vector L_i(nsp); - vector f_i(nsp); - vector h_i(nsp); - vector V_k(nsp); + // A model constant from the Euken correlation for polyatomic gases, described + // below Equation 1 in ely-hanley1981 . + const double f_int = 1.32; - m_thermo -> getPartialMolarVolumes(&V_k[0]); - double L_i_min = BigNumber; + // Pure-species model parameters + // Internal contribution to thermal conductivity (lamba'') + vector Lambda_1_i(m_nsp); + vector f_i(m_nsp); + vector h_i(m_nsp); + vector V_k(m_nsp); + m_thermo -> getPartialMolarVolumes(&V_k[0]); for (size_t i = 0; i < m_nsp; i++) { - double Tc_i = Tcrit_i(i); - double Vc_i = Vcrit_i(i); - double T_r = m_thermo->temperature()/Tc_i; - double V_r = V_k[i]/Vc_i; - double T_p = std::min(T_r,2.0); - double V_p = std::max(0.5,std::min(V_r,2.0)); - - // Calculate variables for density-independent component: - double theta_p = 1.0 + (m_w_ac[i] - 0.011)*(0.56553 - - 0.86276*log(T_p) - 0.69852/T_p); - double phi_p = (1.0 + (m_w_ac[i] - 0.011)*(0.38560 - - 1.1617*log(T_p)))*0.288/Zcrit_i(i); - double f_fac = Tc_i*theta_p/190.4; - double h_fac = 1000*Vc_i*phi_p/99.2; - double T_0 = m_temp/f_fac; - double mu_0 = 1e-7*(2.90774e6/T_0 - 3.31287e6*pow(T_0,-2./3.) - + 1.60810e6*pow(T_0,-1./3.) - 4.33190e5 + 7.06248e4*pow(T_0,1./3.) - - 7.11662e3*pow(T_0,2./3.) + 4.32517e2*T_0 - 1.44591e1*pow(T_0,4./3.) - + 2.03712e-1*pow(T_0,5./3.)); - double H = sqrt(f_fac*16.04/m_mw[i])*pow(h_fac,-2./3.); - double mu_i = mu_0*H*m_mw[i]*c1; - L_i[i] = mu_i*1.32*GasConstant*(cp_0_R[i] - 2.5)/m_mw[i]; - L_i_min = min(L_i_min,L_i[i]); - // Calculate variables for density-dependent component: - double theta_s = 1 + (m_w_ac[i] - 0.011)*(0.09057 - 0.86276*log(T_p) - + (0.31664 - 0.46568/T_p)*(V_p - 0.5)); - double phi_s = (1 + (m_w_ac[i] - 0.011)*(0.39490*(V_p - 1.02355) - - 0.93281*(V_p - 0.75464)*log(T_p)))*0.288/Zcrit_i(i); - f_i[i] = Tc_i*theta_s/190.4; - h_i[i] = 1000*Vc_i*phi_s/99.2; - } - - double h_m = 0; - double f_m = 0; - double mw_m = 0; + // Calculate variables for density-independent component, Equation 1, + // the equation requires the pure-species viscosity estimate from + // Ely and Hanley. + double mu_i = elyHanleyDilutePureSpeciesViscosity(V_k[i], Tcrit_i(i), + Vcrit_i(i), Zcrit_i(i), + m_w_ac[i], m_mw[i]); + + // This is the internal contribution to the thermal conductivity of + // pure-species component, i, from Equation 1 in ely-hanley1983 + Lambda_1_i[i] = (mu_i / m_mw[i])*f_int*GasConstant*(cp_0_R[i] - 2.5); + + // Calculate variables for density-dependent component (lambda') + double Tr = m_thermo->temperature() / Tcrit_i(i); + double Vr = V_k[i] / Vcrit_i(i); + double theta_i = thetaShapeFactor(Tr, Vr, m_w_ac[i]); + double phi_i = phiShapeFactor(Tr, Vr, Zcrit_i(i), m_w_ac[i]); + + f_i[i] = (Tcrit_i(i) / m_ref_Tc)*theta_i; // Equation 12 ely-hanley1983 + h_i[i] = (Vcrit_i(i) / m_ref_Vc)*phi_i; // Equation 13 ely-hanley1983 + } + + double h_m = 0; // Corresponding states parameter, h_x,0 from ely-hanley1983 + double f_m = 0; // Corresponding states parameter, f_x,0 from ely-hanley1983 + double mw_m = 0; // Mixture molecular weight + double Lambda_1_m = 0.0; // Internal component of mixture thermal conductivity for (size_t i = 0; i < m_nsp; i++) { for (size_t j = 0; j < m_nsp; j++) { - // Density-independent component: - double L_ij = 2*L_i[i]*L_i[j]/(L_i[i] + L_i[j] + Tiny); - Lprime_m += molefracs[i]*molefracs[j]*L_ij; - // Additional variables for density-dependent component: + // Compute the internal contribution to the thermal conductivity of the + // mixture + + // Equation 3 ely-hanley1983 + double Lambda_1_ij = 2*Lambda_1_i[i]*Lambda_1_i[j] / + (Lambda_1_i[i] + Lambda_1_i[j] + Tiny); + // Equation 2, ely-hanley1983 + Lambda_1_m += molefracs[i]*molefracs[j]*Lambda_1_ij; + + // Variables for density-dependent translational/collisional component of + // the mixture. + + // Equation 10, ely-hanley1983 double f_ij = sqrt(f_i[i]*f_i[j]); - double h_ij = 0.125*pow(pow(h_i[i],1./3.) + pow(h_i[j],1./3.),3.); - double mw_ij_inv = (m_mw[i] + m_mw[j])/(2*m_mw[i]*m_mw[j]); + + // Equation 11, ely-hanley1983 + double h_ij = 0.125*pow(pow(h_i[i],1.0/3.0) + pow(h_i[j],1.0/3.0), 3.0); + + // Equation 15, ely-hanley1983 + double mw_ij_inv = 0.5*(m_mw[i] + m_mw[j])/(m_mw[i]*m_mw[j]); + + // Equation 8, ely-hanley1983 f_m += molefracs[i]*molefracs[j]*f_ij*h_ij; + + // Equation 9, ely-hanley1983 h_m += molefracs[i]*molefracs[j]*h_ij; - mw_m += molefracs[i]*molefracs[j]*sqrt(mw_ij_inv*f_ij)*pow(h_ij,-4./3.); + + // Equation, 14 ely-hanley1983 + mw_m += molefracs[i]*molefracs[j]*sqrt(mw_ij_inv*f_ij)*pow(h_ij,-4.0/3.0); } } + // The following two equations are the final steps for Equations 8 and 14 in + // ely-hanley1983 . The calculations in the loop above computed the + // right-hand-side of the equations, but the left-hand-side of the equations + // contain other variables that must be moved to the right-hand-side in order to + // get the values of the variables of interest. f_m = f_m/h_m; - mw_m = pow(mw_m,-2.)*f_m*pow(h_m,-8./3.); + mw_m = pow(mw_m,-2.0)*f_m*pow(h_m,-8.0/3.0); - double rho_0 = 16.04*h_m/(1000*m_thermo->molarVolume()); + // The two relations below are from Equation 7, ely-hanley1983 . This must + // be in units of g/cm^3 for use with the empirical correlation. + const double kg_m3_to_g_cm3 = 1e-3; // Conversion factor from kg/m^3 to g/cm^3 + double rho_0 = m_thermo->density()*h_m*kg_m3_to_g_cm3; double T_0 = m_temp/f_m; - double mu_0 = 1e-7*(2.90774e6/T_0 - 3.31287e6*pow(T_0,-2./3.) - + 1.60810e6*pow(T_0,-1./3.) - 4.33190e5 + 7.06248e4 - *pow(T_0,1./3.) - 7.11662e3*pow(T_0,2./3.) + 4.32517e2*T_0 - - 1.44591e1*pow(T_0,4./3.) + 2.03712e-1*pow(T_0,5./3.)); - double L_1m = 1944*mu_0; - double L_2m = (-2.5276e-4 + 3.3433e-4*pow(1.12 - log(T_0/1.680e2),2))*rho_0; - double L_3m = exp(-7.19771 + 85.67822/T_0)*(exp((12.47183 - - 984.6252*pow(T_0,-1.5))*pow(rho_0,0.1) + (rho_0/0.1617 - 1) - *sqrt(rho_0)*(0.3594685 + 69.79841/T_0 - 872.8833*pow(T_0,-2))) - 1.)*1e-3; - double H_m = sqrt(f_m*16.04/mw_m)*pow(h_m,-2./3.); - double Lstar_m = H_m*(L_1m + L_2m + L_3m); - return Lprime_m + Lstar_m; -} - -void HighPressureGasTransport::getThermalDiffCoeffs(double* const dt) -{ - // Method for MultiTransport class: - // solveLMatrixEquation(); - // const double c = 1.6/GasConstant; - // for (size_t k = 0; k < m_nsp; k++) { - // dt[k] = c * m_mw[k] * m_molefracs[k] * m_a[k]; - // } - throw NotImplementedError("HighPressureGasTransport::getThermalDiffCoeffs"); + + // Equation 18, ely-hanley1983 + double Lambda_2_ref = elyHanleyReferenceThermalConductivity(rho_0, T_0); + + // Equation 6, ely-hanley1983 + double F_m = sqrt(f_m*m_ref_MW/mw_m)*pow(h_m,-2.0/3.0); + + // Equation 5, ely-hanley1983 + double Lambda_2_m = F_m*Lambda_2_ref; + + return Lambda_1_m + Lambda_2_m; } -void HighPressureGasTransport::getBinaryDiffCoeffs(const size_t ld, double* const d) +double HighPressureGasTransport::elyHanleyDilutePureSpeciesViscosity(double V, + double Tc, double Vc, double Zc, double acentric_factor, double mw) { - vector PcP(5); - size_t nsp = m_thermo->nSpecies(); - vector molefracs(nsp); - m_thermo->getMoleFractions(&molefracs[0]); + double Tr = m_thermo->temperature() / Tc; + double Vr = V / Vc; + double theta_i = thetaShapeFactor(Tr, Vr, acentric_factor); + double phi_i = phiShapeFactor(Tr, Vr, Zc, acentric_factor); - update_T(); - // Evaluate the binary diffusion coefficients from the polynomial fits. - // This should perhaps be preceded by a check to see whether any of T, P, or - // C have changed. - //if (!m_bindiff_ok) { - updateDiff_T(); - //} - if (ld < nsp) { - throw CanteraError("HighPressureGasTransport::getBinaryDiffCoeffs", - "ld is too small"); + double f_fac = (Tc / m_ref_Tc)*theta_i; // Equation 7 ely-hanley1981 + double h_fac = (Vc / m_ref_Vc)*phi_i; // Equation 8 ely-hanley1981 + double T_0 = m_temp/f_fac; // Equation 3, ely-hanley1981 + + // Dilute reference fluid viscosity correlation, from Table III in + // ely-hanley1981 + double mu_0 = elyHanleyDiluteReferenceViscosity(T_0); + + // Equation 2, ely-hanley1981 + double F = sqrt(f_fac*(mw/m_ref_MW))*pow(h_fac,-2.0/3.0); + + return mu_0*F; +} + +double HighPressureGasTransport::thetaShapeFactor(double Tr, double Vr, + double acentric_factor) +{ + double T_p = std::min(std::max(Tr,0.5), 2.0); + double V_p = std::min(std::max(Vr,0.5), 2.0); + + return 1 + (acentric_factor - m_ref_acentric_factor)*(0.090569 - 0.862762*log(T_p) + + (0.316636 - 0.465684/T_p)*(V_p - 0.5)); + +} + +double HighPressureGasTransport::phiShapeFactor(double Tr, double Vr, double Zc, + double acentric_factor) +{ + double T_p = std::min(std::max(Tr,0.5), 2.0); + double V_p = std::min(std::max(Vr,0.5), 2.0); + + return (1 + (acentric_factor - m_ref_acentric_factor)*(0.394901*(V_p - 1.023545) + - 0.932813*(V_p - 0.754639)*log(T_p)))*(m_ref_Zc/Zc); + +} + +double HighPressureGasTransport::elyHanleyDiluteReferenceViscosity(double T0) +{ + // Conversion factor from the correlation in micrograms/cm/s to Pa*s. + double const correlation_viscosity_conversion = 1e-7; + + if (T0 > 10000) { + T0 = 10000; // Limit the temperature to 10000 K } - double rp = 1.0/m_thermo->pressure(); - for (size_t i = 0; i < nsp; i++) { - for (size_t j = 0; j < nsp; j++) { + + // Coefficients for the correlation from Table III of ely-hanley1981 + const std::vector c = {2.907741307e6, -3.312874033e6, 1.608101838e6, + -4.331904871e5, 7.062481330e4, -7.116620750e3, + 4.325174400e2, -1.445911210e1, 2.037119479e-1}; + + double mu_0 = 0.0; + for (size_t i = 0; i < 9; i++) { + mu_0 += c[i]*pow(T0,(i+1.0-4.0)/3.0); + } + return correlation_viscosity_conversion*mu_0; +} + +double HighPressureGasTransport::elyHanleyReferenceThermalConductivity(double rho0, + double T0) +{ + // Computing the individual terms of Equation 18, ely-hanley1983 . This is an + // evaluation of the expressions shown in Table I of ely-hanley1983 . The + // correlation returns values of thermal conductivity in mW/m/K, + // so a conversion is needed. + const double correlation_factor = 1e-3; // mW/m/K to W/m/K + + // This is the reference gas, dilute gas viscosity (eta_0 in Table III of + // ely-hanley1981) + double mu_0 = elyHanleyDiluteReferenceViscosity(T0); + + // First term in Equation 18. This expression has the correct units because + // it does not use any empirical correlation, so it is excluded at the end from + // the unit conversion. + double Lambda_ref_star = (15*GasConstant / (4*m_ref_MW))*mu_0; + + // Second term in Equation 18 + const vector b = {-2.52762920e-1, 3.34328590e-1, 1.12, 1.680e2}; + double Lambda_ref_1 = (b[0] + b[1]*pow(b[2] - log(T0/b[3]), 2))*rho0; + + // Third term in Equation 18 + const vector a = {-7.197708227, 8.5678222640e1, 1.2471834689e1, + -9.8462522975e2, 3.5946850007e-1, 6.9798412538e1, + -8.7288332851e2}; + double delta_lambda_ref = exp(a[0] + a[1]/T0) + * (exp((a[2] + a[3]*pow(T0,-1.5))*pow(rho0,0.1) + + (rho0/m_ref_rhoc - 1)*sqrt(rho0)*(a[4] + a[5]/T0 + + a[6]*pow(T0,-2))) - 1.0); + + return Lambda_ref_star + (Lambda_ref_1 + delta_lambda_ref)*correlation_factor; +} + +void HighPressureGasTransport::updateCorrectionFactors() { + for (size_t i = 0; i < m_nsp; i++) { + for (size_t j = 0; j < m_nsp; j++) { // Add an offset to avoid a condition where x_i and x_j both equal - // zero (this would lead to Pr_ij = Inf): - double x_i = std::max(Tiny, molefracs[i]); - double x_j = std::max(Tiny, molefracs[j]); + // zero (this would lead to Pr_ij = Inf). + double x_i = std::max(Tiny, m_molefracs[i]); + double x_j = std::max(Tiny, m_molefracs[j]); - // Weight mole fractions of i and j so that X_i + X_j = 1.0: - x_i = x_i/(x_i + x_j); - x_j = x_j/(x_i + x_j); + // Weight mole fractions of i and j so that X_i + X_j = 1.0. + double sum_x_ij = x_i + x_j; + x_i = x_i/(sum_x_ij); + x_j = x_j/(sum_x_ij); - //Calculate Tr and Pr based on mole-fraction-weighted crit constants: + // Calculate Tr and Pr based on mole-fraction-weighted critical constants. double Tr_ij = m_temp/(x_i*Tcrit_i(i) + x_j*Tcrit_i(j)); double Pr_ij = m_thermo->pressure()/(x_i*Pcrit_i(i) + x_j*Pcrit_i(j)); + // Calculate the parameters for Takahashi correlation double P_corr_ij; - if (Pr_ij < 0.1) { - // If pressure is low enough, no correction is needed: - P_corr_ij = 1; - }else { - // Otherwise, calculate the parameters for Takahashi correlation - // by interpolating on Pr_ij: - P_corr_ij = setPcorr(Pr_ij, Tr_ij); - - // If the reduced temperature is too low, the correction factor - // P_corr_ij will be < 0: - if (P_corr_ij<0) { - P_corr_ij = Tiny; - } - } + P_corr_ij = takahashiCorrectionFactor(Pr_ij, Tr_ij); - // Multiply the standard low-pressure binary diffusion coefficient - // (m_bdiff) by the Takahashi correction factor P_corr_ij: - d[ld*j + i] = P_corr_ij*rp * m_bdiff(i,j); + // If the reduced temperature is too low, the correction factor + // P_corr_ij will be < 0. + if (P_corr_ij<0) { + P_corr_ij = Tiny; + } + m_P_corr_ij(i, j) = P_corr_ij; } } } -void HighPressureGasTransport::getMultiDiffCoeffs(const size_t ld, double* const d) +void HighPressureGasTransport::getBinaryDiffCoeffs(const size_t ld, double* const d) { - // Not currently implemented. m_Lmatrix inversion returns NaN. Needs to be - // fixed. --SCD - 2-28-2014 - throw NotImplementedError("HighPressureGasTransport:getMultiDiffCoeffs"); - // Calculate the multi-component Stefan-Maxwell diffusion coefficients, - // based on the Takahashi-correlation-corrected binary diffusion coefficients. - - // update the mole fractions update_C(); - - // update the binary diffusion coefficients update_T(); - updateThermal_T(); - - // Correct the binary diffusion coefficients for high-pressure effects; this - // is basically the same routine used in 'getBinaryDiffCoeffs,' above: - size_t nsp = m_thermo->nSpecies(); - vector molefracs(nsp); - m_thermo->getMoleFractions(&molefracs[0]); - update_T(); - // Evaluate the binary diffusion coefficients from the polynomial fits - - // this should perhaps be preceded by a check for changes in T, P, or C. - updateDiff_T(); - + updateCorrectionFactors(); + // If necessary, evaluate the binary diffusion coefficients from the polynomial + // fits + if (!m_bindiff_ok) { + updateDiff_T(); + } if (ld < m_nsp) { - throw CanteraError("HighPressureGasTransport::getMultiDiffCoeffs", + throw CanteraError("HighPressureGasTransport::getBinaryDiffCoeffs", "ld is too small"); } + + double rp = 1.0/m_thermo->pressure(); for (size_t i = 0; i < m_nsp; i++) { for (size_t j = 0; j < m_nsp; j++) { - // Add an offset to avoid a condition where x_i and x_j both equal - // zero (this would lead to Pr_ij = Inf): - double x_i = std::max(Tiny, molefracs[i]); - double x_j = std::max(Tiny, molefracs[j]); - x_i = x_i/(x_i+x_j); - x_j = x_j/(x_i+x_j); - double Tr_ij = m_temp/(x_i*Tcrit_i(i) + x_j*Tcrit_i(j)); - double Pr_ij = m_thermo->pressure()/(x_i*Pcrit_i(i) + x_j*Pcrit_i(j)); + // Multiply the standard low-pressure binary diffusion coefficient + // (m_bdiff) by the Takahashi correction factor P_corr_ij. + d[ld*j + i] = m_P_corr_ij(i,j)*(rp * m_bdiff(i,j)); + } + } +} - double P_corr_ij; - if (Pr_ij < 0.1) { - P_corr_ij = 1; - }else { - P_corr_ij = setPcorr(Pr_ij, Tr_ij); - if (P_corr_ij<0) { - P_corr_ij = Tiny; +void HighPressureGasTransport::getMixDiffCoeffs(double* const d) +{ + update_T(); + update_C(); + updateCorrectionFactors(); + + // update the binary diffusion coefficients if necessary + if (!m_bindiff_ok) { + updateDiff_T(); + } + + double mmw = m_thermo->meanMolecularWeight(); + double p = m_thermo->pressure(); + if (m_nsp == 1) { + d[0] = m_P_corr_ij(0,0)*m_bdiff(0,0) / p; + } else { + for (size_t i = 0; i < m_nsp; i++) { + double sum2 = 0.0; + for (size_t j = 0; j < m_nsp; j++) { + if (j != i) { + sum2 += m_molefracs[j] / (m_P_corr_ij(i,j)*m_bdiff(j,i)); } } - - m_bdiff(i,j) *= P_corr_ij; + if (sum2 <= 0.0) { + d[i] = m_P_corr_ij(i,i)*m_bdiff(i,i) / p; + } else { + d[i] = (mmw - m_molefracs[i] * m_mw[i])/(p * mmw * sum2); + } } } - m_bindiff_ok = false; // m_bdiff is overwritten by the above routine. +} - // Having corrected m_bdiff for pressure and concentration effects, the - // routine now proceeds the same as in the low-pressure case: +void HighPressureGasTransport::getMixDiffCoeffsMole(double* const d) +{ + update_T(); + update_C(); + updateCorrectionFactors(); - // evaluate L0000 if the temperature or concentrations have - // changed since it was last evaluated. - if (!m_l0000_ok) { - eval_L0000(molefracs.data()); + // update the binary diffusion coefficients if necessary + if (!m_bindiff_ok) { + updateDiff_T(); } - // invert L00,00 - invert(m_Lmatrix, m_nsp); - m_l0000_ok = false; // matrix is overwritten by inverse - m_lmatrix_soln_ok = false; + double p = m_thermo->pressure(); + if (m_nsp == 1) { + d[0] = m_P_corr_ij(0,0)*m_bdiff(0,0) / p; + } else { + for (size_t i = 0; i < m_nsp; i++) { + double sum2 = 0.0; + for (size_t j = 0; j < m_nsp; j++) { + if (j != i) { + sum2 += m_molefracs[j] / (m_P_corr_ij(i,j)*m_bdiff(j,i)); + } + } + if (sum2 <= 0.0) { + d[i] = m_P_corr_ij(i,i)*m_bdiff(i,i) / p; + } else { + d[i] = (1 - m_molefracs[i]) / (p * sum2); + } + } + } +} + +void HighPressureGasTransport::getMixDiffCoeffsMass(double* const d) +{ + update_T(); + update_C(); + updateCorrectionFactors(); - double prefactor = 16.0 * m_temp - *m_thermo->meanMolecularWeight()/(25.0*m_thermo->pressure()); + // update the binary diffusion coefficients if necessary + if (!m_bindiff_ok) { + updateDiff_T(); + } - for (size_t i = 0; i < m_nsp; i++) { - for (size_t j = 0; j < m_nsp; j++) { - double c = prefactor/m_mw[j]; - d[ld*j + i] = c*molefracs[i]*(m_Lmatrix(i,j) - m_Lmatrix(i,i)); + double mmw = m_thermo->meanMolecularWeight(); + double p = m_thermo->pressure(); + + if (m_nsp == 1) { + d[0] = m_P_corr_ij(0,0)*m_bdiff(0,0) / p; + } else { + for (size_t i=0; imeanMolecularWeight(); - double MW_H = m_mw[0]; - double MW_L = m_mw[0]; + + // Mole-fraction-weighted mixture average of the low-pressure polarity correction + // factor double FP_mix_o = 0; + + // Mole-fraction-weighted mixture average of the low-pressure quantum correction + // factor double FQ_mix_o = 0; + + double MW_H = m_mw[0]; // Molecular weight of the heaviest species + double MW_L = m_mw[0]; // Molecular weight of the lightest species + double tKelvin = m_thermo->temperature(); - double Pvp_mix = m_thermo->satPressure(tKelvin); + double P_vap_mix = m_thermo->satPressure(tKelvin); size_t nsp = m_thermo->nSpecies(); vector molefracs(nsp); m_thermo->getMoleFractions(&molefracs[0]); - double x_H = molefracs[0]; + double x_H = molefracs[0]; // Holds the mole fraction of the heaviest species for (size_t i = 0; i < m_nsp; i++) { // Calculate pure-species critical constants and add their contribution // to the mole-fraction-weighted mixture averages: double Tc = Tcrit_i(i); double Tr = tKelvin/Tc; double Zc = Zcrit_i(i); - Tc_mix += Tc*molefracs[i]; - Pc_mix_n += molefracs[i]*Zc; //numerator - Pc_mix_d += molefracs[i]*Vcrit_i(i); //denominator - // Need to calculate ratio of heaviest to lightest species: + Tc_mix += Tc*molefracs[i]; // Equation 9-5.18 + + Pc_mix_n += molefracs[i]*Zc; // Numerator of 9-5.19 + // (Units of Vcrit_i are m^3/kmol, which are fine because they cancel out + // with the Cantera gas constant's units used later) + Pc_mix_d += molefracs[i]*Vcrit_i(i); // Denominator of 9-5.19 + + // Calculate ratio of heaviest to lightest species, used in + // Equation 9-5.23. if (m_mw[i] > MW_H) { MW_H = m_mw[i]; x_H = molefracs[i]; } else if (m_mw[i] < MW_L) { - MW_L = m_mw[i]; } - - // Calculate reduced dipole moment for polar correction term: - double mu_ri = 52.46*100000*m_dipole(i,i)*m_dipole(i,i) - *Pcrit_i(i)/(Tc*Tc); - if (mu_ri < 0.022) { - FP_mix_o += molefracs[i]; - } else if (mu_ri < 0.075) { - FP_mix_o += molefracs[i]*(1. + 30.55*pow(0.292 - Zc, 1.72)); - } else { FP_mix_o += molefracs[i]*(1. + 30.55*pow(0.292 - Zc, 1.72) - *fabs(0.96 + 0.1*(Tr - 0.7))); + MW_L = m_mw[i]; } + // Calculate pure-species reduced dipole moment for pure-species + // polar correction term. + // Equation 9-4.17 requires the pressure + // to be in units of bar, so we convert from Pa to bar. + // The dipole moment is stored in SI units, and it needs to be in + // units of Debye for the Lucas method. + double pascals_to_bar = 1e-5; + double SI_to_Debye = lightSpeed / 1e-21; // Conversion factor from C*m to Debye + double dipole_ii = m_dipole(i,i)*SI_to_Debye; + double mu_ri = 52.46*dipole_ii*dipole_ii*(Pcrit_i(i)*pascals_to_bar)/(Tc*Tc); + + // mole-fraction weighting of pure-species polar correction term + FP_mix_o += molefracs[i] * polarityCorrectionFactor(mu_ri, Tr, Zc); + // Calculate contribution to quantum correction term. - // SCD Note: This assumes the species of interest (He, H2, and D2) have - // been named in this specific way. They are perhaps the most obvious - // names, but it would of course be preferred to have a more general - // approach, here. + // Note: This assumes the species of interest (He, H2, and D2) have + // been named in this specific way. vector spnames = m_thermo->speciesNames(); if (spnames[i] == "He") { - FQ_mix_o += molefracs[i]*FQ_i(1.38,Tr,m_mw[i]); + FQ_mix_o += molefracs[i]*quantumCorrectionFactor(1.38, Tr, m_mw[i]); } else if (spnames[i] == "H2") { - FQ_mix_o += molefracs[i]*(FQ_i(0.76,Tr,m_mw[i])); + FQ_mix_o += molefracs[i]*(quantumCorrectionFactor(0.76, Tr, m_mw[i])); } else if (spnames[i] == "D2") { - FQ_mix_o += molefracs[i]*(FQ_i(0.52,Tr,m_mw[i])); + FQ_mix_o += molefracs[i]*(quantumCorrectionFactor(0.52, Tr, m_mw[i])); } else { FQ_mix_o += molefracs[i]; } @@ -323,167 +631,718 @@ double HighPressureGasTransport::viscosity() double Tr_mix = tKelvin/Tc_mix; double Pc_mix = GasConstant*Tc_mix*Pc_mix_n/Pc_mix_d; double Pr_mix = m_thermo->pressure()/Pc_mix; - double ratio = MW_H/MW_L; - double ksi = pow(GasConstant*Tc_mix*3.6277*pow(10.0,53.0)/(pow(MW_mix,3) - *pow(Pc_mix,4)),1.0/6.0); + // Compute the mixture value of the low-pressure quantum correction factor + // Equation 9-5.23. + double ratio = MW_H/MW_L; + double A = 1.0; if (ratio > 9 && x_H > 0.05 && x_H < 0.7) { - FQ_mix_o *= 1 - 0.01*pow(ratio,0.87); + A = 1 - 0.01*pow(ratio,0.87); } + FQ_mix_o *= A; + + m_FQ_mix_o = FQ_mix_o; + m_FP_mix_o = FP_mix_o; + m_Tc_mix = Tc_mix; + m_Tr_mix = Tr_mix; + m_Pc_mix = Pc_mix; + m_Pr_mix = Pr_mix; + m_MW_mix = MW_mix; + m_P_vap_mix = P_vap_mix; +} + +// Pure species critical properties - Tc, Pc, Vc, Zc: +double HighPressureGasTransport::Tcrit_i(size_t i) +{ + return m_Tcrit[i]; +} - // Calculate Z1m - double Z1m = (0.807*pow(Tr_mix,0.618) - 0.357*exp(-0.449*Tr_mix) - + 0.340*exp(-4.058*Tr_mix)+0.018)*FP_mix_o*FQ_mix_o; +double HighPressureGasTransport::Pcrit_i(size_t i) +{ + return m_Pcrit[i]; +} + +double HighPressureGasTransport::Vcrit_i(size_t i) +{ + return m_Vcrit[i]; +} - // Calculate Z2m: - double Z2m; - if (Tr_mix <= 1.0) { - if (Pr_mix < Pvp_mix/Pc_mix) { - double alpha = 3.262 + 14.98*pow(Pr_mix,5.508); - double beta = 1.390 + 5.746*Pr_mix; - Z2m = 0.600 + 0.760*pow(Pr_mix,alpha) + (0.6990*pow(Pr_mix,beta) - - 0.60)*(1- Tr_mix); +double HighPressureGasTransport::Zcrit_i(size_t i) +{ + return m_Zcrit[i]; +} + +double HighPressureGasTransport::lowPressureNondimensionalViscosity( + double Tr, double FP, double FQ) +{ + double first_term = 0.807*pow(Tr,0.618) - 0.357*exp(-0.449*Tr); + double second_term = 0.340*exp(-4.058*Tr) + 0.018; + return (first_term + second_term)*FP*FQ; +} + +double HighPressureGasTransport::highPressureNondimensionalViscosity( + double Tr, double Pr, double FP_low, double FQ_low, double P_vap, double P_crit) +{ + // This is η_0*ξ + double Z_1 = lowPressureNondimensionalViscosity(Tr, FP_low, FQ_low); + + double Z_2; + if (Tr <= 1.0) { + if (Pr < P_vap/P_crit) { + double alpha = 3.262 + 14.98*pow(Pr, 5.508); + double beta = 1.390 + 5.746*Pr; + Z_2 = 0.600 + 0.760*pow(Pr,alpha) + (0.6990*pow(Pr,beta) - 0.60) * (1-Tr); } else { - throw CanteraError("HighPressureGasTransport::viscosity", - "State is outside the limits of the Lucas model, Tr <= 1"); + throw CanteraError("HighPressureGasTransport::highPressureNondimensionalViscosity", + "State is outside the limits of the Lucas model, Pr ({}) >= " + "P_vap / P_crit ({}) when Tr ({}) <= 1.0", Pr, P_vap / P_crit, Tr); } - } else if ((Tr_mix > 1.0) && (Tr_mix < 40.0)) { - if ((Pr_mix > 0.0) && (Pr_mix <= 100.0)) { - double a_fac = 0.001245*exp(5.1726*pow(Tr_mix,-0.3286))/Tr_mix; - double b_fac = a_fac*(1.6553*Tr_mix - 1.2723); - double c_fac = 0.4489*exp(3.0578*pow(Tr_mix,-37.7332))/Tr_mix; - double d_fac = 1.7368*exp(2.2310*pow(Tr_mix,-7.6351))/Tr_mix; - double f_fac = 0.9425*exp(-0.1853*pow(Tr_mix,0.4489)); - - Z2m = Z1m*(1 + a_fac*pow(Pr_mix,1.3088)/(b_fac*pow(Pr_mix,f_fac) - + pow(1+c_fac*pow(Pr_mix,d_fac),-1))); + } else if (Tr > 1.0 && Tr < 40.0) { + if (Pr > 0.0 && Pr <= 100.0) { + // The following expressions are given in page 9.36 of Poling and + // correspond to parameters in equation 9-6.8. + double a_1 = 1.245e-3; + double a_2 = 5.1726; + double gamma = -0.3286; + double a = a_1*exp(a_2*pow(Tr,gamma))/Tr; + + double b_1 = 1.6553; + double b_2 = 1.2723; + double b = a*(b_1*Tr - b_2); + + double c_1 = 0.4489; + double c_2 = 3.0578; + double delta = -37.7332; + double c = c_1*exp(c_2*pow(Tr, delta))/Tr; + + double d_1 = 1.7368; + double d_2 = 2.2310; + double epsilon = -7.6351; + double d = d_1*exp(d_2*pow(Tr, epsilon))/Tr; + + double e = 1.3088; + + double f_1 = 0.9425; + double f_2 = -0.1853; + double zeta = 0.4489; + double f = f_1*exp(f_2*pow(Tr, zeta)); + + Z_2 = Z_1*(1 + (a*pow(Pr,e)) / (b*pow(Pr,f) + pow(1+c*pow(Pr,d),-1))); } else { - throw CanteraError("HighPressureGasTransport::viscosity", - "State is outside the limits of the Lucas model, 1.0 < Tr < 40"); + throw CanteraError("HighPressureGasTransport::highPressureNondimensionalViscosity", + "The value of Pr ({}) is outside the limits of the Lucas model, " + "valid values of Pr are: 0.0 < Pr <= 100", Pr); } } else { - throw CanteraError("HighPressureGasTransport::viscosity", - "State is outside the limits of the Lucas model, Tr > 40"); + throw CanteraError("HighPressureGasTransport::highPressureNondimensionalViscosity", + "The value of Tr is outside the limits of the Lucas model, " + "valid values of Tr are: 1.0 < Tr < 40", Tr); } - // Calculate Y: - double Y = Z2m/Z1m; + double Y = Z_2 / Z_1; + double FP = (1 + (FP_low - 1)*pow(Y,-3.0)) / FP_low; + double FQ = (1 + (FQ_low - 1)*(1.0/Y - 0.007*pow(log(Y),4.0))) / FQ_low; - // Return the viscosity: - return Z2m*(1 + (FP_mix_o - 1)*pow(Y,-3))*(1 + (FQ_mix_o - 1) - *(1/Y - 0.007*pow(log(Y),4)))/(ksi*FP_mix_o*FQ_mix_o); + // Return the non-dimensional viscosity η*ξ + return Z_2 * FP * FQ; } -// Pure species critical properties - Tc, Pc, Vc, Zc: -double HighPressureGasTransport::Tcrit_i(size_t i) +double HighPressureGasTransport::quantumCorrectionFactor(double Q, double Tr, + double MW) { - // Store current molefracs and set temp molefrac of species i to 1.0: - vector molefracs = store(i, m_thermo->nSpecies()); + return 1.22*pow(Q,0.15)*(1 + 0.00385*pow(pow(Tr - 12.0, 2.0), 1.0/MW) + *sign(Tr - 12.0)); +} - double tc = m_thermo->critTemperature(); - // Restore actual molefracs: - m_thermo->setMoleFractions(&molefracs[0]); - return tc; +double HighPressureGasTransport::polarityCorrectionFactor(double mu_r, double Tr, + double Z_crit) +{ + if (mu_r < 0.022) { + return 1; + } else if (mu_r < 0.075) { + return 1 + 30.55*pow(max(0.292 - Z_crit,0.0), 1.72); + } else { + return 1 + 30.55*pow(max(0.292 - Z_crit, 0.0), 1.72) + *fabs(0.96 + 0.1*(Tr - 0.7)); + } } -double HighPressureGasTransport::Pcrit_i(size_t i) + +// Chung Implementation +// -------------------- +void ChungHighPressureGasTransport::init(ThermoPhase* thermo, int mode, int log_level) { - // Store current molefracs and set temp molefrac of species i to 1.0: - vector molefracs = store(i, m_thermo->nSpecies()); + MixTransport::init(thermo, mode, log_level); + initializeCriticalProperties(); + initializePureFluidProperties(); + m_P_corr_ij.resize(m_nsp, m_nsp); +} - double pc = m_thermo->critPressure(); - // Restore actual molefracs: - m_thermo->setMoleFractions(&molefracs[0]); - return pc; +void ChungHighPressureGasTransport::getTransportData() +{ + // Call the base class's method to fill the properties + GasTransport::getTransportData(); + + // Contents of 'critical-properties.yaml', loaded later if needed + AnyMap critPropsDb; + std::unordered_map dbSpecies; + + // If a species has a zero acentric factor, check the critical-properties.yaml + // database to see if it has a value specified for the species. + for (size_t k = 0; k < m_thermo->nSpecies(); k++) { + if (m_w_ac[k] == 0.0) { + // Load 'crit-properties.yaml' file if not already loaded + if (critPropsDb.empty()) { + critPropsDb = AnyMap::fromYamlFile("critical-properties.yaml"); + dbSpecies = critPropsDb["species"].asMap("name"); + } + + // All names in critical-properties.yaml are upper case + auto ucName = boost::algorithm::to_upper_copy(m_thermo->species(k)->name); + if (dbSpecies.count(ucName)) { + auto& spec = *dbSpecies.at(ucName); + auto& critProps = spec["critical-parameters"].as(); + if (critProps.hasKey("acentric-factor")) { + m_w_ac[k] = critProps.convert("acentric-factor", "1"); + } + } + } + } } -double HighPressureGasTransport::Vcrit_i(size_t i) +void ChungHighPressureGasTransport::initializeCriticalProperties() { - // Store current molefracs and set temp molefrac of species i to 1.0: - vector molefracs = store(i, m_thermo->nSpecies()); + m_Tcrit.resize(m_nsp); + m_Pcrit.resize(m_nsp); + m_Vcrit.resize(m_nsp); + m_Zcrit.resize(m_nsp); + + std::vector molefracs(m_nsp); + m_thermo->getMoleFractions(&molefracs[0]); + + std::vector mf_temp(m_nsp, 0.0); + + for (size_t i = 0; i < m_nsp; ++i) { + mf_temp[i] = 1.0; + m_thermo->setMoleFractions(&mf_temp[0]); - double vc = m_thermo->critVolume(); - // Restore actual molefracs: + if (m_thermo->critTemperature() > 1e4) { + throw CanteraError("ChungHighPressureGasTransport::initializeCriticalProperties", + "Species '{}' must have critical properties defined or non-zero cubic parameters. " + "Check the species definition or the thermo data file.", + m_thermo->species(i)->name); + } + m_Tcrit[i] = m_thermo->critTemperature(); + m_Pcrit[i] = m_thermo->critPressure(); + m_Vcrit[i] = m_thermo->critVolume(); + m_Zcrit[i] = m_thermo->critCompressibility(); + + mf_temp[i] = 0.0; // Reset for the next iteration + } + + // Restore actual mole fractions m_thermo->setMoleFractions(&molefracs[0]); - return vc; } -double HighPressureGasTransport::Zcrit_i(size_t i) +void ChungHighPressureGasTransport::initializePureFluidProperties() { - // Store current molefracs and set temp molefrac of species i to 1.0: - vector molefracs = store(i, m_thermo->nSpecies()); + // First fill the species-specific values that will then be used in the + // combining rules for the Chung method. + m_sigma_i.resize(m_nsp); + m_epsilon_over_k_i.resize(m_nsp); + m_acentric_factor_i.resize(m_nsp); + m_MW_i.resize(m_nsp); + m_kappa_i.resize(m_nsp); + for (size_t i = 0; i < m_nsp; i++) { + // From equation 9-5.32. + double m3_per_kmol_to_cm3_per_mol = 1e3; // Convert from m^3/kmol to cm^3/mol + double Vc = Vcrit_i(i) * m3_per_kmol_to_cm3_per_mol; + m_sigma_i[i] = 0.809*pow(Vc, 1.0/3.0); - double zc = m_thermo->critCompressibility(); - // Restore actual molefracs: - m_thermo->setMoleFractions(&molefracs[0]); - return zc; + // From equation 9-5.34. + m_epsilon_over_k_i[i] = Tcrit_i(i)/1.2593; + + // NOTE: The association parameter is assumed to be zero for all species, but + // is left here for completeness or future revision. + m_kappa_i[i] = 0.0; + + // These values are available from the base class + m_acentric_factor_i[i] = m_w_ac[i]; + m_MW_i[i] = m_mw[i]; + } } -vector HighPressureGasTransport::store(size_t i, size_t nsp) +void ChungHighPressureGasTransport::updateCorrectionFactors() { + for (size_t i = 0; i < m_nsp; i++) { + for (size_t j = 0; j < m_nsp; j++) { + // Add an offset to avoid a condition where x_i and x_j both equal + // zero (this would lead to Pr_ij = Inf). + double x_i = std::max(Tiny, m_molefracs[i]); + double x_j = std::max(Tiny, m_molefracs[j]); + + // Weight mole fractions of i and j so that X_i + X_j = 1.0. + double sum_x_ij = x_i + x_j; + x_i = x_i/(sum_x_ij); + x_j = x_j/(sum_x_ij); + + // Calculate Tr and Pr based on mole-fraction-weighted critical constants. + double Tr_ij = m_temp/(x_i*Tcrit_i(i) + x_j*Tcrit_i(j)); + double Pr_ij = m_thermo->pressure()/(x_i*Pcrit_i(i) + x_j*Pcrit_i(j)); + + // Calculate the parameters for Takahashi correlation + double P_corr_ij; + P_corr_ij = takahashiCorrectionFactor(Pr_ij, Tr_ij); + + // If the reduced temperature is too low, the correction factor + // P_corr_ij will be < 0. + if (P_corr_ij<0) { + P_corr_ij = Tiny; + } + m_P_corr_ij(i, j) = P_corr_ij; + } + } +} + +void ChungHighPressureGasTransport::getBinaryDiffCoeffs(const size_t ld, double* const d) { - vector molefracs(nsp); - m_thermo->getMoleFractions(&molefracs[0]); - vector mf_temp(nsp, 0.0); - mf_temp[i] = 1; - m_thermo->setMoleFractions(&mf_temp[0]); - return molefracs; + update_C(); + update_T(); + updateCorrectionFactors(); + // If necessary, evaluate the binary diffusion coefficients from the polynomial + // fits + if (!m_bindiff_ok) { + updateDiff_T(); + } + if (ld < m_nsp) { + throw CanteraError("ChungHighPressureGasTransport::getBinaryDiffCoeffs", + "ld is too small"); + } + + double rp = 1.0/m_thermo->pressure(); + for (size_t i = 0; i < m_nsp; i++) { + for (size_t j = 0; j < m_nsp; j++) { + // Multiply the standard low-pressure binary diffusion coefficient + // (m_bdiff) by the Takahashi correction factor P_corr_ij. + d[ld*j + i] = m_P_corr_ij(i,j)*(rp * m_bdiff(i,j)); + } + } } -// Calculates quantum correction term for a species based on Tr and MW, used in -// viscosity calculation: -double HighPressureGasTransport::FQ_i(double Q, double Tr, double MW) +void ChungHighPressureGasTransport::getMixDiffCoeffs(double* const d) { - return 1.22*pow(Q,0.15)*(1 + 0.00385*pow(pow(Tr - 12.,2.),1./MW) - *fabs(Tr-12)/(Tr-12)); + update_T(); + update_C(); + updateCorrectionFactors(); + + // update the binary diffusion coefficients if necessary + if (!m_bindiff_ok) { + updateDiff_T(); + } + + double mmw = m_thermo->meanMolecularWeight(); + double p = m_thermo->pressure(); + if (m_nsp == 1) { + d[0] = m_P_corr_ij(0,0)*m_bdiff(0,0) / p; + } else { + for (size_t i = 0; i < m_nsp; i++) { + double sum2 = 0.0; + for (size_t j = 0; j < m_nsp; j++) { + if (j != i) { + sum2 += m_molefracs[j] / (m_P_corr_ij(i,j)*m_bdiff(j,i)); + } + } + if (sum2 <= 0.0) { + d[i] = m_P_corr_ij(i,i)*m_bdiff(i,i) / p; + } else { + d[i] = (mmw - m_molefracs[i] * m_mw[i])/(p * mmw * sum2); + } + } + } } -// Set value of parameter values for Takahashi correlation, by interpolating -// table of constants vs. Pr: -double HighPressureGasTransport::setPcorr(double Pr, double Tr) +void ChungHighPressureGasTransport::getMixDiffCoeffsMole(double* const d) { - const static double Pr_lookup[17] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.8, 1.0, - 1.2, 1.4, 1.6, 1.8, 2.0, 2.5, 3.0, 4.0, 5.0}; - const static double DP_Rt_lookup[17] = {1.01, 1.01, 1.01, 1.01, 1.01, 1.01, - 1.01, 1.02, 1.02, 1.02, 1.02, 1.03, 1.03, 1.04, 1.05, 1.06, 1.07}; - const static double A_ij_lookup[17] = {0.038042, 0.067433, 0.098317, - 0.137610, 0.175081, 0.216376, 0.314051, 0.385736, 0.514553, 0.599184, - 0.557725, 0.593007, 0.696001, 0.790770, 0.502100, 0.837452, 0.890390}; - const static double B_ij_lookup[17] = {1.52267, 2.16794, 2.42910, 2.77605, - 2.98256, 3.11384, 3.50264, 3.07773, 3.54744, 3.61216, 3.41882, 3.18415, - 3.37660, 3.27984, 3.39031, 3.23513, 3.13001}; - const static double C_ij_lookup[17] = {0., 0., 0., 0., 0., 0., 0., 0.141211, - 0.278407, 0.372683, 0.504894, 0.678469, 0.665702, 0., 0.602907, 0., 0.}; - const static double E_ij_lookup[17] = {1., 1., 1., 1., 1., 1., 1., 13.45454, - 14., 10.00900, 8.57519, 10.37483, 11.21674, 1., 6.19043, 1., 1.}; + update_T(); + update_C(); + updateCorrectionFactors(); - // Interpolate Pr vs. those used in Takahashi table: - int Pr_i = 0; - double frac = 0.; + // update the binary diffusion coefficients if necessary + if (!m_bindiff_ok) { + updateDiff_T(); + } - if (Pr < 0.1) { - frac = (Pr - Pr_lookup[0])/(Pr_lookup[1] - Pr_lookup[0]); + double p = m_thermo->pressure(); + if (m_nsp == 1) { + d[0] = m_P_corr_ij(0,0)*m_bdiff(0,0) / p; } else { - for (int j = 1; j < 17; j++) { - if (Pr_lookup[j] > Pr) { - frac = (Pr - Pr_lookup[j-1])/(Pr_lookup[j] - Pr_lookup[j-1]); - break; + for (size_t i = 0; i < m_nsp; i++) { + double sum2 = 0.0; + for (size_t j = 0; j < m_nsp; j++) { + if (j != i) { + sum2 += m_molefracs[j] / (m_P_corr_ij(i,j)*m_bdiff(j,i)); + } + } + if (sum2 <= 0.0) { + d[i] = m_P_corr_ij(i,i)*m_bdiff(i,i) / p; + } else { + d[i] = (1 - m_molefracs[i]) / (p * sum2); } - Pr_i++; } } - // If Pr is greater than the greatest value used by Takahashi (5.0), use the - // final table value. Should eventually add in an extrapolation: - if (Pr_i == 17) { - frac = 1.0; +} + +void ChungHighPressureGasTransport::getMixDiffCoeffsMass(double* const d) +{ + update_T(); + update_C(); + updateCorrectionFactors(); + + // update the binary diffusion coefficients if necessary + if (!m_bindiff_ok) { + updateDiff_T(); + } + + double mmw = m_thermo->meanMolecularWeight(); + double p = m_thermo->pressure(); + + if (m_nsp == 1) { + d[0] = m_P_corr_ij(0,0)*m_bdiff(0,0) / p; + } else { + for (size_t i=0; itemperature(); + double T_star = tKelvin / m_epsilon_over_k_mix; + + // The density is required for high-pressure gases. + // The Chung method requires density to be units of mol/cm^3 + // Use the mixture molecular weight (units of kg/kmol). + // 1 kmol/m^3 = 1e-3 mol/cm^3 + double kg_per_m3_to_mol_per_cm3 = (1.0 / m_MW_mix)*1e-3; + double density = m_thermo->density()*kg_per_m3_to_mol_per_cm3; + + // The value of Cv is already a mole-weighted average of the pure species values + double Cv_mix = m_thermo->cv_mole(); // Units are J/kmol/K + + // This result is in units of W/m/K + double thermal_conductivity = highPressureThermalConductivity( + tKelvin, T_star, m_MW_mix, density, Cv_mix, m_Vc_mix, + m_Tc_mix, m_sigma_mix, m_acentric_factor_mix, + m_mu_r_mix, m_kappa_mix); + + // Return the thermal conductivity in W/m/K + return thermal_conductivity; +} + +double ChungHighPressureGasTransport::highPressureThermalConductivity( + double T, double T_star, double MW, double rho, double Cv, double Vc, + double Tc, double sigma, double acentric_factor, double mu_r, + double kappa) +{ + // Calculate the low-pressure viscosity using the Chung method (units of Pa*s) + double viscosity = lowPressureViscosity(T, T_star, MW, acentric_factor, mu_r, + sigma, kappa); + + + double M_prime = MW / 1000.0; // Convert kg/kmol to kg/mol + + // Definition of tabulated coefficients for the Chung method, as shown in + // Table 10-3 on page 10.23. + static const vector a = {2.44166, -5.0924e-1, 6.6107, 1.4543e1, 7.9274e-1, + -5.8634, 9.1089e1}; + static const vector b = {7.4824e-1, -1.5094, 5.6207, -8.9139, 8.2019e-1, + 1.2801e1, 1.2811e2}; + static const vector c = {-9.1858e-1, -4.9991e1, 6.4760e1, -5.6379, + -6.9369e-1, 9.5893, -5.4217e1}; + static const vector d = {1.2172e2, 6.9983e1, 2.7039e1, 7.4344e1, 6.3173, + 6.5529e1, 5.2381e2}; + + // This is slightly pedantic, but this is done to have the naming convention in the + // equations used match the variable names in the code. This is equation 10-5.9. + double B_1 = a[0] + b[0]*acentric_factor + c[0]*pow(mu_r, 4.0) + d[0]*kappa; + double B_2 = a[1] + b[1]*acentric_factor + c[1]*pow(mu_r, 4.0) + d[1]*kappa; + double B_3 = a[2] + b[2]*acentric_factor + c[2]*pow(mu_r, 4.0) + d[2]*kappa; + double B_4 = a[3] + b[3]*acentric_factor + c[3]*pow(mu_r, 4.0) + d[3]*kappa; + double B_5 = a[4] + b[4]*acentric_factor + c[4]*pow(mu_r, 4.0) + d[4]*kappa; + double B_6 = a[5] + b[5]*acentric_factor + c[5]*pow(mu_r, 4.0) + d[5]*kappa; + double B_7 = a[6] + b[6]*acentric_factor + c[6]*pow(mu_r, 4.0) + d[6]*kappa; + + double y = rho*Vc/6.0; // Equation 10-5.6 (with rho = 1/V) + + double G_1 = (1.0 - 0.5*y)/(pow(1.0-y, 3.0)); // Equation 10-5.7 + + // Equation 10-5.8 + double G_2 = (B_1*((1.0-exp(-B_4*y)) / y) + B_2*G_1*exp(B_5*y) + B_3*G_1) + / (B_1*B_4 + B_2 + B_3); + + double q = 3.586e-3*sqrt(Tc/M_prime) / pow(Vc, 2.0/3.0); // Below equation 10-5.5 + + double Tr = T/Tc; // Reduced temperature + // The following 4 equations are defined below Equation 10-3.14 + double alpha = (Cv / GasConstant) - 3.0/2.0; // GasConstant(R) has units (J/kmol/K) + double beta = 0.7862 - 0.7109*acentric_factor + + 1.3168*acentric_factor*acentric_factor; + double Z = 2.0 + 10.5*Tr*Tr; + double psi = 1.0 + alpha*((0.215 + 0.28288*alpha - 1.061*beta + 0.26665*Z) + / (0.6366 + beta*Z + 1.061*alpha*beta)); + + // Equation 10-5.5 + double lambda = (31.2*viscosity*psi/M_prime)*(1.0/G_2 + B_6*y) + + q*B_7*y*y*sqrt(Tr)*G_2; + + // Units are W/m/K + return lambda; +} + +double ChungHighPressureGasTransport::viscosity() +{ + computeMixtureParameters(); + + // Compute T_star using equation 9-5.26, using the mixture parameters + double tKelvin = m_thermo->temperature(); + double T_star = tKelvin / m_epsilon_over_k_mix; + + // The density is required for high-pressure gases. + // The Chung method requires density to be units of mol/cm^3 + // Use the mixture molecular weight (units of kg/kmol) here. + // 1 kmol/m^3 = 1e-3 mol/cm^3 + double kg_per_m3_to_mol_per_cm3 = (1.0 / m_MW_mix)*1e-3; + double molar_density = m_thermo->density()*kg_per_m3_to_mol_per_cm3; + + // This result is in units of micropoise + double viscosity = highPressureViscosity(T_star, m_MW_mix, molar_density, + m_Vc_mix, m_Tc_mix, + m_acentric_factor_mix, + m_mu_r_mix, m_kappa_mix); + + double micropoise_to_pascals_second = 1e-7; + return viscosity*micropoise_to_pascals_second; +} + +void ChungHighPressureGasTransport::computeMixtureParameters() +{ + // Here we use the combining rules defined on page 9.25. + // We have ASSUMED that the binary interaction parameters are unity for all species + // as was done in the Chung method. + // + // The sigma & kappa relations can be fully computed in the loop. The other ones + // require a final division by the final mixture values, and so the quantities in + // the loop are only the numerators of the equations that are referenced in the + // comments. After the loop, the final mixture values are computed and stored. + + // Zero out the mixture values of the parameters + m_sigma_mix = 0.0; + m_epsilon_over_k_mix = 0.0; + m_MW_mix = 0.0; + m_acentric_factor_mix = 0.0; + m_mu_mix = 0.0; + m_kappa_mix = 0.0; + m_Tc_mix = 0.0; + m_Vc_mix = 0.0; + m_mu_r_mix = 0.0; + + vector molefracs(m_nsp); + m_thermo->getMoleFractions(&molefracs[0]); + for (size_t i = 0; i < m_nsp; i++) { + for (size_t j = 0; j a = {6.324, 1.210e-3, 5.283, 6.623, 19.745, -1.900, + 24.275, 0.7972, -0.2382, 0.06863}; + static const vector b = {50.412, -1.154e-3, 254.209, 38.096, 7.630, + -12.537, 3.450, 1.117, 0.06770, 0.3479}; + static const vector c = {-51.680, -6.257e-3, -168.48, -8.464, -14.354, + 4.958, -11.291, 0.01235, -0.8163, 0.5926}; + static const vector d ={1189.0, 0.03728, 3898.0, 31.42, 31.53, -18.15, + 69.35, -4.117, 4.025, -0.727}; + + // This is slightly pedantic, but this is done to have the naming convention in the + // equations used match the variable names in the code. + double E_1 = a[0] + b[0]*acentric_factor + c[0]*pow(mu_r, 4.0) + d[0]*kappa; + double E_2 = a[1] + b[1]*acentric_factor + c[1]*pow(mu_r, 4.0) + d[1]*kappa; + double E_3 = a[2] + b[2]*acentric_factor + c[2]*pow(mu_r, 4.0) + d[2]*kappa; + double E_4 = a[3] + b[3]*acentric_factor + c[3]*pow(mu_r, 4.0) + d[3]*kappa; + double E_5 = a[4] + b[4]*acentric_factor + c[4]*pow(mu_r, 4.0) + d[4]*kappa; + double E_6 = a[5] + b[5]*acentric_factor + c[5]*pow(mu_r, 4.0) + d[5]*kappa; + double E_7 = a[6] + b[6]*acentric_factor + c[6]*pow(mu_r, 4.0) + d[6]*kappa; + double E_8 = a[7] + b[7]*acentric_factor + c[7]*pow(mu_r, 4.0) + d[7]*kappa; + double E_9 = a[8] + b[8]*acentric_factor + c[8]*pow(mu_r, 4.0) + d[8]*kappa; + double E_10 = a[9] + b[9]*acentric_factor + c[9]*pow(mu_r, 4.0) + d[9]*kappa; + + double y = rho*Vc/6.0; // Equation 9-6.20 + + double G_1 = (1.0 - 0.5*y)/(pow(1.0-y, 3.0)); // Equation 9-6.21 + + // Equation 9-6.22 + double G_2 = (E_1*((1.0-exp(-E_4*y)) / y) + E_2*G_1*exp(E_5*y) + E_3*G_1) + / (E_1*E_4 + E_2 + E_3); + + // Equation 9-6.23 + double eta_2 = E_7*y*y*G_2*exp(E_8 + E_9/T_star + E_10/(T_star*T_star)); + + double omega = neufeldCollisionIntegral(T_star); // Equation 9-4.3 + + // Molecular shapes and polarities factor, Equation 9-4.11 + double Fc = 1 -0.2756*acentric_factor + 0.059035*pow(mu_r, 4.0) + kappa; + + // Renamed eta_star and eta_star_star from the Poling description to eta_1 and + // eta_2 for naming simplicity. + // Equation 9-6.19 + double eta_1 = (sqrt(T_star)/omega) * (Fc*(1.0/G_2 + E_6*y)) + eta_2; + + double eta = eta_1 * 36.344 * sqrt(MW*Tc) / pow(Vc, 2.0/3.0); // Equation 9-6.18 + + return eta; +} + +// Pure species critical properties - Tc, Pc, Vc, Zc: +double ChungHighPressureGasTransport::Tcrit_i(size_t i) +{ + return m_Tcrit[i]; +} + +double ChungHighPressureGasTransport::Pcrit_i(size_t i) +{ + return m_Pcrit[i]; +} + +double ChungHighPressureGasTransport::Vcrit_i(size_t i) +{ + return m_Vcrit[i]; +} + +double ChungHighPressureGasTransport::Zcrit_i(size_t i) +{ + return m_Zcrit[i]; +} + + } diff --git a/src/transport/MMCollisionInt.cpp b/src/transport/MMCollisionInt.cpp index 8387c5e261..2ad54e1767 100644 --- a/src/transport/MMCollisionInt.cpp +++ b/src/transport/MMCollisionInt.cpp @@ -19,7 +19,7 @@ double MMCollisionInt::delta[8] = {0.0, 0.25, 0.50, 0.75, 1.0, 1.5, 2.0, 2.5 }; -double quadInterp(double x0, double* x, double* y) +double MMCollisionInt::quadInterp(double x0, double* x, double* y) { double dx21 = x[1] - x[0]; double dx32 = x[2] - x[1]; @@ -213,16 +213,16 @@ double MMCollisionInt::cstar_table[39*8] = { 0.94444, 0.94444,0.94444,0.94444,0.94444,0.94444,0.94444,0.94444 }; -void MMCollisionInt::init(double tsmin, double tsmax) +void MMCollisionInt::init(double tstar_min, double tstar_max) { m_nmin = -1; m_nmax = -1; for (int n = 0; n < 37; n++) { - if (tsmin > tstar[n+1]) { + if (tstar_min > tstar[n+1]) { m_nmin = n; } - if (tsmax > tstar[n+1]) { + if (tstar_max > tstar[n+1]) { m_nmax = n+1; } } @@ -270,7 +270,7 @@ double MMCollisionInt::fitDelta(int table, int ntstar, int degree, double* c) default: return 0.0; } - w[0] = -1.0; + w[0] = -1.0; // to activate weight values of unity return polyfit(8, degree, delta, begin, w.data(), c); } diff --git a/src/transport/MMCollisionInt.h b/src/transport/MMCollisionInt.h index eaf8380266..d1565e433f 100644 --- a/src/transport/MMCollisionInt.h +++ b/src/transport/MMCollisionInt.h @@ -15,9 +15,44 @@ namespace Cantera { //! Calculation of Collision integrals -/*! - * This class provides functions that interpolate the tabulated collision - * integrals in Monchick and Mason @cite monchick1961. +/** + * This class provides functions that interpolate the tabulated collision integrals in + * Monchick and Mason @cite monchick1961. + * + * The collision integrals computed by Monchick and Mason use the Stockmayer potential, + * which models a polar molecule as a spherical potential with a point dipole at the + * center). Equation 16 of Monchick and Mason @cite monchick1961 gives the potential + * as: + * + * @f[ + * \phi(r) = 4 \epsilon_0 \left[ \left(\frac{\sigma_0}{r}\right)^{12} - \left(\frac{\sigma_0}{r}\right)^6 + \delta \left(\frac{\sigma_0}{r}\right)^3 \right] + * @f] + * + * Where @f$ \epsilon_0 @f$ is the depth of the potential well, @f$ \sigma_0 @f$ is the + * distance at which the potential between the two molecules is zero, @f$ \delta @f$ is + * defined as: + * + * @f[ + * \delta = \frac{1}{4} (\mu^*)^2 \zeta \left( \theta_1, \theta_2, \phi \right) + * @f] + * + * @f$ \mu^* @f$ is the reduced dipole moment. @f$ \theta_1 @f$ , @f$ \theta_2 @f$ , + * and @f$ \phi @f$ are angles related to trajectories of colliding molecules. In the + * work of Monchick and Mason, these details are not what is presented in the tables. + * Instead, the tables are presented as being functions of the reduced temperature, + * @f$ T^* @f$, and the @f$ \delta @f$ parameter. The reduced dipole moment, + * @f$ \mu^* @f$ is defined as: + * + * @f[ + * \mu^* = \frac{\mu}{\sqrt{\epsilon_0 \sigma_0^3}} + * @f] + * + * Where @f$ \mu @f$ is the dipole moment of the molecule and the other parameters + * have been defined earlier. This work considers only the collisions of like + * molecules, so only a single value is needed. + * + * The tabulated data comes from the averaged collision integrals in tables + * V through VIII of Monchick and Mason @cite monchick1961. * * @ingroup tranprops */ @@ -46,6 +81,7 @@ class MMCollisionInt private: double fitDelta(int table, int ntstar, int degree, double* c); + double quadInterp(double x0, double* x, double* y); vector> m_o22poly; vector> m_apoly; @@ -55,25 +91,30 @@ class MMCollisionInt static double delta[8]; static double tstar22[37]; - //! Table of omega22 values from MM + //! Table of omega22 values static double omega22_table[37*8]; - //! table of tstar values + //! T* values (reduced temperature) static double tstar[39]; - //! astar table from MM + //! astar table static double astar_table[39*8]; - //! bstar table from MM + //! bstar table static double bstar_table[39*8]; - //! cstar table from MM + //! cstar table static double cstar_table[39*8]; //! Log temp vector m_logTemp; + //! Index of the tstar array that encompasses the minimum temperature + //! fitting range value of tsmin. int m_nmin; + + //! Index of the tstar array that encompasses the maximum temperature + //! fitting range value of tsmax. int m_nmax; }; diff --git a/src/transport/TransportFactory.cpp b/src/transport/TransportFactory.cpp index 1320f659c6..7763a5da0c 100644 --- a/src/transport/TransportFactory.cpp +++ b/src/transport/TransportFactory.cpp @@ -46,6 +46,7 @@ TransportFactory::TransportFactory() addDeprecatedAlias("water", "Water"); reg("high-pressure", []() { return new HighPressureGasTransport(); }); addDeprecatedAlias("high-pressure", "HighP"); + reg("high-pressure-Chung", []() { return new ChungHighPressureGasTransport(); }); m_CK_mode["CK_Mix"] = m_CK_mode["mixture-averaged-CK"] = true; m_CK_mode["CK_Multi"] = m_CK_mode["multicomponent-CK"] = true; } diff --git a/test/data/HighPressureChungTest.csv b/test/data/HighPressureChungTest.csv new file mode 100644 index 0000000000..7cc1325c22 --- /dev/null +++ b/test/data/HighPressureChungTest.csv @@ -0,0 +1,100 @@ +1.013250e+05, 1.317510e-05, 3.304087e-02, 4.409307e-05, 1.607365e-05 +7.063621e+05, 1.320969e-05, 3.320920e-02, 6.324986e-06, 2.305705e-06 +1.311399e+06, 1.326275e-05, 3.344689e-02, 3.406843e-06, 1.241927e-06 +1.916436e+06, 1.333452e-05, 3.375287e-02, 2.331270e-06, 8.498390e-07 +2.521473e+06, 1.342518e-05, 3.412586e-02, 1.771873e-06, 6.459169e-07 +3.126511e+06, 1.353486e-05, 3.456439e-02, 1.428983e-06, 5.209202e-07 +3.731548e+06, 1.366365e-05, 3.506673e-02, 1.197286e-06, 4.364576e-07 +4.336585e+06, 1.381157e-05, 3.563097e-02, 1.030242e-06, 3.755634e-07 +4.941622e+06, 1.397858e-05, 3.625495e-02, 9.041021e-07, 3.295805e-07 +5.546659e+06, 1.416459e-05, 3.693632e-02, 8.054814e-07, 2.936294e-07 +6.151696e+06, 1.436943e-05, 3.767249e-02, 7.262600e-07, 2.647501e-07 +6.756733e+06, 1.459286e-05, 3.846072e-02, 6.612264e-07, 2.410429e-07 +7.361770e+06, 1.483458e-05, 3.929806e-02, 6.068826e-07, 2.212324e-07 +7.966808e+06, 1.509423e-05, 4.018141e-02, 5.607931e-07, 2.044310e-07 +8.571845e+06, 1.537138e-05, 4.110758e-02, 5.212100e-07, 1.900014e-07 +9.176882e+06, 1.566553e-05, 4.207325e-02, 4.868463e-07, 1.774745e-07 +9.781919e+06, 1.597614e-05, 4.307505e-02, 4.567336e-07, 1.664972e-07 +1.038696e+07, 1.630262e-05, 4.410959e-02, 4.301290e-07, 1.567988e-07 +1.099199e+07, 1.664433e-05, 4.517351e-02, 4.064532e-07, 1.481681e-07 +1.159703e+07, 1.700060e-05, 4.626348e-02, 3.852478e-07, 1.404379e-07 +1.220207e+07, 1.737074e-05, 4.737628e-02, 3.661454e-07, 1.334743e-07 +1.280710e+07, 1.775403e-05, 4.850881e-02, 3.488478e-07, 1.271687e-07 +1.341214e+07, 1.814977e-05, 4.965812e-02, 3.331109e-07, 1.214319e-07 +1.401718e+07, 1.855722e-05, 5.082147e-02, 3.187325e-07, 1.161905e-07 +1.462222e+07, 1.897568e-05, 5.199632e-02, 3.055440e-07, 1.113827e-07 +1.522725e+07, 1.940447e-05, 5.318034e-02, 2.934036e-07, 1.069571e-07 +1.583229e+07, 1.984292e-05, 5.437147e-02, 2.821911e-07, 1.028697e-07 +1.643733e+07, 2.029037e-05, 5.556785e-02, 2.718040e-07, 9.908317e-08 +1.704236e+07, 2.074624e-05, 5.676791e-02, 2.621544e-07, 9.556552e-08 +1.764740e+07, 2.120996e-05, 5.797029e-02, 2.531665e-07, 9.228908e-08 +1.825244e+07, 2.168098e-05, 5.917386e-02, 2.447745e-07, 8.922985e-08 +1.885748e+07, 2.215882e-05, 6.037773e-02, 2.369209e-07, 8.636694e-08 +1.946251e+07, 2.264304e-05, 6.158119e-02, 2.295557e-07, 8.368202e-08 +2.006755e+07, 2.313322e-05, 6.278372e-02, 2.226346e-07, 8.115901e-08 +2.067259e+07, 2.362899e-05, 6.398497e-02, 2.161186e-07, 7.878368e-08 +2.127762e+07, 2.413003e-05, 6.518474e-02, 2.099732e-07, 7.654343e-08 +2.188266e+07, 2.463604e-05, 6.638296e-02, 2.041676e-07, 7.442707e-08 +2.248770e+07, 2.514674e-05, 6.757967e-02, 1.986744e-07, 7.242459e-08 +2.309274e+07, 2.566192e-05, 6.877500e-02, 1.934691e-07, 7.052705e-08 +2.369777e+07, 2.618138e-05, 6.996916e-02, 1.885296e-07, 6.872639e-08 +2.430281e+07, 2.670493e-05, 7.116242e-02, 1.838360e-07, 6.701540e-08 +2.490785e+07, 2.723242e-05, 7.235510e-02, 1.793704e-07, 6.538752e-08 +2.551288e+07, 2.776373e-05, 7.354758e-02, 1.751166e-07, 6.383686e-08 +2.611792e+07, 2.829875e-05, 7.474022e-02, 1.710600e-07, 6.235804e-08 +2.672296e+07, 2.883738e-05, 7.593343e-02, 1.671870e-07, 6.094619e-08 +2.732800e+07, 2.937954e-05, 7.712762e-02, 1.634855e-07, 5.959685e-08 +2.793303e+07, 2.992518e-05, 7.832321e-02, 1.599444e-07, 5.830597e-08 +2.853807e+07, 3.047425e-05, 7.952061e-02, 1.565534e-07, 5.706982e-08 +2.914311e+07, 3.102669e-05, 8.072021e-02, 1.533032e-07, 5.588500e-08 +2.974814e+07, 3.158249e-05, 8.192241e-02, 1.501852e-07, 5.474837e-08 +3.035318e+07, 3.214162e-05, 8.312759e-02, 1.471915e-07, 5.365706e-08 +3.095822e+07, 3.270407e-05, 8.433610e-02, 1.443149e-07, 5.260840e-08 +3.156326e+07, 3.326983e-05, 8.554829e-02, 1.415485e-07, 5.159995e-08 +3.216829e+07, 3.383889e-05, 8.676447e-02, 1.388862e-07, 5.062943e-08 +3.277333e+07, 3.441127e-05, 8.798495e-02, 1.363222e-07, 4.969475e-08 +3.337837e+07, 3.498696e-05, 8.921002e-02, 1.338511e-07, 4.879395e-08 +3.398340e+07, 3.556599e-05, 9.043993e-02, 1.314680e-07, 4.792523e-08 +3.458844e+07, 3.614836e-05, 9.167492e-02, 1.291683e-07, 4.708690e-08 +3.519348e+07, 3.673410e-05, 9.291521e-02, 1.269477e-07, 4.627739e-08 +3.579852e+07, 3.732323e-05, 9.416101e-02, 1.248021e-07, 4.549525e-08 +3.640355e+07, 3.791577e-05, 9.541249e-02, 1.227279e-07, 4.473911e-08 +3.700859e+07, 3.851175e-05, 9.666983e-02, 1.207215e-07, 4.400769e-08 +3.761363e+07, 3.911120e-05, 9.793317e-02, 1.187796e-07, 4.329980e-08 +3.821866e+07, 3.971416e-05, 9.920263e-02, 1.168992e-07, 4.261432e-08 +3.882370e+07, 4.032065e-05, 1.004783e-01, 1.150774e-07, 4.195021e-08 +3.942874e+07, 4.093071e-05, 1.017604e-01, 1.133115e-07, 4.130648e-08 +4.003378e+07, 4.154439e-05, 1.030489e-01, 1.115990e-07, 4.068221e-08 +4.063881e+07, 4.216172e-05, 1.043439e-01, 1.099375e-07, 4.007653e-08 +4.124385e+07, 4.278274e-05, 1.056454e-01, 1.083248e-07, 3.948861e-08 +4.184889e+07, 4.340750e-05, 1.069536e-01, 1.067587e-07, 3.891770e-08 +4.245392e+07, 4.403604e-05, 1.082684e-01, 1.052372e-07, 3.836306e-08 +4.305896e+07, 4.466842e-05, 1.095900e-01, 1.037584e-07, 3.782401e-08 +4.366400e+07, 4.530467e-05, 1.109182e-01, 1.023207e-07, 3.729989e-08 +4.426903e+07, 4.594485e-05, 1.122531e-01, 1.009223e-07, 3.679010e-08 +4.487407e+07, 4.658902e-05, 1.135948e-01, 9.956152e-08, 3.629406e-08 +4.547911e+07, 4.723722e-05, 1.149431e-01, 9.823699e-08, 3.581122e-08 +4.608415e+07, 4.788951e-05, 1.162982e-01, 9.694724e-08, 3.534106e-08 +4.668918e+07, 4.854596e-05, 1.176599e-01, 9.569092e-08, 3.488308e-08 +4.729422e+07, 4.920661e-05, 1.190283e-01, 9.446674e-08, 3.443682e-08 +4.789926e+07, 4.987153e-05, 1.204034e-01, 9.327349e-08, 3.400183e-08 +4.850429e+07, 5.054078e-05, 1.217850e-01, 9.211000e-08, 3.357770e-08 +4.910933e+07, 5.121442e-05, 1.231732e-01, 9.097519e-08, 3.316401e-08 +4.971437e+07, 5.189252e-05, 1.245680e-01, 8.986800e-08, 3.276040e-08 +5.031941e+07, 5.257515e-05, 1.259692e-01, 8.878743e-08, 3.236649e-08 +5.092444e+07, 5.326237e-05, 1.273768e-01, 8.773254e-08, 3.198194e-08 +5.152948e+07, 5.395426e-05, 1.287908e-01, 8.670242e-08, 3.160642e-08 +5.213452e+07, 5.465088e-05, 1.302111e-01, 8.569621e-08, 3.123962e-08 +5.273955e+07, 5.535231e-05, 1.316377e-01, 8.471309e-08, 3.088123e-08 +5.334459e+07, 5.605863e-05, 1.330705e-01, 8.375227e-08, 3.053098e-08 +5.394963e+07, 5.676990e-05, 1.345095e-01, 8.281300e-08, 3.018858e-08 +5.455467e+07, 5.748621e-05, 1.359545e-01, 8.189457e-08, 2.985377e-08 +5.515970e+07, 5.820764e-05, 1.374056e-01, 8.099628e-08, 2.952631e-08 +5.576474e+07, 5.893426e-05, 1.388626e-01, 8.011749e-08, 2.920595e-08 +5.636978e+07, 5.966616e-05, 1.403255e-01, 7.925756e-08, 2.889248e-08 +5.697481e+07, 6.040342e-05, 1.417942e-01, 7.841589e-08, 2.858566e-08 +5.757985e+07, 6.114613e-05, 1.432686e-01, 7.759191e-08, 2.828528e-08 +5.818489e+07, 6.189438e-05, 1.447488e-01, 7.678507e-08, 2.799116e-08 +5.878993e+07, 6.264824e-05, 1.462346e-01, 7.599484e-08, 2.770309e-08 +5.939496e+07, 6.340781e-05, 1.477259e-01, 7.522070e-08, 2.742088e-08 +6.000000e+07, 6.417319e-05, 1.492226e-01, 7.446218e-08, 2.714437e-08 diff --git a/test/data/HighPressureTest.csv b/test/data/HighPressureTest.csv new file mode 100644 index 0000000000..afbf33cdbd --- /dev/null +++ b/test/data/HighPressureTest.csv @@ -0,0 +1,100 @@ +1.013250e+05, 1.442875e-05, 3.739638e-02, 4.409307e-05, 1.607365e-05 +7.063621e+05, 1.449119e-05, 3.838306e-02, 6.324986e-06, 2.305705e-06 +1.311399e+06, 1.457793e-05, 3.918746e-02, 3.406843e-06, 1.241927e-06 +1.916436e+06, 1.468156e-05, 3.994860e-02, 2.331270e-06, 8.498390e-07 +2.521473e+06, 1.479968e-05, 4.069512e-02, 1.771873e-06, 6.459169e-07 +3.126511e+06, 1.493108e-05, 4.143940e-02, 1.428983e-06, 5.209202e-07 +3.731548e+06, 1.507498e-05, 4.218841e-02, 1.197286e-06, 4.364576e-07 +4.336585e+06, 1.523085e-05, 4.294667e-02, 1.030242e-06, 3.755634e-07 +4.941622e+06, 1.539823e-05, 4.371740e-02, 9.041021e-07, 3.295805e-07 +5.546659e+06, 1.557676e-05, 4.450308e-02, 8.054814e-07, 2.936294e-07 +6.151696e+06, 1.576608e-05, 4.530568e-02, 7.262600e-07, 2.647501e-07 +6.756733e+06, 1.596587e-05, 4.612680e-02, 6.612264e-07, 2.410429e-07 +7.361770e+06, 1.617578e-05, 4.696780e-02, 6.068826e-07, 2.212324e-07 +7.966808e+06, 1.639550e-05, 4.782979e-02, 5.607931e-07, 2.044310e-07 +8.571845e+06, 1.662470e-05, 4.871374e-02, 5.212100e-07, 1.900014e-07 +9.176882e+06, 1.686305e-05, 4.962041e-02, 4.868463e-07, 1.774745e-07 +9.781919e+06, 1.711020e-05, 5.055043e-02, 4.567336e-07, 1.664972e-07 +1.038696e+07, 1.736582e-05, 5.152217e-02, 4.301290e-07, 1.567988e-07 +1.099199e+07, 1.762957e-05, 5.252126e-02, 4.064532e-07, 1.481681e-07 +1.159703e+07, 1.790111e-05, 5.354049e-02, 3.852478e-07, 1.404379e-07 +1.220207e+07, 1.818009e-05, 5.458024e-02, 3.661454e-07, 1.334743e-07 +1.280710e+07, 1.846616e-05, 5.564071e-02, 3.488478e-07, 1.271687e-07 +1.341214e+07, 1.875899e-05, 5.672195e-02, 3.331109e-07, 1.214319e-07 +1.401718e+07, 1.905823e-05, 5.782386e-02, 3.187325e-07, 1.161905e-07 +1.462222e+07, 1.936355e-05, 5.894626e-02, 3.055440e-07, 1.113827e-07 +1.522725e+07, 1.967461e-05, 6.008881e-02, 2.934036e-07, 1.069571e-07 +1.583229e+07, 1.999109e-05, 6.125110e-02, 2.821911e-07, 1.028697e-07 +1.643733e+07, 2.031265e-05, 6.243265e-02, 2.718040e-07, 9.908317e-08 +1.704236e+07, 2.063900e-05, 6.363289e-02, 2.621544e-07, 9.556552e-08 +1.764740e+07, 2.096981e-05, 6.485119e-02, 2.531665e-07, 9.228908e-08 +1.825244e+07, 2.130478e-05, 6.608689e-02, 2.447745e-07, 8.922985e-08 +1.885748e+07, 2.164362e-05, 6.733928e-02, 2.369209e-07, 8.636694e-08 +1.946251e+07, 2.198604e-05, 6.860764e-02, 2.295557e-07, 8.368202e-08 +2.006755e+07, 2.233177e-05, 6.989122e-02, 2.226346e-07, 8.115901e-08 +2.067259e+07, 2.268054e-05, 7.118927e-02, 2.161186e-07, 7.878368e-08 +2.127762e+07, 2.303209e-05, 7.250103e-02, 2.099732e-07, 7.654343e-08 +2.188266e+07, 2.338616e-05, 7.382577e-02, 2.041676e-07, 7.442707e-08 +2.248770e+07, 2.374252e-05, 7.516273e-02, 1.986744e-07, 7.242459e-08 +2.309274e+07, 2.410093e-05, 7.651121e-02, 1.934691e-07, 7.052705e-08 +2.369777e+07, 2.446117e-05, 7.787050e-02, 1.885296e-07, 6.872639e-08 +2.430281e+07, 2.482303e-05, 7.923991e-02, 1.838360e-07, 6.701540e-08 +2.490785e+07, 2.518630e-05, 8.061880e-02, 1.793704e-07, 6.538752e-08 +2.551288e+07, 2.555078e-05, 8.200652e-02, 1.751166e-07, 6.383686e-08 +2.611792e+07, 2.591630e-05, 8.340248e-02, 1.710600e-07, 6.235804e-08 +2.672296e+07, 2.628267e-05, 8.480609e-02, 1.671870e-07, 6.094619e-08 +2.732800e+07, 2.664971e-05, 8.621680e-02, 1.634855e-07, 5.959685e-08 +2.793303e+07, 2.701728e-05, 8.763408e-02, 1.599444e-07, 5.830597e-08 +2.853807e+07, 2.738522e-05, 8.905744e-02, 1.565534e-07, 5.706982e-08 +2.914311e+07, 2.775337e-05, 9.048640e-02, 1.533032e-07, 5.588500e-08 +2.974814e+07, 2.812161e-05, 9.192052e-02, 1.501852e-07, 5.474837e-08 +3.035318e+07, 2.848980e-05, 9.335938e-02, 1.471915e-07, 5.365706e-08 +3.095822e+07, 2.885782e-05, 9.480256e-02, 1.443149e-07, 5.260840e-08 +3.156326e+07, 2.922556e-05, 9.624970e-02, 1.415485e-07, 5.159995e-08 +3.216829e+07, 2.959289e-05, 9.770043e-02, 1.388862e-07, 5.062943e-08 +3.277333e+07, 2.995973e-05, 9.915443e-02, 1.363222e-07, 4.969475e-08 +3.337837e+07, 3.032596e-05, 1.006114e-01, 1.338511e-07, 4.879395e-08 +3.398340e+07, 3.069151e-05, 1.020710e-01, 1.314680e-07, 4.792523e-08 +3.458844e+07, 3.105629e-05, 1.035329e-01, 1.291683e-07, 4.708690e-08 +3.519348e+07, 3.142021e-05, 1.049970e-01, 1.269477e-07, 4.627739e-08 +3.579852e+07, 3.178320e-05, 1.064629e-01, 1.248021e-07, 4.549525e-08 +3.640355e+07, 3.214519e-05, 1.079305e-01, 1.227279e-07, 4.473911e-08 +3.700859e+07, 3.250612e-05, 1.093994e-01, 1.207215e-07, 4.400769e-08 +3.761363e+07, 3.286592e-05, 1.108695e-01, 1.187796e-07, 4.329980e-08 +3.821866e+07, 3.322454e-05, 1.123407e-01, 1.168992e-07, 4.261432e-08 +3.882370e+07, 3.358193e-05, 1.138126e-01, 1.150774e-07, 4.195021e-08 +3.942874e+07, 3.393803e-05, 1.152860e-01, 1.133115e-07, 4.130648e-08 +4.003378e+07, 3.429281e-05, 1.167624e-01, 1.115990e-07, 4.068221e-08 +4.063881e+07, 3.464623e-05, 1.182393e-01, 1.099375e-07, 4.007653e-08 +4.124385e+07, 3.499824e-05, 1.197165e-01, 1.083248e-07, 3.948861e-08 +4.184889e+07, 3.534881e-05, 1.211938e-01, 1.067587e-07, 3.891770e-08 +4.245392e+07, 3.569790e-05, 1.226712e-01, 1.052372e-07, 3.836306e-08 +4.305896e+07, 3.604551e-05, 1.241485e-01, 1.037584e-07, 3.782401e-08 +4.366400e+07, 3.639158e-05, 1.256256e-01, 1.023207e-07, 3.729989e-08 +4.426903e+07, 3.673611e-05, 1.271024e-01, 1.009223e-07, 3.679010e-08 +4.487407e+07, 3.707907e-05, 1.285788e-01, 9.956152e-08, 3.629406e-08 +4.547911e+07, 3.742045e-05, 1.300546e-01, 9.823699e-08, 3.581122e-08 +4.608415e+07, 3.776022e-05, 1.315299e-01, 9.694724e-08, 3.534106e-08 +4.668918e+07, 3.809837e-05, 1.330044e-01, 9.569092e-08, 3.488308e-08 +4.729422e+07, 3.843490e-05, 1.344782e-01, 9.446674e-08, 3.443682e-08 +4.789926e+07, 3.876979e-05, 1.359511e-01, 9.327349e-08, 3.400183e-08 +4.850429e+07, 3.910302e-05, 1.374231e-01, 9.211000e-08, 3.357770e-08 +4.910933e+07, 3.943461e-05, 1.388941e-01, 9.097519e-08, 3.316401e-08 +4.971437e+07, 3.976453e-05, 1.403641e-01, 8.986800e-08, 3.276040e-08 +5.031941e+07, 4.009278e-05, 1.418329e-01, 8.878743e-08, 3.236649e-08 +5.092444e+07, 4.041937e-05, 1.433005e-01, 8.773254e-08, 3.198194e-08 +5.152948e+07, 4.074429e-05, 1.447668e-01, 8.670242e-08, 3.160642e-08 +5.213452e+07, 4.106754e-05, 1.462319e-01, 8.569621e-08, 3.123962e-08 +5.273955e+07, 4.138912e-05, 1.476956e-01, 8.471309e-08, 3.088123e-08 +5.334459e+07, 4.170903e-05, 1.491579e-01, 8.375227e-08, 3.053098e-08 +5.394963e+07, 4.202727e-05, 1.506188e-01, 8.281300e-08, 3.018858e-08 +5.455467e+07, 4.234386e-05, 1.520782e-01, 8.189457e-08, 2.985377e-08 +5.515970e+07, 4.265878e-05, 1.535360e-01, 8.099628e-08, 2.952631e-08 +5.576474e+07, 4.297206e-05, 1.549923e-01, 8.011749e-08, 2.920595e-08 +5.636978e+07, 4.328368e-05, 1.564470e-01, 7.925756e-08, 2.889248e-08 +5.697481e+07, 4.359367e-05, 1.579001e-01, 7.841589e-08, 2.858566e-08 +5.757985e+07, 4.390203e-05, 1.593515e-01, 7.759191e-08, 2.828528e-08 +5.818489e+07, 4.420875e-05, 1.608011e-01, 7.678507e-08, 2.799116e-08 +5.878993e+07, 4.451387e-05, 1.622491e-01, 7.599484e-08, 2.770309e-08 +5.939496e+07, 4.481737e-05, 1.636953e-01, 7.522070e-08, 2.742088e-08 +6.000000e+07, 4.511927e-05, 1.651397e-01, 7.446218e-08, 2.714437e-08 diff --git a/test/data/methane_co2.yaml b/test/data/methane_co2.yaml new file mode 100644 index 0000000000..0c493a965f --- /dev/null +++ b/test/data/methane_co2.yaml @@ -0,0 +1,61 @@ +units: {length: cm, quantity: mol, activation-energy: cal/mol} + +phases: +- name: methane_co2 + species: [CH4, CO2] + thermo: Peng-Robinson + kinetics: gas + transport: mixture-averaged + reactions: none + state: + T: 300 + P: 1 atm +species: +- name: CH4 + composition: {C: 1, H: 4} + thermo: + model: NASA7 + temperature-ranges: [200.0, 1000.0, 3500.0] + data: + - [5.14987613, -0.0136709788, 4.91800599e-05, -4.84743026e-08, 1.66693956e-11, + -1.02466476e+04, -4.64130376] + - [0.074851495, 0.0133909467, -5.73285809e-06, 1.22292535e-09, -1.0181523e-13, + -9468.34459, 18.437318] + note: L8/88 + transport: + model: gas + geometry: nonlinear + well-depth: 141.4 + diameter: 3.746 + polarizability: 2.6 + rotational-relaxation: 13.0 + critical-parameters: + critical-temperature: 190.7 + critical-pressure: 4.63e+06 + critical-molar-volume: 0.0989 + critical-compressibility: 0.288 + acentric-factor: 0.011 +- name: CO2 + composition: {C: 1, O: 2} + thermo: + model: NASA7 + temperature-ranges: [200.0, 1000.0, 3500.0] + data: + - [2.35677352, 8.98459677e-03, -7.12356269e-06, 2.45919022e-09, -1.43699548e-13, + -4.83719697e+04, 9.90105222] + - [3.85746029, 4.41437026e-03, -2.21481404e-06, 5.23490188e-10, -4.72084164e-14, + -4.8759166e+04, 2.27163806] + note: L7/88 + transport: + model: gas + geometry: linear + well-depth: 244.0 + diameter: 3.763 + polarizability: 2.65 + rotational-relaxation: 2.1 + critical-parameters: + critical-temperature: 304.2 + critical-pressure: 7.39e+06 + critical-molar-volume: 0.0948 + critical-compressibility: 0.275 + acentric-factor: 0.228 diff --git a/test/data/methane_co2_noCritProp.yaml b/test/data/methane_co2_noCritProp.yaml new file mode 100644 index 0000000000..ae7a8b4722 --- /dev/null +++ b/test/data/methane_co2_noCritProp.yaml @@ -0,0 +1,60 @@ +units: {length: cm, quantity: mol, activation-energy: cal/mol} + +phases: +- name: methane_co2 + species: [CH4, CO2] + thermo: Peng-Robinson + kinetics: gas + transport: mixture-averaged + reactions: none + state: + T: 300 + P: 1 atm +species: +- name: CH4 + composition: {C: 1, H: 4} + thermo: + model: NASA7 + temperature-ranges: [200.0, 1000.0, 3500.0] + data: + - [5.14987613, -0.0136709788, 4.91800599e-05, -4.84743026e-08, 1.66693956e-11, + -1.02466476e+04, -4.64130376] + - [0.074851495, 0.0133909467, -5.73285809e-06, 1.22292535e-09, -1.0181523e-13, + -9468.34459, 18.437318] + note: L8/88 + transport: + model: gas + geometry: nonlinear + well-depth: 141.4 + diameter: 3.746 + polarizability: 2.6 + rotational-relaxation: 13.0 + critical-parameters: + critical-temperature: 190.7 + critical-pressure: 4.63e+06 + critical-molar-volume: 0.0989 + critical-compressibility: 0.288 + acentric-factor: 0.011 +- name: CO2 + composition: {C: 1, O: 2} + thermo: + model: NASA7 + temperature-ranges: [200.0, 1000.0, 3500.0] + data: + - [2.35677352, 8.98459677e-03, -7.12356269e-06, 2.45919022e-09, -1.43699548e-13, + -4.83719697e+04, 9.90105222] + - [3.85746029, 4.41437026e-03, -2.21481404e-06, 5.23490188e-10, -4.72084164e-14, + -4.8759166e+04, 2.27163806] + note: L7/88 + transport: + model: gas + geometry: linear + well-depth: 244.0 + diameter: 3.763 + polarizability: 2.65 + rotational-relaxation: 2.1 + equation-of-state: + model: Peng-Robinson + a: 0 + b: 0 + acentric-factor: 0.228 diff --git a/test/data/transport_models_test.xml b/test/data/transport_models_test.xml index 6306739b60..895f64baea 100644 --- a/test/data/transport_models_test.xml +++ b/test/data/transport_models_test.xml @@ -48,17 +48,17 @@ - H C - H H2 CH3 CH4 + H C O + CO2 CH4 1200.0 2666.4473684210525 - H:0.002, H2:0.988, CH3:0.0002, CH4:0.01 + CO2: 0.988, CH4: 0.012 - + diff --git a/test/data/transport_models_test.yaml b/test/data/transport_models_test.yaml index c5f18f37dd..e7679001ee 100644 --- a/test/data/transport_models_test.yaml +++ b/test/data/transport_models_test.yaml @@ -41,14 +41,13 @@ phases: state: {T: 1200.0 K, P: 2666.4473684210525 Pa, X: {H: 2.0e-03, H2: 0.988, CH3: 2.0e-04, CH4: 0.01}} - name: HighP - elements: [H, C] + elements: [H, C, O] species: - - gri30.yaml/species: [H, H2, CH3, CH4] - thermo: ideal-gas + - methane_co2.yaml/species: [CO2, CH4] + thermo: Redlich-Kwong transport: high-pressure skip-undeclared-third-bodies: true kinetics: gas reactions: - - gri30.yaml/reactions: declared-species - state: {T: 1200.0 K, P: 2666.4473684210525 Pa, X: {H: 2.0e-03, H2: 0.988, CH3: 2.0e-04, - CH4: 0.01}} + - gri30.yaml/reactions: none + state: {T: 1200.0 K, P: 2666.4473684210525 Pa, X: {CO2: 0.988, CH4: 0.012}} diff --git a/test/python/conftest.py b/test/python/conftest.py index 31b804f261..85c07175a1 100644 --- a/test/python/conftest.py +++ b/test/python/conftest.py @@ -18,7 +18,7 @@ def pytest_addoption(parser): "--save-reference", action="store", default=None, help="Save the reference output files for specific tests. " "Options: diffusion, counterflow_premixed, counterflow_premixed_nonideal, " - "combustor, wall" + "combustor, wall, high_pressure_transport, high_pressure_chung_transport" ) def pytest_configure(config): diff --git a/test/python/test_transport.py b/test/python/test_transport.py index 4e753a59b7..4d2579778a 100644 --- a/test/python/test_transport.py +++ b/test/python/test_transport.py @@ -4,7 +4,9 @@ from pytest import approx import cantera as ct - +from .utilities import ( + compareProfiles +) class TestTransport: @@ -176,7 +178,7 @@ def test_add_species_multi(self, cantera_data_path): assert gas1.thermal_conductivity == approx(gas2.thermal_conductivity) assert gas1.multi_diff_coeffs == approx(gas2.multi_diff_coeffs) - def test_species_viscosities(self, phase): + def test_species_visosities(self, phase): for species_name in phase.species_names: # check that species viscosity matches overall for single-species # state @@ -659,3 +661,119 @@ def test_serialization(self, gas): assert data['quadrupole-polarizability'] == approx(3.602) assert 'dispersion-coefficient' not in gas.species('CO2').transport.input_data + + +class TestHighPressureGasTransport(): + """ + Note: to re-create the reference file: + (1) Set PYTHONPATH to build/python. + (2) Go into test/python directory and run: + pytest --save-reference=high_pressure_transport test_transport.py::TestHighPressureGasTransport::test_high_pressure_transport + pytest --save-reference=high_pressure_chung_transport test_transport.py::TestHighPressureGasTransport::test_high_pressure_chung_transport + (3) Compare the reference files created in the current working directory with + the ones in test/data and replace them if needed. + """ + + def test_failure_for_species_with_no_properties(self): + """ + All species must have critical properties defined to use the high pressure + transport model. This test uses a YAML file with a specified value of the + a and b parameters for the Peng-Robinson equation of state, which should + be parsed by the thermo model and will set the critical properties to + non-physical values. These non-physical values should trigger an error + in the high-pressure transport model. + """ + gas = ct.Solution('methane_co2_noCritProp.yaml') + + with pytest.raises(ct.CanteraError, match="must have critical properties defined"): + gas.transport_model = 'high-pressure-Chung' + + with pytest.raises(ct.CanteraError, match="must have critical properties defined"): + gas.transport_model = 'high-pressure' + + def test_high_pressure_transport(self, request, test_data_path): + """ + This test compares the viscosity and thermal conductivities of a mixture of + CH4 and CO2 over a range of pressures using the high-pressure transport + model and compares the results to a reference file. This is a regression test. + """ + referenceFile = "HighPressureTest.csv" + + phasedef = """ + phases: + - name: methane_co2 + species: + - gri30.yaml/species: [CH4, CO2] + thermo: Peng-Robinson + transport: mixture-averaged + state: {T: 300, P: 1 atm} + """ + gas = ct.Solution(yaml=phasedef) + gas.transport_model = 'high-pressure' + + pressures = np.linspace(101325, 6e7, 100) + # Collect viscosities and thermal conductivities + viscosities = [] + thermal_conductivities = [] + diffusion_coefficients = [] + for pressure in pressures: + gas.TPX = 350, pressure, 'CH4:0.755, CO2:0.245' + viscosities.append(gas.viscosity) + thermal_conductivities.append(gas.thermal_conductivity) + diffusion_coefficients.append(gas.mix_diff_coeffs) + + data = np.empty((len(viscosities), 3+ len(diffusion_coefficients[0]))) + data[:,0] = pressures + data[:,1] = viscosities + data[:,2] = thermal_conductivities + for i in range(len(diffusion_coefficients[0])): + data[:,3+i] = [d[i] for d in diffusion_coefficients] + + saveReference = request.config.getoption("--save-reference") + if saveReference == 'high_pressure_transport': + np.savetxt(referenceFile, data, '%11.6e', ', ') + else: + bad = compareProfiles(test_data_path / referenceFile, data, + rtol=1e-2, atol=1e-8, xtol=1e-2) + assert not bad, bad + + def test_high_pressure_chung_transport(self, request, test_data_path): + referenceFile = "HighPressureChungTest.csv" + + phasedef = """ + phases: + - name: methane_co2 + species: + - gri30.yaml/species: [CH4, CO2] + thermo: Peng-Robinson + transport: mixture-averaged + state: {T: 300, P: 1 atm} + """ + gas = ct.Solution(yaml=phasedef) + gas.transport_model = 'high-pressure-Chung' + + pressures = np.linspace(101325, 6e7, 100) + # Collect viscosities and thermal conductivities + viscosities = [] + thermal_conductivities = [] + diffusion_coefficients = [] + for pressure in pressures: + gas.TPX = 350, pressure, 'CH4:0.755, CO2:0.245' + viscosities.append(gas.viscosity) + thermal_conductivities.append(gas.thermal_conductivity) + diffusion_coefficients.append(gas.mix_diff_coeffs) + + data = np.empty((len(viscosities), 3+gas.n_species)) + data[:,0] = pressures + data[:,1] = viscosities + data[:,2] = thermal_conductivities + for i in range(len(diffusion_coefficients[0])): + data[:,3+i] = [d[i] for d in diffusion_coefficients] + + saveReference = request.config.getoption("--save-reference") + if saveReference == 'high_pressure_chung_transport': + np.savetxt(referenceFile, data, '%11.6e', ', ') + else: + bad = compareProfiles(test_data_path / referenceFile, data, + rtol=1e-2, atol=1e-8, xtol=1e-2) + assert not bad, bad