https://gitlab.opengeosys.org/ogs/ogs.git
Raw File
Tip revision: ff1060fea27c610459b434f039b23e4ad6d4b1c1 authored by Thomas Nagel on 01 February 2021, 13:55:04 UTC
[PL/RM] Phase compressibility saturation cut-off.
Tip revision: ff1060f
ReactionCaOH2.cpp
/**
 * \file
 * \copyright
 * Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
 *            Distributed under a Modified BSD License.
 *              See accompanying file LICENSE.txt or
 *              http://www.opengeosys.org/project/license
 */

#include "ReactionCaOH2.h"

#include <cassert>

#include "Adsorption.h"
#include "BaseLib/Error.h"
#include "MaterialLib/PhysicalConstant.h"

namespace Adsorption
{
const double ReactionCaOH2::_reaction_enthalpy = -1.12e+05;
const double ReactionCaOH2::_reaction_entropy = -143.5;
const double ReactionCaOH2::_M_carrier =
    MaterialLib::PhysicalConstant::MolarMass::N2;
const double ReactionCaOH2::_M_react =
    MaterialLib::PhysicalConstant::MolarMass::Water;

const double ReactionCaOH2::_tol_l = 1e-4;
const double ReactionCaOH2::_tol_u = 1.0 - 1e-4;
const double ReactionCaOH2::_tol_rho = 0.1;

const double ReactionCaOH2::rho_low = 1656.0;
const double ReactionCaOH2::rho_up = 2200.0;

double ReactionCaOH2::getEnthalpy(const double /*p_Ads*/,
                                  const double /*T_Ads*/,
                                  const double /*M_Ads*/) const
{
    return -_reaction_enthalpy / _M_react;
}

double ReactionCaOH2::getReactionRate(const double /*p_Ads*/,
                                      const double /*T_Ads*/,
                                      const double /*M_Ads*/,
                                      const double /*loading*/) const
{
    OGS_FATAL("get_reaction_rate do not call directly");
}

double ReactionCaOH2::getReactionRate(double const solid_density)
{
    _rho_s = solid_density;
    calculateQR();
    return _qR;
}

void ReactionCaOH2::updateParam(double T_solid,
                                double p_gas,
                                double x_react,
                                double rho_s_initial)
{
    _T_s = T_solid;
    _p_gas = p_gas / 1e5;  // convert Pa to bar
    _x_react = x_react;
    _rho_s = rho_s_initial;
}

void ReactionCaOH2::calculateQR()
{
    // Convert mass fraction into mole fraction
    const double mol_frac_react =
        AdsorptionReaction::getMolarFraction(_x_react, _M_react, _M_carrier);

    _p_r_g = std::max(mol_frac_react * _p_gas, 1.0e-3);  // avoid illdefined log
    setChemicalEquilibrium();
    const double dXdt = CaHydration();
    _qR = (rho_up - rho_low) * dXdt;
}

// determine equilibrium temperature and pressure according to van't Hoff
void ReactionCaOH2::setChemicalEquilibrium()
{
    const double R = MaterialLib::PhysicalConstant::IdealGasConstant;

    _X_D = (_rho_s - rho_up - _tol_rho) / (rho_low - rho_up - 2.0 * _tol_rho);
    _X_D = (_X_D < 0.5)
               ? std::max(_tol_l, _X_D)
               : std::min(_X_D, _tol_u);  // constrain to interval [tol_l;tol_u]

    _X_H = 1.0 - _X_D;

    // calculate equilibrium
    // using the p_eq to calculate the T_eq - Clausius-Clapeyron
    _T_eq = (_reaction_enthalpy / R) /
            ((_reaction_entropy / R) + std::log(_p_r_g));  // unit of p in bar
    // Alternative: Use T_s as T_eq and calculate p_eq - for Schaube kinetics
    _p_eq = std::exp((_reaction_enthalpy / R) / _T_s - (_reaction_entropy / R));
}

double ReactionCaOH2::CaHydration()
{
    const double R = MaterialLib::PhysicalConstant::IdealGasConstant;
    double dXdt;
    // step 3, calculate dX/dt
#ifdef SIMPLE_KINETICS
    if (T_s < T_eq)  // hydration - simple model
#else
    if (_p_r_g > _p_eq)  // hydration - Schaube model
#endif
    {
        // X_H = max(tol_l,X_H); //lower tolerance to avoid oscillations at
        // onset of hydration reaction. Set here so that no residual reaction
        // rate occurs at end of hydration.
#ifdef SIMPLE_KINETICS  // this is from P. Schmidt
        dXdt = -1.0 * (1.0 - X_H) * (T_s - T_eq) / T_eq * 0.2 *
               conversion_rate::x_react;
#else  // this is from Schaube
        if (_X_H == _tol_u || _rho_s == rho_up)
        {
            dXdt = 0.0;
        }
        else if ((_T_eq - _T_s) >= 50.0)
        {
            dXdt = 13945.0 * exp(-89486.0 / R / _T_s) *
                   std::pow(_p_r_g / _p_eq - 1.0, 0.83) * 3.0 *
                   (_X_D)*std::pow(-1.0 * log(_X_D), 0.666);
        }
        else
        {
            dXdt = 1.0004e-34 * exp(5.3332e4 / _T_s) * std::pow(_p_r_g, 6.0) *
                   (_X_D);
        }
#endif
    }
    else  // dehydration
    {
        // X_D = max(tol_l,X_D); //lower tolerance to avoid oscillations at
        // onset of dehydration reaction. Set here so that no residual reaction
        // rate occurs at end of dehydration.
#ifdef SIMPLE_KINETICS  // this is from P. Schmidt
        dXdt = -1.0 * (1.0 - X_D) * (T_s - T_eq) / T_eq * 0.05;
#else
        if (_X_D == _tol_u || _rho_s == rho_low)
        {
            dXdt = 0.0;
        }
        else if (_X_D < 0.2)
        {
            dXdt = -1.9425e12 * exp(-1.8788e5 / R / _T_s) *
                   std::pow(1.0 - _p_r_g / _p_eq, 3.0) * (_X_H);
        }
        else
        {
            dXdt = -8.9588e9 * exp(-1.6262e5 / R / _T_s) *
                   std::pow(1.0 - _p_r_g / _p_eq, 3.0) * 2.0 *
                   std::pow(_X_H, 0.5);
        }
#endif
    }
    return dXdt;
}

}  // namespace Adsorption
back to top