Skip to content

Commit 59b5434

Browse files
Add first parameter dependencies to chromatography models
Add radial flow and parameter dependence support to createLWE Axial dispersion for all FV units, film diffusion parameter dependence for LRMP FV unit Add tests for radial flow convection dispersion operators Enable radial dispersion coeff dependency in operators Parameter dependencies are work in progress and the interfaces might change up until the next release Co-authored-by: jbreue16 <[email protected]>
1 parent 82a0f84 commit 59b5434

25 files changed

+949
-269
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
.. _parameter_dependencies:
2+
3+
Parameter Dependencies
4+
======================
5+
6+
Some parameters depend on other parameters (parameter-parameter dependency) or the solution variables (parameter-state dependency).
7+
Parameter dependencies are defined in the unit operation scope.
8+
9+
Parameter-Parameter Dependencies
10+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
11+
12+
Group /input/model/unit_XXX
13+
---------------------------
14+
15+
``COL_DISPERSION_DEP``
16+
17+
Parameter dependence of column dispersion on the interstitial velocity. Available for the LRM, LRMP and GRM units (with FV discretization only at the moment)
18+
19+
================ ===================================== =============
20+
**Type:** string **Range:** :math:`\texttt{POWER_LAW}` **Length:** 1
21+
================ ===================================== =============
22+
23+
``FILM_DIFFUSION_DEP``
24+
25+
Parameter dependence of film diffusion on the interstitial velocity. Available for the LRMP unit (with FV discretization only at the moment)
26+
27+
================ ===================================== =============
28+
**Type:** string **Range:** :math:`\texttt{POWER_LAW}` **Length:** 1
29+
================ ===================================== =============
30+
31+
32+
**Correlations**
33+
""""""""""""""""
34+
35+
Different types of parameter correlations are can be applied.
36+
The following correlations can be used for all parameter-parameter dependencies, but we specify the required input fields only for ``COL_DISPERSION_DEP``, for the sake of conciseness.
37+
38+
**Power Law**
39+
40+
.. math::
41+
42+
\begin{aligned}
43+
p_{dep} &= p_{dep} \cdot b \ |p_{on}^x|
44+
\end{aligned}
45+
46+
Here, :math:`p_{dep}` is the dependent parameter and :math:`p_{on}` is the parameter it depends on.
47+
48+
``COL_DISPERSION_DEP_BASE``
49+
50+
Base :math:`b` of the power law parameter dependence. Optional, defaults to :math:`1.0`
51+
52+
================ ============================= =============
53+
**Type:** double **Range:** :math:`\mathbb{R}` **Length:** 1
54+
================ ============================= =============
55+
56+
``COL_DISPERSION_DEP_EXPONENT``
57+
58+
Exponent :math:`x` of the power law parameter dependence
59+
60+
================ ============================= =============
61+
**Type:** double **Range:** :math:`\mathbb{R}` **Length:** 1
62+
================ ============================= =============
63+
64+
``COL_DISPERSION_DEP_ABS``
65+
66+
Specifies whether or not the absolute value should be computed. Optional, defaults to :math:`1`
67+
68+
============= =========================== =============
69+
**Type:** int **Range:** :math:`\{0, 1\}` **Length:** 1
70+
============= =========================== =============
71+
72+
73+
Parameter-State Dependencies
74+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
75+
76+
Group /input/model/unit_XXX
77+
---------------------------
78+
79+
Parameter-State Dependencies are not fully implemented yet.

doc/interface/unit_operations/radial_flow_models.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ For information on model equations, refer to :ref:`lumped_rate_model_without_por
3434
**Type:** double **Range:** :math:`\geq 0` **Length:** see :math:`\texttt{COL_DISPERSION_MULTIPLEX}`
3535
================ ========================= =========================================================
3636

37-
For multiplex specifications, e.g. for component dependency, see :ref:`general_rate_model_model`.
37+
In addition to the multiplex specification (e.g. component dependency, see :ref:`general_rate_model_model`), the dispersion coefficient for radial flow model usually depends on other parameters.
38+
Parameter dependencies are described here :ref:`parameter_dependencies`.
39+
3840

3941
``COL_RADIUS_INNER``
4042

src/libcadet/model/GeneralRateModel.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1263,7 +1263,7 @@ template <typename ConvDispOperator>
12631263
template <typename StateType, typename ResidualType, typename ParamType, bool wantJac>
12641264
int GeneralRateModel<ConvDispOperator>::residualBulk(double t, unsigned int secIdx, StateType const* yBase, double const* yDotBase, ResidualType* resBase, util::ThreadLocalStorage& threadLocalMem)
12651265
{
1266-
_convDispOp.residual(t, secIdx, yBase, yDotBase, resBase, wantJac, typename ParamSens<ParamType>::enabled());
1266+
_convDispOp.residual(*this, t, secIdx, yBase, yDotBase, resBase, wantJac, typename ParamSens<ParamType>::enabled());
12671267
if (!_dynReactionBulk || (_dynReactionBulk->numReactionsLiquid() == 0))
12681268
return 0;
12691269

src/libcadet/model/GeneralRateModel2D.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ bool GeneralRateModel2D::configureModelDiscretization(IParameterProvider& paramP
723723
}
724724
}
725725

726-
const bool transportSuccess = _convDispOp.configureModelDiscretization(paramProvider, _disc.nComp, _disc.nCol, _disc.nRad, _dynReactionBulk);
726+
const bool transportSuccess = _convDispOp.configureModelDiscretization(paramProvider, helper, _disc.nComp, _disc.nCol, _disc.nRad, _dynReactionBulk);
727727

728728
// Setup the memory for tempState based on state vector
729729
_tempState = new double[numDofs()];
@@ -1336,7 +1336,7 @@ int GeneralRateModel2D::residualImpl(double t, unsigned int secIdx, StateType co
13361336
template <typename StateType, typename ResidualType, typename ParamType, bool wantJac>
13371337
int GeneralRateModel2D::residualBulk(double t, unsigned int secIdx, StateType const* yBase, double const* yDotBase, ResidualType* resBase, util::ThreadLocalStorage& threadLocalMem)
13381338
{
1339-
_convDispOp.residual(t, secIdx, yBase, yDotBase, resBase, wantJac, typename ParamSens<ParamType>::enabled());
1339+
_convDispOp.residual(*this, t, secIdx, yBase, yDotBase, resBase, wantJac, typename ParamSens<ParamType>::enabled());
13401340
if (!_dynReactionBulk || (_dynReactionBulk->numReactionsLiquid() == 0))
13411341
return 0;
13421342

src/libcadet/model/LumpedRateModelWithPores.cpp

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "model/BindingModel.hpp"
2222
#include "model/ReactionModel.hpp"
2323
#include "model/parts/BindingCellKernel.hpp"
24+
#include "model/ParameterDependence.hpp"
2425
#include "SimulationTypes.hpp"
2526
#include "linalg/DenseMatrix.hpp"
2627
#include "linalg/BandMatrix.hpp"
@@ -63,7 +64,7 @@ int schurComplementMultiplierLRMPores(void* userData, double const* x, double* z
6364

6465
template <typename ConvDispOperator>
6566
LumpedRateModelWithPores<ConvDispOperator>::LumpedRateModelWithPores(UnitOpIdx unitOpIdx) : UnitOperationBase(unitOpIdx),
66-
_dynReactionBulk(nullptr), _jacP(0), _jacPdisc(0), _jacPF(0), _jacFP(0), _jacInlet(), _analyticJac(true),
67+
_dynReactionBulk(nullptr), _filmDiffDep(nullptr), _jacP(0), _jacPdisc(0), _jacPF(0), _jacFP(0), _jacInlet(), _analyticJac(true),
6768
_jacobianAdDirs(0), _factorizeJacobian(false), _tempState(nullptr), _initC(0), _initCp(0), _initQ(0),
6869
_initState(0), _initStateDot(0)
6970
{
@@ -75,6 +76,7 @@ LumpedRateModelWithPores<ConvDispOperator>::~LumpedRateModelWithPores() CADET_NO
7576
delete[] _tempState;
7677

7778
delete _dynReactionBulk;
79+
delete _filmDiffDep;
7880

7981
delete[] _disc.parTypeOffset;
8082
delete[] _disc.nBound;
@@ -263,6 +265,18 @@ bool LumpedRateModelWithPores<ConvDispOperator>::configureModelDiscretization(IP
263265

264266
const bool transportSuccess = _convDispOp.configureModelDiscretization(paramProvider, helper, _disc.nComp, _disc.nCol);
265267

268+
if (paramProvider.exists("FILM_DIFFUSION_DEP"))
269+
{
270+
const std::string paramDepName = paramProvider.getString("FILM_DIFFUSION_DEP");
271+
_filmDiffDep = helper.createParameterParameterDependence(paramDepName);
272+
if (!_filmDiffDep)
273+
throw InvalidParameterException("Unknown parameter dependence " + paramDepName + " in FILM_DIFFUSION_DEP");
274+
275+
_filmDiffDep->configureModelDiscretization(paramProvider);
276+
}
277+
else
278+
_filmDiffDep = helper.createParameterParameterDependence("CONSTANT_ONE");
279+
266280
// Allocate memory
267281
Indexer idxr(_disc);
268282

@@ -402,6 +416,12 @@ bool LumpedRateModelWithPores<ConvDispOperator>::configure(IParameterProvider& p
402416

403417
const bool transportSuccess = _convDispOp.configure(_unitOpIdx, paramProvider, _parameters);
404418

419+
if (_filmDiffDep)
420+
{
421+
if (!_filmDiffDep->configure(paramProvider, _unitOpIdx, ParTypeIndep, BoundStateIndep, "FILM_DIFFUSION_DEP"))
422+
throw InvalidParameterException("Failed to configure film diffusion parameter dependency (FILM_DIFFUSION_DEP)");
423+
}
424+
405425
// Read geometry parameters
406426
_colPorosity = paramProvider.getDouble("COL_POROSITY");
407427
_singleParRadius = readAndRegisterMultiplexTypeParam(paramProvider, _parameters, _parRadius, "PAR_RADIUS", _disc.nParType, _unitOpIdx);
@@ -964,7 +984,7 @@ template <typename ConvDispOperator>
964984
template <typename StateType, typename ResidualType, typename ParamType, bool wantJac>
965985
int LumpedRateModelWithPores<ConvDispOperator>::residualBulk(double t, unsigned int secIdx, StateType const* yBase, double const* yDotBase, ResidualType* resBase, util::ThreadLocalStorage& threadLocalMem)
966986
{
967-
_convDispOp.residual(t, secIdx, yBase, yDotBase, resBase, wantJac, typename ParamSens<ParamType>::enabled());
987+
_convDispOp.residual(*this, t, secIdx, yBase, yDotBase, resBase, wantJac, typename ParamSens<ParamType>::enabled());
968988
if (!_dynReactionBulk || (_dynReactionBulk->numReactionsLiquid() == 0))
969989
return 0;
970990

@@ -1068,7 +1088,12 @@ int LumpedRateModelWithPores<ConvDispOperator>::residualFlux(double t, unsigned
10681088
{
10691089
const unsigned int colCell = i / _disc.nComp;
10701090
const unsigned int comp = i % _disc.nComp;
1071-
resCol[i] += jacCF_val * static_cast<ParamType>(filmDiff[comp]) * static_cast<ParamType>(_parTypeVolFrac[type + _disc.nParType * colCell]) * yFluxType[i];
1091+
1092+
const double relPos = _convDispOp.relativeCoordinate(colCell);
1093+
const active curVelocity = _convDispOp.currentVelocity(relPos);
1094+
const active modifier = _filmDiffDep->getValue(*this, ColumnPosition{relPos, 0.0, 0.0}, comp, ParTypeIndep, BoundStateIndep, curVelocity);
1095+
1096+
resCol[i] += jacCF_val * static_cast<ParamType>(filmDiff[comp]) * static_cast<ParamType>(modifier) * static_cast<ParamType>(_parTypeVolFrac[type + _disc.nParType * colCell]) * yFluxType[i];
10721097
}
10731098

10741099
// J_{f,0} block, adds bulk volume state c_i to flux equation
@@ -1084,10 +1109,15 @@ int LumpedRateModelWithPores<ConvDispOperator>::residualFlux(double t, unsigned
10841109
// J_{p,f} block, adds flux to particle / bead volume equations
10851110
for (unsigned int pblk = 0; pblk < _disc.nCol; ++pblk)
10861111
{
1112+
const double relPos = _convDispOp.relativeCoordinate(pblk);
1113+
const active curVelocity = _convDispOp.currentVelocity(relPos);
1114+
10871115
for (unsigned int comp = 0; comp < _disc.nComp; ++comp)
10881116
{
1117+
const active modifier = _filmDiffDep->getValue(*this, ColumnPosition{relPos, 0.0, 0.0}, comp, ParTypeIndep, BoundStateIndep, curVelocity);
1118+
10891119
const unsigned int eq = pblk * idxr.strideColCell() + comp * idxr.strideColComp();
1090-
resParType[pblk * idxr.strideParBlock(type) + comp] += jacPF_val / static_cast<ParamType>(poreAccFactor[comp]) * static_cast<ParamType>(filmDiff[comp]) * yFluxType[eq];
1120+
resParType[pblk * idxr.strideParBlock(type) + comp] += jacPF_val / static_cast<ParamType>(poreAccFactor[comp]) * static_cast<ParamType>(filmDiff[comp]) * static_cast<ParamType>(modifier) * yFluxType[eq];
10911121
}
10921122
}
10931123

@@ -1148,8 +1178,12 @@ void LumpedRateModelWithPores<ConvDispOperator>::assembleOffdiagJac(double t, un
11481178
const unsigned int colCell = eq / _disc.nComp;
11491179
const unsigned int comp = eq % _disc.nComp;
11501180

1181+
const double relPos = _convDispOp.relativeCoordinate(colCell);
1182+
const double curVelocity = static_cast<double>(_convDispOp.currentVelocity(relPos));
1183+
const double modifier = _filmDiffDep->getValue(*this, ColumnPosition{relPos, 0.0, 0.0}, comp, ParTypeIndep, BoundStateIndep, curVelocity);
1184+
11511185
// Main diagonal corresponds to j_{f,i} (flux) state variable
1152-
_jacCF.addElement(eq, eq + typeOffset, jacCF_val * static_cast<double>(filmDiff[comp]) * static_cast<double>(_parTypeVolFrac[type + _disc.nParType * colCell]));
1186+
_jacCF.addElement(eq, eq + typeOffset, jacCF_val * static_cast<double>(filmDiff[comp]) * modifier * static_cast<double>(_parTypeVolFrac[type + _disc.nParType * colCell]));
11531187
}
11541188

11551189
// J_{f,0} block, adds bulk volume state c_i to flux equation
@@ -1161,11 +1195,16 @@ void LumpedRateModelWithPores<ConvDispOperator>::assembleOffdiagJac(double t, un
11611195
// J_{p,f} block, implements bead boundary condition in outer bead shell equation
11621196
for (unsigned int pblk = 0; pblk < _disc.nCol; ++pblk)
11631197
{
1198+
const double relPos = _convDispOp.relativeCoordinate(pblk);
1199+
const double curVelocity = static_cast<double>(_convDispOp.currentVelocity(relPos));
1200+
11641201
for (unsigned int comp = 0; comp < _disc.nComp; ++comp)
11651202
{
11661203
const unsigned int eq = typeOffset + pblk * idxr.strideColCell() + comp * idxr.strideColComp();
11671204
const unsigned int col = pblk * idxr.strideParBlock(type) + comp;
1168-
_jacPF[type].addElement(col, eq, jacPF_val / static_cast<double>(poreAccFactor[comp]) * static_cast<double>(filmDiff[comp]));
1205+
1206+
const double modifier = _filmDiffDep->getValue(*this, ColumnPosition{relPos, 0.0, 0.0}, comp, ParTypeIndep, BoundStateIndep, curVelocity);
1207+
_jacPF[type].addElement(col, eq, jacPF_val / static_cast<double>(poreAccFactor[comp]) * static_cast<double>(filmDiff[comp]) * modifier);
11691208
}
11701209
}
11711210

@@ -1468,6 +1507,15 @@ bool LumpedRateModelWithPores<ConvDispOperator>::setParameter(const ParameterId&
14681507

14691508
if (_convDispOp.setParameter(pId, value))
14701509
return true;
1510+
1511+
if (_filmDiffDep)
1512+
{
1513+
if (_filmDiffDep->hasParameter(pId))
1514+
{
1515+
_filmDiffDep->setParameter(pId, value);
1516+
return true;
1517+
}
1518+
}
14711519
}
14721520

14731521
return UnitOperationBase::setParameter(pId, value);
@@ -1509,6 +1557,16 @@ void LumpedRateModelWithPores<ConvDispOperator>::setSensitiveParameterValue(cons
15091557

15101558
if (_convDispOp.setSensitiveParameterValue(_sensParams, pId, value))
15111559
return;
1560+
1561+
if (_filmDiffDep)
1562+
{
1563+
active* const param = _filmDiffDep->getParameter(pId);
1564+
if (param)
1565+
{
1566+
param->setValue(value);
1567+
return;
1568+
}
1569+
}
15121570
}
15131571

15141572
UnitOperationBase::setSensitiveParameterValue(pId, value);
@@ -1575,6 +1633,17 @@ bool LumpedRateModelWithPores<ConvDispOperator>::setSensitiveParameter(const Par
15751633
LOG(Debug) << "Found parameter " << pId << ": Dir " << adDirection << " is set to " << adValue;
15761634
return true;
15771635
}
1636+
1637+
if (_filmDiffDep)
1638+
{
1639+
active* const param = _filmDiffDep->getParameter(pId);
1640+
if (param)
1641+
{
1642+
LOG(Debug) << "Found parameter " << pId << ": Dir " << adDirection << " is set to " << adValue;
1643+
param->setADValue(adDirection, adValue);
1644+
return true;
1645+
}
1646+
}
15781647
}
15791648

15801649
return UnitOperationBase::setSensitiveParameter(pId, adDirection, adValue);

src/libcadet/model/LumpedRateModelWithPores.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ class LumpedRateModelWithPores : public UnitOperationBase
264264

265265
ConvDispOperator _convDispOp; //!< Convection dispersion operator for interstitial volume transport
266266
IDynamicReactionModel* _dynReactionBulk; //!< Dynamic reactions in the bulk volume
267+
IParameterParameterDependence* _filmDiffDep; //!< Film diffusion dependency on local velocity
267268

268269
std::vector<linalg::BandMatrix> _jacP; //!< Particle jacobian diagonal blocks (all of them for each particle type)
269270
std::vector<linalg::FactorizableBandMatrix> _jacPdisc; //!< Particle jacobian diagonal blocks (all of them for each particle type) with time derivatives from BDF method

src/libcadet/model/LumpedRateModelWithoutPores.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ namespace
4646
class ConvOpResidual
4747
{
4848
public:
49-
static inline void call(ConvDispOperator& op, double t, unsigned int secIdx, StateType const* const y, double const* const yDot, ResidualType* const res, cadet::linalg::BandMatrix& jac)
49+
static inline void call(cadet::IModel* const model, ConvDispOperator& op, double t, unsigned int secIdx, StateType const* const y, double const* const yDot, ResidualType* const res, cadet::linalg::BandMatrix& jac)
5050
{
5151
// This should not be reached
5252
cadet_assert(false);
@@ -57,29 +57,29 @@ namespace
5757
class ConvOpResidual<ConvDispOperator, double, ResidualType, ParamType, true>
5858
{
5959
public:
60-
static inline void call(ConvDispOperator& op, double t, unsigned int secIdx, double const* const y, double const* const yDot, ResidualType* const res, cadet::linalg::BandMatrix& jac)
60+
static inline void call(cadet::IModel* const model, ConvDispOperator& op, double t, unsigned int secIdx, double const* const y, double const* const yDot, ResidualType* const res, cadet::linalg::BandMatrix& jac)
6161
{
62-
op.residual(t, secIdx, y, yDot, res, jac);
62+
op.residual(*model, t, secIdx, y, yDot, res, jac);
6363
}
6464
};
6565

6666
template <typename ConvDispOperator, typename ResidualType, typename ParamType>
6767
class ConvOpResidual<ConvDispOperator, double, ResidualType, ParamType, false>
6868
{
6969
public:
70-
static inline void call(ConvDispOperator& op, double t, unsigned int secIdx, double const* const y, double const* const yDot, ResidualType* const res, cadet::linalg::BandMatrix& jac)
70+
static inline void call(cadet::IModel* const model, ConvDispOperator& op, double t, unsigned int secIdx, double const* const y, double const* const yDot, ResidualType* const res, cadet::linalg::BandMatrix& jac)
7171
{
72-
op.residual(t, secIdx, y, yDot, res, typename cadet::ParamSens<ParamType>::enabled());
72+
op.residual(*model, t, secIdx, y, yDot, res, typename cadet::ParamSens<ParamType>::enabled());
7373
}
7474
};
7575

7676
template <typename ConvDispOperator, typename ResidualType, typename ParamType>
7777
class ConvOpResidual<ConvDispOperator, cadet::active, ResidualType, ParamType, false>
7878
{
7979
public:
80-
static inline void call(ConvDispOperator& op, double t, unsigned int secIdx, cadet::active const* const y, double const* const yDot, ResidualType* const res, cadet::linalg::BandMatrix& jac)
80+
static inline void call(cadet::IModel* const model, ConvDispOperator& op, double t, unsigned int secIdx, cadet::active const* const y, double const* const yDot, ResidualType* const res, cadet::linalg::BandMatrix& jac)
8181
{
82-
op.residual(t, secIdx, y, yDot, res, typename cadet::ParamSens<ParamType>::enabled());
82+
op.residual(*model, t, secIdx, y, yDot, res, typename cadet::ParamSens<ParamType>::enabled());
8383
}
8484
};
8585
}
@@ -609,7 +609,7 @@ template <typename ConvDispOperator>
609609
template <typename StateType, typename ResidualType, typename ParamType, bool wantJac>
610610
int LumpedRateModelWithoutPores<ConvDispOperator>::residualImpl(double t, unsigned int secIdx, StateType const* const y, double const* const yDot, ResidualType* const res, util::ThreadLocalStorage& threadLocalMem)
611611
{
612-
ConvOpResidual<ConvDispOperator, StateType, ResidualType, ParamType, wantJac>::call(_convDispOp, t, secIdx, y, yDot, res, _jac);
612+
ConvOpResidual<ConvDispOperator, StateType, ResidualType, ParamType, wantJac>::call(this, _convDispOp, t, secIdx, y, yDot, res, _jac);
613613

614614
Indexer idxr(_disc);
615615

@@ -785,7 +785,7 @@ template <typename ConvDispOperator>
785785
unsigned int LumpedRateModelWithoutPores<ConvDispOperator>::localOutletComponentIndex(unsigned int port) const CADET_NOEXCEPT
786786
{
787787
// Inlets are duplicated so need to be accounted for
788-
if (static_cast<double>(_convDispOp.currentVelocity()) >= 0.0)
788+
if (_convDispOp.forwardFlow())
789789
// Forward Flow: outlet is last cell
790790
return _disc.nComp + (_disc.nCol - 1) * (_disc.nComp + _disc.strideBound);
791791
else

0 commit comments

Comments
 (0)