Critical-state-line calibration utility¶
The CSL calibration helper is available as
It is a standalone utility. You can run it before a full ACT optimization to obtain initial or fixed critical-state-line parameters for hypoplastic or SANISAND-family models.
What the function does
fit_csl(...) fits a critical-state-line model, returns the fitted parameters in a dictionary, prints the result to the command prompt, plots the measured/generated data against the fitted line, saves the figure in the selected result directory and writes a small csl_fit_*.dat file that is automatically inserted into the ACT PDF report.
Supported CSL equations¶
Bauer CSL¶
Use model='bauer' for the Bauer CSL used by the hypoplastic family:
In the ACT Python interface, \(p\) is provided in kPa and the fitted hs value is returned in GPa, consistent with the hypoplastic ACT model classes.
The returned parameters are:
Li-Wang CSL¶
Use model='li-wang' for the Li-Wang CSL used by the SANISAND-family models:
The returned parameters are:
Input mode 1: direct \(p\)-\(e\) data¶
Use this mode when your data already contain mean effective stress \(p\) and void ratio \(e\).
from ACT.utilities.csl import fit_csl
result = fit_csl(
model='bauer',
p=[25., 50., 100., 200., 400.],
e=[0.91, 0.88, 0.85, 0.82, 0.79],
result_dir=model.out_dir,
)
params = result['parameters']
ec0 = params['ec0']
hs = params['hs']
n = params['n']
print(ec0, hs, n)
print(result['r2'])
Do not index result['parameters'] like a list
result['parameters'] is a dictionary. Therefore this is wrong:
Use the parameter names instead:
Input mode 2: oedometric compression data¶
Use this mode when your input data are vertical effective stress, \(K_0\) and void ratio, or vertical effective stress, \(K_0\), axial strain and initial void ratio. ACT converts the vertical stress to mean effective stress by
K0 can be a scalar or an array with one value per stress point.
import numpy as np
from ACT.utilities.csl import fit_csl
phic = 33.0
K0 = 1. - np.sin(phic*np.pi/180.)
result = fit_csl(
model='bauer',
vertical_stress=[25., 50., 100., 200., 400.],
K0=K0,
void_ratio=[0.91, 0.88, 0.85, 0.82, 0.79],
result_dir=model.out_dir,
)
params = result['parameters']
ec0 = params['ec0']
hs = params['hs']
n = params['n']
Oedometer data from stress-strain records¶
The ACT Excel database stores oedometric compression tests as vertical stress and axial strain. You can therefore pass the measured strain directly. e_initial may be a scalar or an array with one initial void ratio per strain value. ACT converts the strain to void ratio by
for the usual ACT sign convention where compressive oedometric strain is positive.
import numpy as np
from ACT.utilities.csl import fit_csl
phic = 37.0
K0 = 1. - np.sin(phic*np.pi/180.)
result = fit_csl(
model='bauer',
vertical_stress=sigma_v, # measured oedometric stress in kPa
K0=K0,
strain=eps_ax, # measured oedometric strain dh/h0
e_initial=0.359, # initial void ratio from the OED sheet
result_dir=model.out_dir,
)
params = result['parameters']
model.ec0 = params['ec0']
model.hs = params['hs']
model.n = params['n']
strain and axial_strain are synonyms. e_initial and initial_void_ratio are synonyms.
Loading-unloading-reloading oedometer data¶
Loading-unloading-reloading curves should normally not be fitted point-by-point for CSL/compression-law calibration. At the same stress level, unloading and reloading points represent a different stress history and a different reversible/irreversible strain split. Including all points would over-weight unloading loops, hold phases and repeated stress levels.
For oedometric input, the default evaluation='auto' detects a non-monotonic stress path and fits the virgin loading envelope instead. Internally ACT keeps points close to the historical maximum stress path and then retains the lowest void ratio in logarithmic stress bins. This gives a monotonic compression envelope suitable for Bauer/Li-Wang CSL fitting.
result = fit_csl(
model='bauer',
vertical_stress=sigma_v,
K0=K0,
strain=eps_ax,
e_initial=e0,
evaluation='auto', # default; detects LUR and uses the envelope
envelope_bins=50, # number of logarithmic stress bins for the envelope
stress_tolerance=0.005, # relative tolerance for recognising the max-stress path
result_dir=model.out_dir,
)
If you deliberately want to fit every single point, including unloading and reloading branches, set
result = fit_csl(
model='bauer',
vertical_stress=sigma_v,
K0=K0,
strain=eps_ax,
e_initial=e0,
evaluation='all',
result_dir=model.out_dir,
)
This is usually not recommended for CSL/compression-law calibration from LUR tests.
vertical_stress and sigma_v are synonyms. The following call is equivalent:
result = fit_csl(
model='bauer',
sigma_v=[25., 50., 100., 200., 400.],
K0=K0,
void_ratio=[0.91, 0.88, 0.85, 0.82, 0.79],
result_dir=model.out_dir,
)
Directly from collected ACT oedometer tests¶
When the experimental database has already been collected, you can also pass the ACT oedometer test objects directly. This is useful when several oedometer tests with different initial void ratios should be evaluated together.
import numpy as np
from ACT.utilities.csl import fit_csl_oedometer_tests
phic = 37.0
K0 = 1. - np.sin(phic*np.pi/180.)
result = fit_csl_oedometer_tests(
db.oedometer, # list of ACT oedometer test objects
model='bauer',
K0=K0,
evaluation='auto',
envelope_bins=50,
result_dir=model.out_dir,
)
params = result['parameters']
model.ec0 = params['ec0']
model.hs = params['hs']
model.n = params['n']
The wrapper concatenates test.stress and test.strain and uses the first value of test.void as the initial void ratio for each test. The actual fitting is still performed by fit_csl(...).
Input mode 3: Bolton-generated CSL points¶
Use this mode when no measured CSL points are available and you want to generate a first estimate from \(e_{\max}\), \(e_{\min}\), \(Q\) and \(R\):
from ACT.utilities.csl import fit_csl
result = fit_csl(
model='bauer',
emax=0.977,
emin=0.605,
Q=9.15,
R=0.77,
p_min=10.,
p_max=1000.,
n_points=30,
result_dir=model.out_dir,
)
params = result['parameters']
ec0 = params['ec0']
hs = params['hs']
n = params['n']
You can also provide your own pressure vector:
result = fit_csl(
model='bauer',
p=[25., 50., 100., 200., 400.],
emax=0.977,
emin=0.605,
Q=9.15,
R=0.77,
result_dir=model.out_dir,
)
Example: Li-Wang¶
For SANISAND-family models, use model='li-wang' and read the Li-Wang parameter names:
from ACT.utilities.csl import fit_csl
result = fit_csl(
model='li-wang',
p=[25., 50., 100., 200., 400.],
e=[0.91, 0.88, 0.85, 0.82, 0.79],
result_dir=model.out_dir,
)
params = result['parameters']
e0 = params['e0']
lambdac = params['lambdac']
xi = params['xi']
print(e0, lambdac, xi)
print(result['r2'])
Updating an ACT model object directly¶
If the ACT model object has matching parameter names, fit_csl(...) can write the fitted parameters directly to the model instance:
from ACT.models import hypoplasticity
from ACT.utilities.csl import fit_csl
model = hypoplasticity()
result = fit_csl(
model='bauer',
p=[25., 50., 100., 200., 400.],
e=[0.91, 0.88, 0.85, 0.82, 0.79],
result_dir=model.out_dir,
update_model=model,
)
print(model.ec0)
print(model.hs)
print(model.n)
For Li-Wang fits, lambdac is also written to lambda_c if the target model uses that SANISAND naming convention.
Returned dictionary¶
The returned object has the following structure:
{
'type': 'csl_fit',
'created': '...',
'model': 'Bauer',
'input_source': '...',
'n_points': 5,
'raw_points': 5,
'evaluation': 'all data points',
'parameters': {'ec0': ..., 'hs': ..., 'n': ...},
'r2': ...,
'patm': 100.0,
'p': array([...]),
'e_exp': array([...]),
'e_fit': array([...]),
'p_raw': array([...]),
'e_raw': array([...]),
'figure': './results/csl_fit_bauer.png',
'report_file': './results/csl_fit_bauer_....dat',
}
The most commonly used entries are:
| Entry | Meaning |
|---|---|
result['parameters'] |
dictionary with fitted CSL parameters |
result['r2'] |
coefficient of determination of the CSL fit |
result['evaluation'] |
evaluation mode used for the fitted data, for example all data points or virgin loading envelope |
result['n_points'] |
number of selected points used for the fit |
result['raw_points'] |
number of raw input points before envelope selection |
result['p'] |
stress points actually used for the fit |
result['e_exp'] |
input or generated void-ratio values |
result['e_fit'] |
fitted void-ratio values at the same stress points |
result['p_raw'] |
raw stress points before envelope selection |
result['e_raw'] |
raw void-ratio values before envelope selection |
result['figure'] |
saved PNG figure |
result['report_file'] |
plain-text ACT report-data file |
Report integration¶
Each call creates these files in result_dir:
The .dat file is a plain ACT key-value text file. During report generation, ACT.utilities.reporting.write_pdf_report(...) searches the result directory for csl_fit_*.dat files and inserts one Critical-state-line calibration page per fit into the PDF report. The page contains the settings, the number of raw and selected data points, the \(R^2\) value, the fitted parameters and the CSL figure. The CSL figure is not repeated again in the general result-figure section.