Skip to content

Note

Click here to download the full example code

Usage of the model-versus-data code verification tool on a Finite-Element (Abaqus) model

Check an Abaqus cantilever beam model versus a reference dataset with the 'CodeVerificationAgainstData' tool.

from __future__ import annotations

import logging

from gemseo.datasets.io_dataset import IODataset
from gemseo.utils.directory_creator import DirectoryNamingMethod

from vimseo import EXAMPLE_RUNS_DIR
from vimseo.api import activate_logger
from vimseo.api import create_model
from vimseo.core.model_settings import IntegratedModelSettings
from vimseo.tools.verification.verification_vs_data import CodeVerificationAgainstData

We first define the logger level:

activate_logger(level=logging.INFO)

Then we create the model to verify:

model_name = "BendingTestAnalytical"
load_case = "Cantilever"
model = create_model(
    model_name,
    load_case,
    model_options=IntegratedModelSettings(
        directory_archive_root=EXAMPLE_RUNS_DIR / "archive/verification_vs_data",
        directory_scratch_root=EXAMPLE_RUNS_DIR / "scratch/verification_vs_data",
        cache_file_path=EXAMPLE_RUNS_DIR
        / f"caches/verification_vs_data/{model_name}_{load_case}_cache.hdf",
    ),
)

Out:

    INFO - 23:52:41: Found 2 entries in the cache file : C:\Users\sebastien.bocquet\Dev\vimseo\docs\runnable_examples\model_runs\caches\verification_vs_data\BendingTestAnalytical_Cantilever_cache.hdf node : node

We also need a reference dataset. Here we do it programmatically, but we can also create it from a csv file: ``

reference_data = IODataset().from_array(
    data=[[10.0, 10.0, -4.0, -12.0], [15.0, 10.0, -6.0, -40.0]],
    variable_names=["height", "width", "maximum_dplt", "reaction_forces"],
    variable_names_to_group_names={
        "height": "inputs",
        "width": "inputs",
        "maximum_dplt": "outputs",
        "reaction_forces": "outputs",
    },
)

All inputs to the verification are now available. We create the verification tool we are interested in.

verificator = CodeVerificationAgainstData(
    directory_naming_method=DirectoryNamingMethod.NUMBERED,
    working_directory="CodeVerificationAgainstData_results",
)

# The options can be modified.
# Alternatively, options can be passed as keyword arguments to
# ``CodeVerificationAgainstModelFromParameterSpace()`` constructor.
verificator.options["metric_names"] = [
    "SquaredErrorMetric",
    "RelativeErrorMetric",
    "AbsoluteErrorMetric",
]

verificator.execute(
    model=model,
    reference_data=reference_data,
    output_names=["maximum_dplt", "reaction_forces"],
    description={
        "title": "Verification of a cantilever analytic beam for a variation of beam height.",
        "element_wise": ["Small height value", "High height value"],
    },
)

Out:

    INFO - 23:52:41: Working directory is C:\Users\sebastien.bocquet\Dev\vimseo\docs\runnable_examples\03_verification_vs_data\CodeVerificationAgainstData_results
    INFO - 23:52:41: Working directory is C:\Users\sebastien.bocquet\Dev\vimseo\docs\runnable_examples\03_verification_vs_data\CodeVerificationAgainstData_results\CustomDOETool
    INFO - 23:52:41: Working directory is C:\Users\sebastien.bocquet\Dev\vimseo\docs\runnable_examples\03_verification_vs_data\CodeVerificationAgainstData_results\CustomDOETool
    INFO - 23:52:41:  
    INFO - 23:52:41: *** Start DOEScenario execution ***
    INFO - 23:52:41: DOEScenario
    INFO - 23:52:41:    Disciplines: Model BendingTestAnalytical:  An analytical model for the bending of a parallelepipedic beam
    INFO - 23:52:41: 
    INFO - 23:52:41: Load case:
    INFO - 23:52:41:    Load case Cantilever: A cantilever load case.
    INFO - 23:52:41:    
    INFO - 23:52:41:    Boundary condition variables:
    INFO - 23:52:41:    ['imposed_dplt', 'relative_dplt_location']
    INFO - 23:52:41:    
    INFO - 23:52:41:    Plot parameters:
    INFO - 23:52:41:    {
    INFO - 23:52:41:     "curves": []
    INFO - 23:52:41: }
    INFO - 23:52:41:    Load:
    INFO - 23:52:41:    Load(direction='', sign='', type='')
    INFO - 23:52:41: 
    INFO - 23:52:41: Default values:
    INFO - 23:52:41:    
    INFO - 23:52:41:    Default geometrical variables:
    INFO - 23:52:41:    {"height": [40.0], "length": [600.0], "width": [30.0]}
    INFO - 23:52:41:    
    INFO - 23:52:41:    Default numerical variables:
    INFO - 23:52:41:    {}
    INFO - 23:52:41:    
    INFO - 23:52:41:    Default boundary conditions variables:
    INFO - 23:52:41:    {"imposed_dplt": [-5.0], "relative_dplt_location": [1.0]}
    INFO - 23:52:41:    
    INFO - 23:52:41:    Default material variables:
    INFO - 23:52:41:    {"nu_p": [0.3], "young_modulus": [210000.0]}
    INFO - 23:52:41: model_inputs:
    INFO - 23:52:41:    [
    INFO - 23:52:41:     "length",
    INFO - 23:52:41:     "width",
    INFO - 23:52:41:     "height",
    INFO - 23:52:41:     "imposed_dplt",
    INFO - 23:52:41:     "relative_dplt_location",
    INFO - 23:52:41:     "young_modulus",
    INFO - 23:52:41:     "nu_p"
    INFO - 23:52:41: ]
    INFO - 23:52:41: model_outputs:
    INFO - 23:52:41:    [
    INFO - 23:52:41:     "reaction_forces",
    INFO - 23:52:41:     "moment",
    INFO - 23:52:41:     "moment_grid",
    INFO - 23:52:41:     "dplt",
    INFO - 23:52:41:     "dplt_grid",
    INFO - 23:52:41:     "maximum_dplt",
    INFO - 23:52:41:     "location_max_dplt",
    INFO - 23:52:41:     "dplt_at_force_location",
    INFO - 23:52:41:     "model",
    INFO - 23:52:41:     "load_case",
    INFO - 23:52:41:     "error_code",
    INFO - 23:52:41:     "description",
    INFO - 23:52:41:     "job_name",
    INFO - 23:52:41:     "persistent_result_files",
    INFO - 23:52:41:     "n_cpus",
    INFO - 23:52:41:     "date",
    INFO - 23:52:41:     "cpu_time",
    INFO - 23:52:41:     "user",
    INFO - 23:52:41:     "machine",
    INFO - 23:52:41:     "vims_git_version",
    INFO - 23:52:41:     "directory_archive_root",
    INFO - 23:52:41:     "directory_archive_job",
    INFO - 23:52:41:     "directory_scratch_root",
    INFO - 23:52:41:     "directory_scratch_job"
    INFO - 23:52:41: ]
    INFO - 23:52:41:    MDO formulation: DisciplinaryOpt
    INFO - 23:52:41: Optimization problem:
    INFO - 23:52:41:    minimize maximum_dplt(height, width)
    INFO - 23:52:41:    with respect to height, width
    INFO - 23:52:41:    over the design space:
    INFO - 23:52:41:       +--------+-------------+-------+-------------+-------+
    INFO - 23:52:41:       | Name   | Lower bound | Value | Upper bound | Type  |
    INFO - 23:52:41:       +--------+-------------+-------+-------------+-------+
    INFO - 23:52:41:       | height |     -inf    |  None |     inf     | float |
    INFO - 23:52:41:       | width  |     -inf    |  None |     inf     | float |
    INFO - 23:52:41:       +--------+-------------+-------+-------------+-------+
    INFO - 23:52:41: Solving optimization problem with algorithm CustomDOE:
    INFO - 23:52:41:     50%|█████     | 1/2 [00:00<00:00, 12.60 it/sec, obj=-5]
    INFO - 23:52:41:    100%|██████████| 2/2 [00:00<00:00, 17.30 it/sec, obj=-5]
    INFO - 23:52:41: Optimization result:
    INFO - 23:52:41:    Optimizer info:
    INFO - 23:52:41:       Status: None
    INFO - 23:52:41:       Message: None
    INFO - 23:52:41:       Number of calls to the objective function by the optimizer: 2
    INFO - 23:52:41:    Solution:
    INFO - 23:52:41:       Objective: -4.999999999999999
    INFO - 23:52:41:       Design space:
    INFO - 23:52:41:          +--------+-------------+-------+-------------+-------+
    INFO - 23:52:41:          | Name   | Lower bound | Value | Upper bound | Type  |
    INFO - 23:52:41:          +--------+-------------+-------+-------------+-------+
    INFO - 23:52:41:          | height |     -inf    |   10  |     inf     | float |
    INFO - 23:52:41:          | width  |     -inf    |   10  |     inf     | float |
    INFO - 23:52:41:          +--------+-------------+-------+-------------+-------+
    INFO - 23:52:41: *** End DOEScenario execution (time: 0:00:00.123067) ***

VerificationResult(metadata=ToolResultMetadata(generic={'datetime': '03-09-2026_23-52-41', 'version': '0.1.7.dev12+gb7d116037'}, misc={}, settings={'input_names': [], 'output_names': ['maximum_dplt', 'reaction_forces'], 'metric_names': ['SquaredErrorMetric', 'RelativeErrorMetric', 'AbsoluteErrorMetric'], 'description': {'title': 'Verification of a cantilever analytic beam for a variation of beam height.', 'element_wise': ['Small height value', 'High height value']}}, report={}, model=ModelDescription(name='BendingTestAnalytical', summary=' An analytical model for the bending of a parallelepipedic beam', load_case=Beam_Cantilever(name='Cantilever', domain='Beam', summary='A cantilever load case.', plot_parameters=PlotParameters(curves=[]), bc_variable_names=['imposed_dplt', 'relative_dplt_location'], load=Load(direction='', sign='', type='')), dataflow={'model_inputs': ['length', 'width', 'height', 'imposed_dplt', 'relative_dplt_location', 'young_modulus', 'nu_p'], 'model_outputs': ['reaction_forces', 'moment', 'moment_grid', 'dplt', 'dplt_grid', 'maximum_dplt', 'location_max_dplt', 'dplt_at_force_location', 'model', 'load_case', 'error_code', 'description', 'job_name', 'persistent_result_files', 'n_cpus', 'date', 'cpu_time', 'user', 'machine', 'vims_git_version', 'directory_archive_root', 'directory_archive_job', 'directory_scratch_root', 'directory_scratch_job'], 'PreBendingTestAnalytical_Cantilever': {'inputs': ['length', 'width', 'height', 'imposed_dplt', 'relative_dplt_location', 'young_modulus', 'nu_p'], 'outputs': ['imposed_dplt_location', 'quadratic_moment', 'reaction_forces', 'moment', 'moment_grid', 'solver', 'boundary']}, 'RunBendingTestAnalytical': {'inputs': ['solver', 'boundary', 'moment', 'moment_grid', 'young_modulus', 'quadratic_moment', 'nu_p'], 'outputs': ['dplt', 'dplt_grid']}, 'PostBendingTestAnalytical_Cantilever': {'inputs': ['dplt', 'dplt_grid', 'moment', 'moment_grid', 'imposed_dplt_location', 'reaction_forces'], 'outputs': ['reaction_forces', 'maximum_dplt', 'dplt_grid', 'location_max_dplt', 'dplt', 'moment', 'moment_grid', 'dplt_at_force_location']}, 'subroutine_names': []}, default_inputs={<InputGroupNames.NUMERICAL_VARS: 'numerical variables'>: {}, <InputGroupNames.BC_VARS: 'boundary conditions variables'>: {'imposed_dplt': [-5.0], 'relative_dplt_location': [1.0]}, <InputGroupNames.GEOMETRICAL_VARS: 'geometrical variables'>: {'length': [600.0], 'width': [30.0], 'height': [40.0]}, <InputGroupNames.MATERIAL_VARS: 'material variables'>: {'young_modulus': [210000.0], 'nu_p': [0.3]}}, curves=[('dplt_grid', 'dplt'), ('moment_grid', 'moment')], verbose=False)), simulation_and_reference=GROUP     inputs         outputs                                 Reference                
VARIABLE  height width  cpu_time maximum_dplt reaction_forces maximum_dplt reaction_forces
COMPONENT      0     0         0            0               0            0               0
0           10.0  10.0  0.033884         -5.0      -12.152778         -4.0           -12.0
1           15.0  10.0  0.010976         -5.0      -41.015625         -6.0           -40.0, element_wise_metrics=GROUP     SquaredErrorMetric                 RelativeErrorMetric                 AbsoluteErrorMetric                 inputs      
VARIABLE        maximum_dplt reaction_forces        maximum_dplt reaction_forces        maximum_dplt reaction_forces height width
COMPONENT                  0               0                   0               0                   0               0      0     0
0                        1.0        0.023341            0.250000        0.012731                 1.0        0.152778   10.0  10.0
1                        1.0        1.031494            0.166667        0.025391                 1.0        1.015625   15.0  10.0, integrated_metrics={'SquaredErrorMetric': {'maximum_dplt': 1.0000000000000009, 'reaction_forces': 0.5274175950038581}, 'RelativeErrorMetric': {'maximum_dplt': 0.20833333328819448, 'reaction_forces': 0.019061053239892913}, 'AbsoluteErrorMetric': {'maximum_dplt': 1.0000000000000004, 'reaction_forces': 0.5842013888888893}}, description={'title': 'Verification of a cantilever analytic beam for a variation of beam height.', 'element_wise': ['Small height value', 'High height value']})

The result contains the error metrics:

verificator.result.integrated_metrics

Out:

{'SquaredErrorMetric': {'maximum_dplt': 1.0000000000000009, 'reaction_forces': 0.5274175950038581}, 'RelativeErrorMetric': {'maximum_dplt': 0.20833333328819448, 'reaction_forces': 0.019061053239892913}, 'AbsoluteErrorMetric': {'maximum_dplt': 1.0000000000000004, 'reaction_forces': 0.5842013888888893}}

And saved on disk, together with its metadata:

verificator.save_results()

Out:

    INFO - 23:52:41: Saving result to C:\Users\sebastien.bocquet\Dev\vimseo\docs\runnable_examples\03_verification_vs_data\CodeVerificationAgainstData_results\CodeVerificationAgainstData_result.hdf5
    INFO - 23:52:41: Saving result to C:\Users\sebastien.bocquet\Dev\vimseo\docs\runnable_examples\03_verification_vs_data\CodeVerificationAgainstData_results\CustomDOETool\CustomDOETool_result.hdf5

The saved results can be loaded in a dedicated dashboard to be explored. The dashboard is opened by typing dashboard_verification in a terminal, and selecting the tab Comparison case.

The results can also be plotted from the Python API. It shows the scatter matrix of the inputs:

figures = verificator.plot_results(
    verificator.result,
    "RelativeErrorMetric",
    "reaction_forces",
    save=False,
    show=True,
    directory_path=verificator.working_directory,
)

plot bending test vs data

Out:

C:\Users\sebastien.bocquet\Dev\vimseo\.tox\doc\Lib\site-packages\pandas\plotting\_matplotlib\misc.py:100: UserWarning:

Attempting to set identical low and high xlims makes transformation singular; automatically expanding.

C:\Users\sebastien.bocquet\Dev\vimseo\.tox\doc\Lib\site-packages\pandas\plotting\_matplotlib\misc.py:101: UserWarning:

Attempting to set identical low and high ylims makes transformation singular; automatically expanding.

C:\Users\sebastien.bocquet\Dev\vimseo\.tox\doc\Lib\site-packages\pandas\plotting\_matplotlib\misc.py:91: UserWarning:

Attempting to set identical low and high xlims makes transformation singular; automatically expanding.

C:\Users\sebastien.bocquet\Dev\vimseo\.tox\doc\Lib\site-packages\gemseo\utils\matplotlib_figure.py:59: UserWarning:

FigureCanvasAgg is non-interactive, and thus cannot be shown

    INFO - 23:52:42: Working directory is C:\Users\sebastien.bocquet\Dev\vimseo\docs\runnable_examples\03_verification_vs_data\CodeVerificationAgainstData_results
{'text/html': '<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: \'local\'};</script>\n        <script charset="utf-8" src="https://cdn.plot.ly/plotly-2.35.0.min.js"></script>                <div id="15161715-426b-429a-abb7-bb81c7bba2e9" class="plotly-graph-div" style="height:525px; width:100%;"></div>            <script type="text/javascript">                                    window.PLOTLYENV=window.PLOTLYENV || {};                                    if (document.getElementById("15161715-426b-429a-abb7-bb81c7bba2e9")) {                    Plotly.newPlot(                        "15161715-426b-429a-abb7-bb81c7bba2e9",                        [{"alignmentgroup":"True","bingroup":"x","hovertemplate":"reaction_forces=%{x}\\u003cbr\\u003ecount=%{y}\\u003cextra\\u003e\\u003c\\u002fextra\\u003e","legendgroup":"","marker":{"color":"#000001","pattern":{"shape":""}},"name":"","offsetgroup":"","orientation":"v","showlegend":false,"x":[0.01273148148042059,0.025390624999365237],"xaxis":"x","yaxis":"y","type":"histogram"}],                        {"template":{"data":{"candlestick":[{"decreasing":{"line":{"color":"#000033"}},"increasing":{"line":{"color":"#000032"}},"type":"candlestick"}],"contourcarpet":[{"colorscale":[[0.0,"#000011"],[0.1111111111111111,"#000012"],[0.2222222222222222,"#000013"],[0.3333333333333333,"#000014"],[0.4444444444444444,"#000015"],[0.5555555555555556,"#000016"],[0.6666666666666666,"#000017"],[0.7777777777777778,"#000018"],[0.8888888888888888,"#000019"],[1.0,"#000020"]],"type":"contourcarpet"}],"contour":[{"colorscale":[[0.0,"#000011"],[0.1111111111111111,"#000012"],[0.2222222222222222,"#000013"],[0.3333333333333333,"#000014"],[0.4444444444444444,"#000015"],[0.5555555555555556,"#000016"],[0.6666666666666666,"#000017"],[0.7777777777777778,"#000018"],[0.8888888888888888,"#000019"],[1.0,"#000020"]],"type":"contour"}],"heatmap":[{"colorscale":[[0.0,"#000011"],[0.1111111111111111,"#000012"],[0.2222222222222222,"#000013"],[0.3333333333333333,"#000014"],[0.4444444444444444,"#000015"],[0.5555555555555556,"#000016"],[0.6666666666666666,"#000017"],[0.7777777777777778,"#000018"],[0.8888888888888888,"#000019"],[1.0,"#000020"]],"type":"heatmap"}],"histogram2d":[{"colorscale":[[0.0,"#000011"],[0.1111111111111111,"#000012"],[0.2222222222222222,"#000013"],[0.3333333333333333,"#000014"],[0.4444444444444444,"#000015"],[0.5555555555555556,"#000016"],[0.6666666666666666,"#000017"],[0.7777777777777778,"#000018"],[0.8888888888888888,"#000019"],[1.0,"#000020"]],"type":"histogram2d"}],"icicle":[{"textfont":{"color":"white"},"type":"icicle"}],"sankey":[{"textfont":{"color":"#000036"},"type":"sankey"}],"scatter":[{"marker":{"line":{"width":0}},"type":"scatter"}],"table":[{"cells":{"fill":{"color":"#000038"},"font":{"color":"#000037"},"line":{"color":"#000039"}},"header":{"fill":{"color":"#000040"},"font":{"color":"#000036"},"line":{"color":"#000039"}},"type":"table"}],"waterfall":[{"connector":{"line":{"color":"#000036","width":2}},"decreasing":{"marker":{"color":"#000033"}},"increasing":{"marker":{"color":"#000032"}},"totals":{"marker":{"color":"#000034"}},"type":"waterfall"}]},"layout":{"coloraxis":{"colorscale":[[0.0,"#000011"],[0.1111111111111111,"#000012"],[0.2222222222222222,"#000013"],[0.3333333333333333,"#000014"],[0.4444444444444444,"#000015"],[0.5555555555555556,"#000016"],[0.6666666666666666,"#000017"],[0.7777777777777778,"#000018"],[0.8888888888888888,"#000019"],[1.0,"#000020"]]},"colorscale":{"diverging":[[0.0,"#000021"],[0.1,"#000022"],[0.2,"#000023"],[0.3,"#000024"],[0.4,"#000025"],[0.5,"#000026"],[0.6,"#000027"],[0.7,"#000028"],[0.8,"#000029"],[0.9,"#000030"],[1.0,"#000031"]],"sequential":[[0.0,"#000011"],[0.1111111111111111,"#000012"],[0.2222222222222222,"#000013"],[0.3333333333333333,"#000014"],[0.4444444444444444,"#000015"],[0.5555555555555556,"#000016"],[0.6666666666666666,"#000017"],[0.7777777777777778,"#000018"],[0.8888888888888888,"#000019"],[1.0,"#000020"]],"sequentialminus":[[0.0,"#000011"],[0.1111111111111111,"#000012"],[0.2222222222222222,"#000013"],[0.3333333333333333,"#000014"],[0.4444444444444444,"#000015"],[0.5555555555555556,"#000016"],[0.6666666666666666,"#000017"],[0.7777777777777778,"#000018"],[0.8888888888888888,"#000019"],[1.0,"#000020"]]},"colorway":["#000001","#000002","#000003","#000004","#000005","#000006","#000007","#000008","#000009","#000010"]}},"xaxis":{"anchor":"y","domain":[0.0,1.0],"title":{"text":"reaction_forces"}},"yaxis":{"anchor":"x","domain":[0.0,1.0],"title":{"text":"count"}},"legend":{"tracegroupgap":0},"margin":{"t":60},"barmode":"relative"},                        {"responsive": true}                    )                };                            </script>        </div>'}

and an histogram of the errors:

figures["error_metric_histogram"]

Total running time of the script: ( 0 minutes 1.559 seconds)

Download Python source code: plot_bending_test_vs_data.py

Download Jupyter notebook: plot_bending_test_vs_data.ipynb

Gallery generated by mkdocs-gallery