35
35
{ "type": "ScalarParameter", "varName": "beta0", "confName": "HICUNI_BETA0"},
36
36
{ "type": "ScalarParameter", "varName": "beta1", "confName": "HICUNI_BETA1"},
37
37
{ "type": "ScalarComponentDependentParameter", "varName": "kA", "confName": "HICUNI_KA"},
38
+ { "type": "ScalarComponentDependentParameter", "varName": "kALin", "confName": "HICUNI_KA_LIN"},
38
39
{ "type": "ScalarComponentDependentParameter", "varName": "kD", "confName": "HICUNI_KD"},
39
40
{ "type": "ScalarComponentDependentParameter", "varName": "kP", "confName": "HICUNI_KP"},
40
41
{ "type": "ScalarComponentDependentParameter", "varName": "kS", "confName": "HICUNI_KS"},
41
42
{ "type": "ScalarComponentDependentParameter", "varName": "epsilon", "confName": "HICUNI_EPSILON"},
42
43
{ "type": "ScalarComponentDependentParameter", "varName": "nu", "confName": "HICUNI_NU"},
44
+ { "type": "ScalarComponentDependentParameter", "varName": "nuLin", "confName": "HICUNI_NU_LIN"},
43
45
{ "type": "ScalarComponentDependentParameter", "varName": "qMax", "confName": "HICUNI_QMAX"}
44
46
],
45
47
"constantParameters":
46
48
[
49
+ { "type": "ScalarParameter", "varName": "refPh", "default": 7.0, "objName": "referencePh", "confName": "HICUNI_PH_REF"},
47
50
{ "type": "ScalarParameter", "varName": "rho", "default": 0.00003348, "objName": "osmoticEffect", "confName": "HICUNI_RHO"}
48
51
49
52
]
55
58
beta0 = bulk-like ordered water molecules at infinitely diluted salt concentration
56
59
beta1 = influence of salt concentration on bulk-like ordered water molecules
57
60
kA = Adsorption constant
61
+ kALin = Linear dependency of ka on pH
58
62
kD = Desorption constant
59
63
kP = Influence of protein concentration on protein activity
60
64
kS = Influence of salt concentration on protein activity
61
65
epsilon = Influence of bound protein concentration on bound protein activity
62
66
nu = Number of binding sites
67
+ nuLin = Linear dependency of nu on pH
63
68
qMax = Maximum binding capacity
64
69
rh0 = osmotic effect of salt concentration on water activity. Calculated as osmotic_coefficient * molar_weight_of_water * ion_number in
70
+ refpH = reference pH (defaults to 7)
65
71
*/
66
72
67
73
namespace cadet
@@ -75,8 +81,10 @@ namespace cadet
75
81
inline bool HICUNIFIEDParamHandler::validateConfig (unsigned int nComp, unsigned int const * nBoundStates)
76
82
{
77
83
if ((_kA.size () != _kD.size ()) || (_kA.size () != _nu.size ()) || (_kA.size () != _qMax.size ())
78
- || (_kA.size () != _kP.size ()) || (_kA.size () != _kS.size ()) || (_kA.size () != _epsilon.size ()) || (_kA.size () < nComp))
79
- throw InvalidParameterException (" HICUNI_KA, HICUNI_KD, HICUNI_NU, and HICUNI_QMAX have to have the same size" );
84
+ || (_kA.size () != _kP.size ()) || (_kA.size () != _kS.size ()) || (_kA.size () != _epsilon.size ())
85
+ || (_kA.size () != _nuLin.size ()) || (_kA.size () != _kALin.size ())
86
+ || (_kA.size () < nComp))
87
+ throw InvalidParameterException (" HICUNI_KA, HICUNI_KD, HICUNI_NU, and HICUNI_QMAX, HICUNI_KA_LIN, HICUNI_NU_LIN have to have the same size" );
80
88
81
89
return true ;
82
90
}
@@ -86,8 +94,10 @@ namespace cadet
86
94
inline bool ExtHICUNIFIEDParamHandler::validateConfig (unsigned int nComp, unsigned int const * nBoundStates)
87
95
{
88
96
if ((_kA.size () != _kD.size ()) || (_kA.size () != _nu.size ()) || (_kA.size () != _qMax.size ())
89
- || (_kA.size () != _kP.size ()) || (_kA.size () != _kS.size ()) || (_kA.size () != _epsilon.size ()) || (_kA.size () < nComp))
90
- throw InvalidParameterException (" KA, KD, NU, and QMAX have to have the same size" );
97
+ || (_kA.size () != _kP.size ()) || (_kA.size () != _kS.size ()) || (_kA.size () != _epsilon.size ())
98
+ || (_kA.size () != _nuLin.size ()) || (_kA.size () != _kALin.size ())
99
+ || (_kA.size () < nComp))
100
+ throw InvalidParameterException (" HICUNI_KA, HICUNI_KD, HICUNI_NU, and HICUNI_QMAX, HICUNI_KA_LIN, HICUNI_NU_LIN have to have the same size" );
91
101
92
102
return true ;
93
103
}
@@ -97,7 +107,10 @@ namespace cadet
97
107
* @brief Defines a unified HIC isotherm combining publications by Deichert et al 2010, Mollerup et al 2006, and Jäpel and Buyel 2022
98
108
* @details Implements a unified HIC isotherm : \f[ \begin{align}
99
109
* \beta &= \beta_0 e^{c_{p,0}\beta_1}\\
100
- * \frac{\mathrm{d}q_i}{\mathrm{d}t} &= k_{a,i} c_{p,i}e^{k_{p,i} c_{p,i}+k_{s,i} c_{s}}(1-\sum{\frac{q_p}{q_{max}}})^{ν_i} -k_{d,i} q_{p,i}(1+\epsilon q_{p,i}) (e^{ρc_{s}})^{ν_i β_0 e^{β_1 c_s}}
110
+ * k_{a,i} &= k_{a,i,0} \exp\left( k_{a,i,lin} (\mathrm{pH}-\mathrm{pH}_{ref})\right)\\
111
+ * \nu_i &= \nu_{i,0} + \nu_{i,lin} (\mathrm{pH}-\mathrm{pH}_{ref})\\
112
+ * \frac{\mathrm{d}q_i}{\mathrm{d}t} &= k_{a,i} c_{p,i}e^{k_{p,i} c_{p,i}+k_{s,i} c_{s}}(1-\sum{\frac{q_p}{q_{max}}})^{\nu_i}
113
+ * -k_{d,i} q_{p,i}(1+\epsilon q_{p,i}) (e^{\rho c_{s}})^{\nu_i \beta_0 e^{\beta_1 c_s}}
101
114
* \end{align} \f]
102
115
* Component @c 0 is assumed to be salt without a bound state. Multiple bound states are not supported.
103
116
* Components without bound state (i.e., salt and non-binding components) are supported.
@@ -122,6 +135,10 @@ namespace cadet
122
135
if (nBound[0 ] != 0 )
123
136
throw InvalidParameterException (" HICUNIFIED binding model requires exactly zero bound states for salt component" );
124
137
138
+
139
+ // Guarantee that modifier component is non-binding
140
+ if (nBound[1 ] != 0 )
141
+ throw InvalidParameterException (" HICUNIFIED binding model requires non-binding pH modifier component (NBOUND[1] = 0)" );
125
142
return res;
126
143
}
127
144
@@ -167,6 +184,10 @@ namespace cadet
167
184
168
185
typename ParamHandler_t::ParamsHandle const _p = _paramHandler.update (t, secIdx, colPos, _nComp, _nBoundStates, workSpace);
169
186
187
+ // Pseudo component 1 is pH
188
+ const CpStateType pH = yCp[1 ];
189
+ const ParamType refPh = static_cast <ParamType>(_p->refPh );
190
+
170
191
const ParamType beta0 = static_cast <ParamType>(_p->beta0 );
171
192
const ParamType beta1 = static_cast <ParamType>(_p->beta1 );
172
193
@@ -183,7 +204,7 @@ namespace cadet
183
204
StateParamType qSum = 1.0 ;
184
205
185
206
unsigned int bndIdx = 0 ;
186
- for (int i = 0 ; i < _nComp; ++i)
207
+ for (int i = 2 ; i < _nComp; ++i)
187
208
{
188
209
// Skip components without bound states (bound state index bndIdx is not advanced)
189
210
if (_nBoundStates[i] == 0 )
@@ -196,23 +217,26 @@ namespace cadet
196
217
}
197
218
198
219
bndIdx = 0 ;
199
- for (int i = 0 ; i < _nComp; ++i)
220
+ for (int i = 2 ; i < _nComp; ++i)
200
221
{
201
222
// Skip components without bound states (bound state index bndIdx is not advanced)
202
223
if (_nBoundStates[i] == 0 )
203
224
continue ;
204
225
205
226
const ParamType kD = static_cast <ParamType>(_p->kD [i]);
206
227
const ParamType kA = static_cast <ParamType>(_p->kA [i]);
228
+ const ParamType kALin = static_cast <ParamType>(_p->kALin [i]);
207
229
const ParamType kP = static_cast <ParamType>(_p->kP [i]);
208
230
const ParamType kS = static_cast <ParamType>(_p->kS [i]);
209
231
const ParamType nu = static_cast <ParamType>(_p->nu [i]);
232
+ const ParamType nuLin = static_cast <ParamType>(_p->nuLin [i]);
210
233
const ParamType epsilon = static_cast <ParamType>(_p->epsilon [i]);
211
234
212
- /* res[bndIdx] = kD * y[bndIdx] * pow(water_activity, nu * beta)
213
- - kA * pow(qSum, nu) * yCp[i];*/
214
- res[bndIdx] = kD * y[bndIdx] * (1 + epsilon * y[bndIdx]) * pow (water_activity, nu * beta)
215
- - kA * pow (qSum, nu) * yCp[i] * exp (kP * yCp[i] + kS * yCp[0 ]);
235
+ const CpStateParamType kApH = kA * exp (kALin * (pH - refPh));
236
+ const CpStateParamType nupH = nu + nuLin * (pH - refPh);
237
+
238
+ res[bndIdx] = kD * y[bndIdx] * (1 + epsilon * y[bndIdx]) * pow (water_activity, nupH * beta)
239
+ - kApH * pow (qSum, nupH) * yCp[i] * exp (kP * yCp[i] + kS * yCp[0 ]);
216
240
217
241
// Next bound component
218
242
++bndIdx;
@@ -228,6 +252,10 @@ namespace cadet
228
252
229
253
using std::pow, std::exp;
230
254
255
+ // Pseudo component 1 is pH
256
+ const double pH = yCp[1 ];
257
+ const double refPh = static_cast <double >(_p->refPh );
258
+
231
259
const double beta0 = static_cast <double >(_p->beta0 );
232
260
const double beta1 = static_cast <double >(_p->beta1 );
233
261
@@ -239,7 +267,7 @@ namespace cadet
239
267
double qSum = 1.0 ;
240
268
241
269
unsigned int bndIdx = 0 ;
242
- for (int i = 0 ; i < _nComp; ++i)
270
+ for (int i = 2 ; i < _nComp; ++i)
243
271
{
244
272
// Skip components without bound states (bound state index bndIdx is not advanced)
245
273
if (_nBoundStates[i] == 0 )
@@ -252,7 +280,7 @@ namespace cadet
252
280
}
253
281
254
282
bndIdx = 0 ;
255
- for (int i = 0 ; i < _nComp; ++i)
283
+ for (int i = 2 ; i < _nComp; ++i)
256
284
{
257
285
// Skip components without bound states (bound state index bndIdx is not advanced)
258
286
if (_nBoundStates[i] == 0 )
@@ -264,15 +292,21 @@ namespace cadet
264
292
const double kS = static_cast <double >(_p->kS [i]);
265
293
const double nu = static_cast <double >(_p->nu [i]);
266
294
const double epsilon = static_cast <double >(_p->epsilon [i]);
295
+ const double kALin = static_cast <double >(_p->kALin [i]);
296
+ const double nuLin = static_cast <double >(_p->nuLin [i]);
297
+
298
+ const double kApH = kA * exp (kALin * (pH - refPh));
299
+ const double nupH = nu + nuLin * (pH - refPh);
300
+
267
301
268
302
// dres_i / dc_{p,0}
269
- jac[-bndIdx - offsetCp] = kD * y[bndIdx] * (1 + epsilon * y[bndIdx]) * (-rho) * nu * beta0 * (beta1 * yCp[0 ] + 1 ) *
270
- exp (beta1 * yCp[0 ] - rho * nu * beta0 * exp (beta1 * yCp[0 ]) * yCp[0 ])
271
- - kA * yCp[i] * pow (qSum, nu ) * exp (kP * yCp[i] + kS * yCp[0 ]) * kS ;
303
+ jac[-bndIdx - offsetCp] = kD * y[bndIdx] * (1 + epsilon * y[bndIdx]) * (-rho) * nupH * beta0 * (beta1 * yCp[0 ] + 1 ) *
304
+ exp (beta1 * yCp[0 ] - rho * nupH * beta0 * exp (beta1 * yCp[0 ]) * yCp[0 ])
305
+ - kApH * yCp[i] * pow (qSum, nupH ) * exp (kP * yCp[i] + kS * yCp[0 ]) * kS ;
272
306
273
307
// dres_i / dc_{p,i}
274
- jac[i - bndIdx - offsetCp] = -kA * pow (qSum, nu ) * exp (kP * yCp[i] + kS * yCp[0 ])
275
- - kA * yCp[i] * pow (qSum, nu ) * exp (kP * yCp[i] + kS * yCp[0 ]) * kP ;
308
+ jac[i - bndIdx - offsetCp] = -kApH * pow (qSum, nupH ) * exp (kP * yCp[i] + kS * yCp[0 ])
309
+ - kApH * yCp[i] * pow (qSum, nupH ) * exp (kP * yCp[i] + kS * yCp[0 ]) * kP ;
276
310
// Getting to c_{p,i}: -bndIdx takes us to q_0, another -offsetCp to c_{p,0} and a +i to c_{p,i}.
277
311
// This means jac[i - bndIdx - offsetCp] corresponds to c_{p,i}.
278
312
@@ -286,14 +320,14 @@ namespace cadet
286
320
continue ;
287
321
288
322
// dres_i / dq_j
289
- jac[bndIdx2 - bndIdx] = kA * yCp[i] * nu * pow (qSum, nu - 1 ) / (static_cast <double >(_p->qMax [j])) * exp (kP * yCp[i] + kS * yCp[0 ]);
323
+ jac[bndIdx2 - bndIdx] = kApH * yCp[i] * nupH * pow (qSum, nupH - 1 ) / (static_cast <double >(_p->qMax [j])) * exp (kP * yCp[i] + kS * yCp[0 ]);
290
324
// Getting to q_j: -bndIdx takes us to q_0, another +bndIdx2 to q_j. This means jac[bndIdx2 - bndIdx] corresponds to q_j.
291
325
292
326
++bndIdx2;
293
327
}
294
328
295
329
// Add to dres_i / dq_i
296
- jac[0 ] += (1 + 2 * epsilon * y[bndIdx]) * kD * pow (water_activity, nu * beta);
330
+ jac[0 ] += (1 + 2 * epsilon * y[bndIdx]) * kD * pow (water_activity, nupH * beta);
297
331
298
332
// Advance to next flux and Jacobian row
299
333
++bndIdx;
0 commit comments