2012-04-19 10:21:08 -05:00
|
|
|
/*
|
|
|
|
Copyright 2012 SINTEF ICT, Applied Mathematics.
|
|
|
|
|
|
|
|
This file is part of the Open Porous Media project (OPM).
|
|
|
|
|
|
|
|
OPM is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
OPM is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2014-11-18 18:44:54 -06:00
|
|
|
#include <config.h>
|
|
|
|
|
2012-04-19 10:21:08 -05:00
|
|
|
#include <opm/polymer/PolymerProperties.hpp>
|
|
|
|
#include <cmath>
|
|
|
|
#include <vector>
|
|
|
|
#include <opm/core/utility/linearInterpolation.hpp>
|
2014-04-26 04:09:43 -05:00
|
|
|
#include <opm/core/utility/ErrorMacros.hpp>
|
|
|
|
#include <opm/core/utility/Exceptions.hpp>
|
2012-04-19 10:21:08 -05:00
|
|
|
|
|
|
|
namespace Opm
|
|
|
|
{
|
|
|
|
double PolymerProperties::cMax() const
|
|
|
|
{
|
|
|
|
return c_max_;
|
|
|
|
}
|
|
|
|
|
|
|
|
double PolymerProperties::mixParam() const
|
|
|
|
{
|
|
|
|
return mix_param_;
|
|
|
|
}
|
|
|
|
|
|
|
|
double PolymerProperties::rockDensity() const
|
|
|
|
{
|
|
|
|
return rock_density_;
|
|
|
|
}
|
|
|
|
|
|
|
|
double PolymerProperties::deadPoreVol() const
|
|
|
|
{
|
|
|
|
return dead_pore_vol_;
|
|
|
|
}
|
|
|
|
|
|
|
|
double PolymerProperties::resFactor() const
|
|
|
|
{
|
|
|
|
return res_factor_;
|
|
|
|
}
|
|
|
|
|
|
|
|
double PolymerProperties::cMaxAds() const
|
|
|
|
{
|
|
|
|
return c_max_ads_;
|
|
|
|
}
|
|
|
|
|
|
|
|
int PolymerProperties::adsIndex() const
|
|
|
|
{
|
|
|
|
return ads_index_;
|
|
|
|
}
|
2014-03-18 00:25:52 -05:00
|
|
|
|
2014-03-18 20:23:20 -05:00
|
|
|
const std::vector<double>&
|
2014-03-18 00:25:52 -05:00
|
|
|
PolymerProperties::shearWaterVelocity() const
|
|
|
|
{
|
|
|
|
return water_vel_vals_;
|
|
|
|
}
|
|
|
|
|
2014-03-21 01:34:46 -05:00
|
|
|
double
|
|
|
|
PolymerProperties::shearVrf(const double velocity) const
|
2014-03-18 00:25:52 -05:00
|
|
|
{
|
2014-03-21 01:34:46 -05:00
|
|
|
return Opm::linearInterpolation(water_vel_vals_, shear_vrf_vals_, velocity);
|
2014-03-18 00:25:52 -05:00
|
|
|
}
|
2012-04-19 10:21:08 -05:00
|
|
|
|
2014-03-26 03:02:39 -05:00
|
|
|
double
|
|
|
|
PolymerProperties::shearVrfWithDer(const double velocity, double& der) const
|
|
|
|
{
|
|
|
|
der = Opm::linearInterpolationDerivative(water_vel_vals_, shear_vrf_vals_, velocity);
|
|
|
|
return Opm::linearInterpolation(water_vel_vals_, shear_vrf_vals_, velocity);
|
|
|
|
}
|
|
|
|
|
2012-04-19 10:21:08 -05:00
|
|
|
double PolymerProperties::viscMult(double c) const
|
|
|
|
{
|
|
|
|
return Opm::linearInterpolation(c_vals_visc_, visc_mult_vals_, c);
|
|
|
|
}
|
|
|
|
|
|
|
|
double PolymerProperties::viscMultWithDer(double c, double* der) const
|
|
|
|
{
|
|
|
|
*der = Opm::linearInterpolationDerivative(c_vals_visc_, visc_mult_vals_, c);
|
|
|
|
return Opm::linearInterpolation(c_vals_visc_, visc_mult_vals_, c);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PolymerProperties::simpleAdsorption(double c, double& c_ads) const
|
|
|
|
{
|
|
|
|
double dummy;
|
|
|
|
simpleAdsorptionBoth(c, c_ads, dummy, false);
|
|
|
|
}
|
|
|
|
|
2012-04-23 03:07:51 -05:00
|
|
|
void PolymerProperties::simpleAdsorptionWithDer(double c, double& c_ads,
|
2012-04-19 10:21:08 -05:00
|
|
|
double& dc_ads_dc) const
|
|
|
|
{
|
|
|
|
simpleAdsorptionBoth(c, c_ads, dc_ads_dc, true);
|
|
|
|
}
|
|
|
|
|
2012-04-23 03:07:51 -05:00
|
|
|
void PolymerProperties::simpleAdsorptionBoth(double c, double& c_ads,
|
2012-04-19 10:21:08 -05:00
|
|
|
double& dc_ads_dc, bool if_with_der) const
|
|
|
|
{
|
|
|
|
c_ads = Opm::linearInterpolation(c_vals_ads_, ads_vals_, c);;
|
|
|
|
if (if_with_der) {
|
|
|
|
dc_ads_dc = Opm::linearInterpolationDerivative(c_vals_ads_, ads_vals_, c);
|
|
|
|
} else {
|
|
|
|
dc_ads_dc = 0.;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PolymerProperties::adsorption(double c, double cmax, double& c_ads) const
|
|
|
|
{
|
|
|
|
double dummy;
|
|
|
|
adsorptionBoth(c, cmax, c_ads, dummy, false);
|
|
|
|
}
|
|
|
|
|
2012-04-23 03:07:51 -05:00
|
|
|
void PolymerProperties::adsorptionWithDer(double c, double cmax,
|
2012-04-19 10:21:08 -05:00
|
|
|
double& c_ads, double& dc_ads_dc) const
|
|
|
|
{
|
|
|
|
adsorptionBoth(c, cmax, c_ads, dc_ads_dc, true);
|
|
|
|
}
|
|
|
|
|
2012-04-23 03:07:51 -05:00
|
|
|
void PolymerProperties::adsorptionBoth(double c, double cmax,
|
|
|
|
double& c_ads, double& dc_ads_dc,
|
2012-04-19 10:21:08 -05:00
|
|
|
bool if_with_der) const
|
|
|
|
{
|
|
|
|
if (ads_index_ == Desorption) {
|
|
|
|
simpleAdsorptionBoth(c, c_ads, dc_ads_dc, if_with_der);
|
|
|
|
} else if (ads_index_ == NoDesorption) {
|
2014-12-07 19:52:57 -06:00
|
|
|
simpleAdsorptionBoth(std::max(c, cmax), c_ads, dc_ads_dc, if_with_der);
|
2012-04-19 10:21:08 -05:00
|
|
|
} else {
|
2013-09-03 08:00:29 -05:00
|
|
|
OPM_THROW(std::runtime_error, "Invalid Adsoption index");
|
2012-04-19 10:21:08 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-26 02:25:46 -05:00
|
|
|
void PolymerProperties::effectiveVisc(const double c, const double* visc, double& mu_w_eff) const {
|
|
|
|
effectiveInvVisc(c, visc, mu_w_eff);
|
|
|
|
mu_w_eff = 1./mu_w_eff;
|
2012-04-19 10:21:08 -05:00
|
|
|
}
|
|
|
|
|
2012-04-26 02:25:46 -05:00
|
|
|
void PolymerProperties::effectiveViscWithDer(const double c, const double* visc, double& mu_w_eff, double dmu_w_eff_dc) const {
|
|
|
|
effectiveInvViscWithDer(c, visc, mu_w_eff, dmu_w_eff_dc);
|
|
|
|
mu_w_eff = 1./mu_w_eff;
|
|
|
|
dmu_w_eff_dc = -dmu_w_eff_dc*mu_w_eff*mu_w_eff;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PolymerProperties::effectiveInvVisc(const double c, const double* visc, double& inv_mu_w_eff) const
|
2012-04-19 10:21:08 -05:00
|
|
|
{
|
2012-04-26 02:25:46 -05:00
|
|
|
double dummy;
|
|
|
|
effectiveInvViscBoth(c, visc, inv_mu_w_eff, dummy, false);
|
2012-04-19 10:21:08 -05:00
|
|
|
}
|
|
|
|
|
2012-04-26 02:25:46 -05:00
|
|
|
void PolymerProperties::effectiveInvViscWithDer(const double c, const double* visc,
|
|
|
|
double& inv_mu_w_eff,
|
|
|
|
double& dinv_mu_w_eff_dc) const {
|
|
|
|
effectiveInvViscBoth(c, visc, inv_mu_w_eff, dinv_mu_w_eff_dc, true);
|
2012-04-19 10:21:08 -05:00
|
|
|
}
|
|
|
|
|
2012-04-26 02:25:46 -05:00
|
|
|
void PolymerProperties::effectiveInvViscBoth(const double c, const double* visc,
|
|
|
|
double& inv_mu_w_eff,
|
|
|
|
double& dinv_mu_w_eff_dc,
|
|
|
|
bool if_with_der) const {
|
2012-04-19 10:21:08 -05:00
|
|
|
double cbar = c/c_max_;
|
|
|
|
double mu_w = visc[0];
|
|
|
|
double mu_m;
|
|
|
|
double omega = mix_param_;
|
2012-04-23 03:07:51 -05:00
|
|
|
double dmu_m_dc;
|
2012-04-19 10:21:08 -05:00
|
|
|
if (if_with_der) {
|
2012-04-23 03:07:51 -05:00
|
|
|
mu_m = viscMultWithDer(c, &dmu_m_dc)*mu_w;
|
|
|
|
dmu_m_dc *= mu_w;
|
|
|
|
} else {
|
2012-04-19 10:21:08 -05:00
|
|
|
mu_m = viscMult(c)*mu_w;
|
|
|
|
}
|
|
|
|
double mu_p = viscMult(c_max_)*mu_w;
|
2012-04-26 02:25:46 -05:00
|
|
|
double inv_mu_m_omega = std::pow(mu_m, -omega);
|
|
|
|
double inv_mu_w_e = inv_mu_m_omega*std::pow(mu_w, omega - 1.);
|
|
|
|
double inv_mu_p_eff = inv_mu_m_omega*std::pow(mu_p, omega - 1.);
|
|
|
|
inv_mu_w_eff = (1.0 - cbar)*inv_mu_w_e + cbar*inv_mu_p_eff;
|
2012-04-19 10:21:08 -05:00
|
|
|
if (if_with_der) {
|
2012-04-26 02:25:46 -05:00
|
|
|
double dinv_mu_w_e_dc = -omega*dmu_m_dc*std::pow(mu_m, -omega - 1)*std::pow(mu_w, omega - 1);
|
|
|
|
double dinv_mu_p_eff_dc = -omega*dmu_m_dc*std::pow(mu_m, -omega - 1)*std::pow(mu_p, omega - 1);
|
|
|
|
dinv_mu_w_eff_dc = (1 - cbar)*dinv_mu_w_e_dc + cbar*dinv_mu_p_eff_dc +
|
|
|
|
1/c_max_*(inv_mu_p_eff - inv_mu_w_e);
|
2012-04-19 10:21:08 -05:00
|
|
|
}
|
|
|
|
}
|
2012-04-23 03:07:51 -05:00
|
|
|
|
2012-04-19 10:21:08 -05:00
|
|
|
void PolymerProperties::effectiveRelperm(const double c,
|
|
|
|
const double cmax,
|
|
|
|
const double* relperm,
|
|
|
|
double& eff_relperm_wat) const {
|
|
|
|
double dummy;
|
|
|
|
effectiveRelpermBoth(c, cmax, relperm, 0, eff_relperm_wat,
|
|
|
|
dummy, dummy, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PolymerProperties::effectiveRelpermWithDer (const double c,
|
|
|
|
const double cmax,
|
|
|
|
const double* relperm,
|
|
|
|
const double* drelperm_ds,
|
|
|
|
double& eff_relperm_wat,
|
|
|
|
double& deff_relperm_wat_ds,
|
|
|
|
double& deff_relperm_wat_dc) const {
|
2012-04-25 01:39:39 -05:00
|
|
|
effectiveRelpermBoth(c, cmax, relperm,
|
|
|
|
drelperm_ds, eff_relperm_wat,
|
|
|
|
deff_relperm_wat_ds, deff_relperm_wat_dc,
|
|
|
|
true);
|
2012-04-19 10:21:08 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void PolymerProperties::effectiveRelpermBoth(const double c,
|
|
|
|
const double cmax,
|
|
|
|
const double* relperm,
|
|
|
|
const double* drelperm_ds,
|
|
|
|
double& eff_relperm_wat,
|
|
|
|
double& deff_relperm_wat_ds,
|
|
|
|
double& deff_relperm_wat_dc,
|
|
|
|
bool if_with_der) const {
|
|
|
|
double c_ads;
|
|
|
|
double dc_ads_dc;
|
|
|
|
adsorptionBoth(c, cmax, c_ads, dc_ads_dc, if_with_der);
|
|
|
|
double rk = 1 + (res_factor_ - 1)*c_ads/c_max_ads_;
|
|
|
|
eff_relperm_wat = relperm[0]/rk;
|
|
|
|
if (if_with_der) {
|
2012-06-14 02:35:45 -05:00
|
|
|
deff_relperm_wat_ds = (drelperm_ds[0]-drelperm_ds[2])/rk; //derivative with respect to sw
|
2013-12-12 03:44:00 -06:00
|
|
|
//\frac{\partial k_{rw_eff}}{\parital c} = -\frac{krw}{rk^2}\frac{(RRF-1)}{c^a_{max}}\frac{\partial c^a}{\partial c}.
|
2013-12-16 04:43:52 -06:00
|
|
|
deff_relperm_wat_dc = -(res_factor_ - 1)*dc_ads_dc*relperm[0]/(rk*rk*c_max_ads_);
|
2012-04-19 10:21:08 -05:00
|
|
|
} else {
|
|
|
|
deff_relperm_wat_ds = -1.0;
|
|
|
|
deff_relperm_wat_dc = -1.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PolymerProperties::effectiveMobilities(const double c,
|
|
|
|
const double cmax,
|
|
|
|
const double* visc,
|
|
|
|
const double* relperm,
|
2012-04-25 01:39:39 -05:00
|
|
|
double* mob) const
|
2012-04-23 03:07:51 -05:00
|
|
|
{
|
2012-04-25 01:39:39 -05:00
|
|
|
double dummy;
|
|
|
|
double dummy_pointer[4];
|
2012-04-19 10:21:08 -05:00
|
|
|
effectiveMobilitiesBoth(c, cmax, visc, relperm,
|
2012-04-25 01:39:39 -05:00
|
|
|
dummy_pointer, mob, dummy_pointer, dummy, false);
|
2012-04-19 10:21:08 -05:00
|
|
|
}
|
|
|
|
|
2012-04-25 01:39:39 -05:00
|
|
|
|
2012-04-19 10:21:08 -05:00
|
|
|
void PolymerProperties::effectiveMobilitiesWithDer(const double c,
|
|
|
|
const double cmax,
|
|
|
|
const double* visc,
|
|
|
|
const double* relperm,
|
|
|
|
const double* drelpermds,
|
2012-04-25 01:39:39 -05:00
|
|
|
double* mob,
|
|
|
|
double* dmobds,
|
2012-04-23 03:07:51 -05:00
|
|
|
double& dmobwatdc) const
|
2012-04-19 10:21:08 -05:00
|
|
|
{
|
|
|
|
effectiveMobilitiesBoth(c, cmax, visc,
|
2012-04-24 04:20:06 -05:00
|
|
|
relperm, drelpermds, mob, dmobds,
|
2012-04-19 10:21:08 -05:00
|
|
|
dmobwatdc, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PolymerProperties::effectiveMobilitiesBoth(const double c,
|
|
|
|
const double cmax,
|
|
|
|
const double* visc,
|
|
|
|
const double* relperm,
|
|
|
|
const double* drelperm_ds,
|
2012-04-25 01:39:39 -05:00
|
|
|
double* mob,
|
|
|
|
double* dmob_ds,
|
2012-04-19 10:21:08 -05:00
|
|
|
double& dmobwat_dc,
|
2012-04-23 03:07:51 -05:00
|
|
|
bool if_with_der) const
|
2012-04-19 10:21:08 -05:00
|
|
|
{
|
2012-04-26 02:25:46 -05:00
|
|
|
double inv_mu_w_eff;
|
|
|
|
double dinv_mu_w_eff_dc;
|
|
|
|
effectiveInvViscBoth(c, visc, inv_mu_w_eff, dinv_mu_w_eff_dc, if_with_der);
|
2012-04-19 10:21:08 -05:00
|
|
|
double eff_relperm_wat;
|
|
|
|
double deff_relperm_wat_ds;
|
|
|
|
double deff_relperm_wat_dc;
|
2012-04-25 01:39:39 -05:00
|
|
|
|
2012-04-19 10:21:08 -05:00
|
|
|
effectiveRelpermBoth(c, cmax, relperm,
|
|
|
|
drelperm_ds, eff_relperm_wat,
|
|
|
|
deff_relperm_wat_ds, deff_relperm_wat_dc,
|
|
|
|
if_with_der);
|
2012-04-25 01:39:39 -05:00
|
|
|
|
2012-06-13 10:01:23 -05:00
|
|
|
// The "function" eff_relperm_wat is defined as a function of only sw (so that its
|
|
|
|
// partial derivative with respect to so is zero).
|
|
|
|
|
2012-04-26 02:25:46 -05:00
|
|
|
mob[0] = eff_relperm_wat*inv_mu_w_eff;
|
|
|
|
mob[1] = relperm[1]/visc[1];
|
2012-04-23 03:07:51 -05:00
|
|
|
|
2012-04-19 10:21:08 -05:00
|
|
|
if (if_with_der) {
|
2012-04-26 02:25:46 -05:00
|
|
|
dmobwat_dc = eff_relperm_wat*dinv_mu_w_eff_dc
|
|
|
|
+ deff_relperm_wat_dc*inv_mu_w_eff;
|
|
|
|
dmob_ds[0*2 + 0] = deff_relperm_wat_ds*inv_mu_w_eff;
|
2012-06-26 01:37:08 -05:00
|
|
|
// one have to deside which variables to derive
|
|
|
|
// here the full derivative is written out
|
|
|
|
dmob_ds[0*2 + 1] = 0.0*(drelperm_ds[0*2 + 1] - drelperm_ds[1*2 + 1])/visc[1];
|
|
|
|
dmob_ds[1*2 + 0] = -0.0*deff_relperm_wat_ds*inv_mu_w_eff;
|
2012-06-13 10:01:23 -05:00
|
|
|
dmob_ds[1*2 + 1] = (drelperm_ds[1*2 + 1] - drelperm_ds[0*2 + 1])/visc[1];
|
2012-04-19 10:21:08 -05:00
|
|
|
}
|
|
|
|
}
|
2012-04-23 03:07:51 -05:00
|
|
|
|
2012-04-23 04:49:05 -05:00
|
|
|
void PolymerProperties::effectiveTotalMobility(const double c,
|
|
|
|
const double cmax,
|
|
|
|
const double* visc,
|
|
|
|
const double* relperm,
|
|
|
|
double& totmob) const
|
|
|
|
{
|
2012-04-25 01:39:39 -05:00
|
|
|
double dummy1[4];
|
|
|
|
double dummy2[2];
|
|
|
|
effectiveTotalMobilityBoth(c, cmax, visc, relperm, dummy1,
|
|
|
|
totmob, dummy2, false);
|
2012-04-23 04:49:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void PolymerProperties::effectiveTotalMobilityWithDer(const double c,
|
|
|
|
const double cmax,
|
|
|
|
const double* visc,
|
|
|
|
const double* relperm,
|
|
|
|
const double* drelperm_ds,
|
|
|
|
double& totmob,
|
2012-04-25 01:39:39 -05:00
|
|
|
double* dtotmob_dsdc) const
|
2012-04-23 04:49:05 -05:00
|
|
|
{
|
|
|
|
effectiveTotalMobilityBoth(c, cmax, visc, relperm, drelperm_ds,
|
|
|
|
totmob, dtotmob_dsdc, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PolymerProperties::effectiveTotalMobilityBoth(const double c,
|
|
|
|
const double cmax,
|
|
|
|
const double* visc,
|
|
|
|
const double* relperm,
|
|
|
|
const double* drelperm_ds,
|
|
|
|
double& totmob,
|
2012-04-25 01:39:39 -05:00
|
|
|
double* dtotmob_dsdc,
|
2012-04-23 04:49:05 -05:00
|
|
|
bool if_with_der) const
|
|
|
|
{
|
2012-04-25 01:39:39 -05:00
|
|
|
double mob[2];
|
2012-04-25 02:23:59 -05:00
|
|
|
double dmob_ds[4];
|
2012-04-23 04:49:05 -05:00
|
|
|
double dmobwat_dc;
|
|
|
|
effectiveMobilitiesBoth(c, cmax, visc, relperm, drelperm_ds,
|
|
|
|
mob, dmob_ds, dmobwat_dc, if_with_der);
|
|
|
|
totmob = mob[0] + mob[1];
|
|
|
|
if (if_with_der) {
|
2012-06-13 10:01:23 -05:00
|
|
|
dtotmob_dsdc[0] = dmob_ds[0*2 + 0] - dmob_ds[1*2 + 0]
|
|
|
|
+ dmob_ds[0*2 + 1] - dmob_ds[1*2 + 1]; //derivative with respect to sw
|
2012-04-23 04:49:05 -05:00
|
|
|
dtotmob_dsdc[1] = dmobwat_dc; //derivative with respect to c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-23 03:07:51 -05:00
|
|
|
void PolymerProperties::computeMc(const double& c, double& mc) const
|
2012-04-19 10:21:08 -05:00
|
|
|
{
|
|
|
|
double dummy;
|
|
|
|
computeMcBoth(c, mc, dummy, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PolymerProperties::computeMcWithDer(const double& c, double& mc,
|
2012-04-25 01:39:39 -05:00
|
|
|
double& dmc_dc) const
|
2012-04-19 10:21:08 -05:00
|
|
|
{
|
|
|
|
computeMcBoth(c, mc, dmc_dc, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PolymerProperties::computeMcBoth(const double& c, double& mc,
|
2012-04-23 03:07:51 -05:00
|
|
|
double& dmc_dc, bool if_with_der) const
|
2012-04-19 10:21:08 -05:00
|
|
|
{
|
|
|
|
double cbar = c/c_max_;
|
|
|
|
double omega = mix_param_;
|
|
|
|
double r = std::pow(viscMult(c_max_), 1 - omega); // viscMult(c_max_)=mu_p/mu_w
|
|
|
|
mc = c/(cbar + (1 - cbar)*r);
|
|
|
|
if (if_with_der) {
|
|
|
|
dmc_dc = r/std::pow(cbar + (1 - cbar)*r, 2);
|
|
|
|
} else {
|
|
|
|
dmc_dc = 0.;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|