Use a piecewise cubic polynomial for charateristic charge in GIEX adsorption model#97
Use a piecewise cubic polynomial for charateristic charge in GIEX adsorption model#97sleweke wants to merge 8 commits into
Conversation
|
Thanks for putting this together! I pulled and it compiled fine. However, if I try to run it, it does not seem to read the parameters properly. I went in and printed the values and I got 120 for GIEX_NU, and 0 for GIEX_NU_LIN although I did provide the parameters correctly (see attached file). Maybe it's because of the 'skipConfig' flag? |
|
There were some bugs (mostly copy & paste), as well as a conceptual problem:
Indeed, that was the case. The validation code ran before the custom parameter reading code. The provided test file has |
| // Check breaks | ||
| for (int i = 0; i < nComp; ++i) | ||
| { | ||
| cadet::active const* const b = _nuBreaks.get().data() + nPieces * i; |
There was a problem hiding this comment.
Since there are nPieces + 1 breaks for each component, I think this line should read
cadet::active const* const b = _nuBreaks.get().data() + (nPieces + 1) * i;
Otherwise the exception is thrown.
| **Type:** double **Length:** NCOMP | ||
| =================== ========================= | ||
| =================== =============================== | ||
| **Type:** double **Length:** multiples of NCOMP |
There was a problem hiding this comment.
Is this really NCOMP or rather NBOUND?
There was a problem hiding this comment.
It's NCOMP. Each component has at most 1 bound state. Entries of non-binding components are ignored (but must be present just in the other adsorption models).
There was a problem hiding this comment.
Ok, good! Otherwise setting up the config would be a nightmare! ^^
Lucky guess! ^^
Oh, I sent you the wrong file... Here is a new one that runs. However, I'm not sure yet that it works properly. Here is another one where I tried to use the old interface but it does not run ( |
|
I noticed that the total resin capacity seems to be exceeded sometimes. For example, if you check even though lambda is only 3000. I don't seem to have the same issue if I use only one global polynomial. |
|
Note that the formula for the Maybe the visualization code is wrong: #!/usr/bin/env python3
import h5py
import matplotlib.pyplot as plt
import numpy as np
with h5py.File('giex_check_lambda.h5', 'r') as f:
nu_const = f['/input/model/unit_003/adsorption/GIEX_NU'][()]
nu_lin = f['/input/model/unit_003/adsorption/GIEX_NU_LIN'][()]
nu_quad = f['/input/model/unit_003/adsorption/GIEX_NU_QUAD'][()]
nu_cube = f['/input/model/unit_003/adsorption/GIEX_NU_CUBE'][()]
nu_breaks = f['/input/model/unit_003/adsorption/GIEX_NU_BREAKS'][()]
n_comp = f['/input/model/unit_003/NCOMP'][()]
n_pieces = int(len(nu_const) / n_comp)
print('Comp {} Pieces {}'.format(n_comp, n_pieces))
n_per_piece = 100
fig, axs = plt.subplots(2, 3)
axs = axs.reshape((6,))
for i in range(n_comp):
breaks = nu_breaks[(n_pieces+1)*i:(n_pieces+1)*(i+1)]
con = nu_const[n_pieces * i:n_pieces*(i+1)]
lin = nu_const[n_pieces * i:n_pieces*(i+1)]
quad = nu_const[n_pieces * i:n_pieces*(i+1)]
cube = nu_const[n_pieces * i:n_pieces*(i+1)]
x = np.empty((n_per_piece * n_pieces,))
y = np.empty((n_per_piece * n_pieces,))
for j in range(n_pieces):
x[n_per_piece * j: n_per_piece * (j+1)] = np.linspace(breaks[j], breaks[j+1], n_per_piece)
t = x[n_per_piece * j: n_per_piece * (j+1)] - breaks[j]
y[n_per_piece * j: n_per_piece * (j+1)] = con[j] + t * (lin[j] + t * (quad[j] + t * cube[j]))
axs[i].plot(x,y)
axs[i].set_title('Component {}'.format(i))
plt.show() |
|
I think there is an issue with the variable names here:
If you update to: It seems alright. |
|
I assume most if not all applications will be based on cubic splines. However, the user needs to take care of the continuity and boundary conditions at the nodes, which can be tedious and error prone. In addition, it complicates parameter estimation from measurement data. Have you considered using a different parameterization, e.g. a series of x and y values of the interpolated function with natural boundary conditions? |
As far as I know, this was not considered. However, to get the polynomial coefficients, I simply used scipy's cubic splines module which are already twice continuously differentiable. Nevertheless, I still can't get it to run properly. It gets stuck shortly after a section boundary. @sleweke Is it already considered that negative nu should be ignored? |
1977401 to
b1601b1
Compare
b1601b1 to
72dea22
Compare
Adds a vector valued and a vector valued component dependent parameter class. The ordering of the latter is component-major (i.e., component index changes the slowest). The reaction index is used for the vector element index in the ParameterId.
The characteristic charge nu is extended to a piecewise cubic polynomial in the GIEX adsorption model. The nu of each component can have different polynomial coefficients and breaks, but their amount must be the same over all components. If the breaks are not provided, a single global polynomial is applied. This maintains backwards compatibility.
Renames the validateConfig() function in the parameter handler to validate() and makes it public. Splits configure() into configure() and configureAndValidate(). This allows more fine-grained control, especially in situations where adsorption models require custom configuration code.
Renames the validateConfig() function in the parameter handler to validate() and makes it public. Splits configure() into configure() and configureAndValidate(). This allows more fine-grained control, especially in situations where reaction models require custom configuration code.
Fixes copy and paste bugs in reading optional parameters of the GIEX adsorption model. Also adds a check for strict monotonicity of the polynomial breaks.
Fixes some more bugs in the GIEX adsorption model.
Number of spline pieces was fundamentally wrong.
72dea22 to
d804b30
Compare

The characteristic charge nu is extended to a piecewise cubic polynomial in the GIEX adsorption model. The nu of each component can have different polynomial coefficients and breaks, but their amount must be the same over all components.
If the breaks are not provided, a single global polynomial is applied. This maintains backwards compatibility.
The code compiles but is untested. Only the file format docs have been added.