.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_calibration/least_squares_and_gaussian_calibration/plot_calibration_deflection_tube.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_calibration_least_squares_and_gaussian_calibration_plot_calibration_deflection_tube.py: Calibration of the deflection of a tube ======================================= In this example, we calibrate the deflection of a tube as described in the :ref:`use cases ` section. More precisely, we calibrate the mechanical parameters of a physical model which computes the vertical deflection of a tube and two deflection angles. This example shows how to calibrate a computer code which has several outputs. In this example, we use Gaussian calibration method to calibrate the parametric model. Please read :ref:`gaussian_calibration` for more details on Bayesian Gaussian calibration. This study is relatively complicated: please read the :doc:`calibration of the Chaboche mechanical model ` first if this is not already done. Variables --------- In this this model, the following list presents which variables are observed input variables, input calibrated parameters and observed output variables. * F, E: Input. Observed. * L, a, D, d: Input. Calibrated. * :math:`g_1`, :math:`g_2`, :math:`g_3`: Output. Observed. .. GENERATED FROM PYTHON SOURCE LINES 30-35 .. code-block:: Python from openturns.usecases import deflection_tube import openturns as ot import openturns.viewer as otv from matplotlib import pyplot as plt .. GENERATED FROM PYTHON SOURCE LINES 36-39 Create a calibration problem ---------------------------- We load the model from the use case module : .. GENERATED FROM PYTHON SOURCE LINES 41-45 .. code-block:: Python dt = deflection_tube.DeflectionTube() print("Inputs:", dt.model.getInputDescription()) print("Outputs:", dt.model.getOutputDescription()) .. rst-class:: sphx-glr-script-out .. code-block:: none Inputs: [F,L,a,De,di,E] Outputs: [Deflection,Left angle,Right angle] .. GENERATED FROM PYTHON SOURCE LINES 46-50 We see that there are 6 inputs: F, L, a, De, di, E and 3 outputs: Deflection, Left angle, Right angle. In this calibration example, the variables F and E are observed inputs and the input parameters L, a, De, di are calibrated. .. GENERATED FROM PYTHON SOURCE LINES 52-53 We create a sample out of our input distribution : .. GENERATED FROM PYTHON SOURCE LINES 55-59 .. code-block:: Python sampleSize = 100 inputSample = dt.inputDistribution.getSample(sampleSize) inputSample[0:5] .. raw:: html
ForceLengthLocationExternal diameterInternal diameterYoung Modulus
01.060821.510.80.1196966.1
10.87338271.510.80.1197401.2
20.95617341.510.80.1200460.7
31.1205481.510.80.1193805.3
40.78186151.510.80.1200026.5


.. GENERATED FROM PYTHON SOURCE LINES 60-61 We take the image of our input sample by the model : .. GENERATED FROM PYTHON SOURCE LINES 63-66 .. code-block:: Python outputDeflection = dt.model(inputSample) outputDeflection[0:5] .. raw:: html
DeflectionLeft angleRight angle
0-7.442589e-06-1.488518e-051.860647e-05
1-6.114042e-06-1.222808e-051.52851e-05
2-6.591451e-06-1.31829e-051.647863e-05
3-7.989849e-06-1.59797e-051.997462e-05
4-5.401521e-06-1.080304e-051.35038e-05


.. GENERATED FROM PYTHON SOURCE LINES 67-71 We now define the observed noise of the output. Since there are three observed outputs, there are three different standard deviations to define. Then we define a 3x3 covariance matrix of the observed outputs. .. GENERATED FROM PYTHON SOURCE LINES 73-78 .. code-block:: Python observationNoiseSigma = [0.1e-6, 0.5e-6, 0.5e-6] observationNoiseCovariance = ot.CovarianceMatrix(3) for i in range(3): observationNoiseCovariance[i, i] = observationNoiseSigma[i] ** 2 .. GENERATED FROM PYTHON SOURCE LINES 79-83 Finally, we define a dimension 3 normal distribution of the observed output and get a sample from it. We add this noise to the output of the model, which defines the observed output. .. GENERATED FROM PYTHON SOURCE LINES 85-90 .. code-block:: Python noiseSigma = ot.Normal([0.0, 0.0, 0.0], observationNoiseCovariance) sampleObservationNoise = noiseSigma.getSample(sampleSize) observedOutput = outputDeflection + sampleObservationNoise observedOutput[0:5] .. raw:: html
DeflectionLeft angleRight angle
0-7.356762e-06-1.533846e-051.814807e-05
1-5.99772e-06-1.207712e-051.553027e-05
2-6.543909e-06-1.357725e-051.61439e-05
3-8.003641e-06-1.646546e-051.93807e-05
4-5.258701e-06-1.109766e-051.263771e-05


.. GENERATED FROM PYTHON SOURCE LINES 91-92 We now extract the observed inputs from the input sample. .. GENERATED FROM PYTHON SOURCE LINES 94-100 .. code-block:: Python observedInput = ot.Sample(sampleSize, 2) observedInput[:, 0] = inputSample[:, 0] # F observedInput[:, 1] = inputSample[:, 5] # E observedInput.setDescription(["Force", "Young Modulus"]) observedInput[0:5] .. raw:: html
ForceYoung Modulus
01.06082196966.1
10.8733827197401.2
20.9561734200460.7
31.120548193805.3
40.7818615200026.5


.. GENERATED FROM PYTHON SOURCE LINES 101-104 We would like to see how the observed output depend on the observed inputs. To do this, we use the :meth:`~openturns.VisualTest.DrawPairs` method. .. GENERATED FROM PYTHON SOURCE LINES 106-112 .. code-block:: Python fullSample = ot.Sample(sampleSize, 5) fullSample[:, 0:2] = observedInput fullSample[:, 2:5] = observedOutput fullSample.setDescription(["Force", "Young", "Deflection", "Left Angle", "Right Angle"]) fullSample[0:5] .. raw:: html
ForceYoungDeflectionLeft AngleRight Angle
01.06082196966.1-7.356762e-06-1.533846e-051.814807e-05
10.8733827197401.2-5.99772e-06-1.207712e-051.553027e-05
20.9561734200460.7-6.543909e-06-1.357725e-051.61439e-05
31.120548193805.3-8.003641e-06-1.646546e-051.93807e-05
40.7818615200026.5-5.258701e-06-1.109766e-051.263771e-05


.. GENERATED FROM PYTHON SOURCE LINES 113-117 .. code-block:: Python graph = ot.VisualTest.DrawPairs(fullSample) view = otv.View(graph, figure_kw={"figsize": (10.0, 8.0)}) plt.subplots_adjust(wspace=0.3, hspace=0.3) .. image-sg:: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_001.svg :alt: plot calibration deflection tube :srcset: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_001.svg :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 118-127 Setting up the calibration -------------------------- Please consider that the input parameters L, a, De, di are calibrated. We define the initial point of the calibrated parameters: these values will be used as the mean of the prior normal distribution of the parameters. We set it with a slight difference with the true values, because, in general, we do not know the exact value (otherwise we would not use a calibration method). .. GENERATED FROM PYTHON SOURCE LINES 129-136 .. code-block:: Python XL = 1.4 # Exact : 1.5 Xa = 1.2 # Exact : 1.0 XD = 0.7 # Exact : 0.8 Xd = 0.2 # Exact : 0.1 thetaPrior = [XL, Xa, XD, Xd] .. GENERATED FROM PYTHON SOURCE LINES 137-144 We now define the standard deviation of the prior distribution of the parameters. We compute the standard deviation as 10% of the value of the parameter. This ensures that the prior normal distribution has a spread which scales correctly with the mean of the Gaussian distribution. In other words, this setting corresponds to a 10% coefficient of variation. .. GENERATED FROM PYTHON SOURCE LINES 146-157 .. code-block:: Python sigmaXL = 0.1 * XL sigmaXa = 0.1 * Xa sigmaXD = 0.1 * XD sigmaXd = 0.1 * Xd parameterCovariance = ot.CovarianceMatrix(4) parameterCovariance[0, 0] = sigmaXL**2 parameterCovariance[1, 1] = sigmaXa**2 parameterCovariance[2, 2] = sigmaXD**2 parameterCovariance[3, 3] = sigmaXd**2 print(parameterCovariance) .. rst-class:: sphx-glr-script-out .. code-block:: none [[ 0.0196 0 0 0 ] [ 0 0.0144 0 0 ] [ 0 0 0.0049 0 ] [ 0 0 0 0.0004 ]] .. GENERATED FROM PYTHON SOURCE LINES 158-186 In the physical model, the inputs and parameters are ordered as presented in the next table. Notice that there are no parameters in the physical model. +-------+----------------+ | Index | Input variable | +=======+================+ | 0 | F | +-------+----------------+ | 1 | L | +-------+----------------+ | 2 | a | +-------+----------------+ | 3 | De | +-------+----------------+ | 4 | di | +-------+----------------+ | 5 | E | +-------+----------------+ +-------+-----------+ | Index | Parameter | +=======+===========+ | ∅ | ∅ | +-------+-----------+ **Table 1.** Indices and names of the inputs and parameters of the physical model. .. GENERATED FROM PYTHON SOURCE LINES 188-191 .. code-block:: Python print("Physical Model Inputs:", dt.model.getInputDescription()) print("Physical Model Parameters:", dt.model.getParameterDescription()) .. rst-class:: sphx-glr-script-out .. code-block:: none Physical Model Inputs: [F,L,a,De,di,E] Physical Model Parameters: [] .. GENERATED FROM PYTHON SOURCE LINES 192-220 In order to perform calibration, we have to define a parametric model, with observed inputs and parameters to calibrate. In order to do this, we create a :class:`~openturns.ParametricFunction` where the parameters are `L`, `a`, `de`, `di`, which have the indices 1, 2, 3 and 4 in the physical model. +-------+----------------+ | Index | Input variable | +=======+================+ | 0 | F | +-------+----------------+ | 1 | E | +-------+----------------+ +-------+-----------+ | Index | Parameter | +=======+===========+ | 0 | L | +-------+-----------+ | 1 | a | +-------+-----------+ | 2 | De | +-------+-----------+ | 3 | di | +-------+-----------+ **Table 2.** Indices and names of the inputs and parameters of the parametric model. .. GENERATED FROM PYTHON SOURCE LINES 222-227 .. code-block:: Python calibratedIndices = [1, 2, 3, 4] # [L, a, De, di] calibrationFunction = ot.ParametricFunction(dt.model, calibratedIndices, thetaPrior) print("Parametric Model Inputs:", calibrationFunction.getInputDescription()) print("Parametric Model Parameters:", calibrationFunction.getParameterDescription()) .. rst-class:: sphx-glr-script-out .. code-block:: none Parametric Model Inputs: [F,E] Parametric Model Parameters: [L,a,De,di] .. GENERATED FROM PYTHON SOURCE LINES 228-238 In the next cells, we are going to perform a Bayesian calibration, based on Gaussian assumptions. In the Bayesian framework, we define the standard deviation of the prior Gaussian distribution of the observation errors. Although the exact value of the standard deviation of the observation errors is equal to 0.1e-6, we set slightly different values because the value of the true standard deviation of the observation error is not known in general. We will be able to check if these hypotheses are correct after calibration, using the :meth:`~openturns.CalibrationResult.drawResiduals()` method. .. GENERATED FROM PYTHON SOURCE LINES 240-247 .. code-block:: Python sigmaObservation = [0.2e-6, 0.3e-6, 0.3e-6] # Exact : [0.1e-6, 0.5e-6, 0.5e-6] # Set the diagonal of the covariance matrix. errorCovariance = ot.CovarianceMatrix(3) errorCovariance[0, 0] = sigmaObservation[0] ** 2 errorCovariance[1, 1] = sigmaObservation[1] ** 2 errorCovariance[2, 2] = sigmaObservation[2] ** 2 .. GENERATED FROM PYTHON SOURCE LINES 248-252 .. code-block:: Python calibrationFunction.setParameter(thetaPrior) predictedOutput = calibrationFunction(observedInput) predictedOutput[0:5] .. raw:: html
DeflectionLeft angleRight angle
0-3.154534e-06-1.051511e-051.708706e-05
1-2.591431e-06-8.638103e-061.403692e-05
2-2.79378e-06-9.312601e-061.513298e-05
3-3.38649e-06-1.12883e-051.834349e-05
4-2.28943e-06-7.631432e-061.240108e-05


.. GENERATED FROM PYTHON SOURCE LINES 253-256 Calibration with Gaussian non linear calibration ------------------------------------------------ We are finally able to use the :class:`~openturns.GaussianNonLinearCalibration`. .. GENERATED FROM PYTHON SOURCE LINES 258-267 .. code-block:: Python algo = ot.GaussianNonLinearCalibration( calibrationFunction, observedInput, observedOutput, thetaPrior, parameterCovariance, errorCovariance, ) .. GENERATED FROM PYTHON SOURCE LINES 268-269 The :meth:`~openturns.GaussianNonLinearCalibration.run` method launches the optimization algorithm. .. GENERATED FROM PYTHON SOURCE LINES 271-274 .. code-block:: Python algo.run() calibrationResult = algo.getResult() .. GENERATED FROM PYTHON SOURCE LINES 275-278 Analysis of the results ----------------------- The :meth:`~openturns.CalibrationResult.getParameterMAP` method returns the optimized parameters. .. GENERATED FROM PYTHON SOURCE LINES 280-284 .. code-block:: Python thetaMAP = calibrationResult.getParameterMAP() print("theta After = ", thetaMAP) print("theta Before = ", thetaPrior) .. rst-class:: sphx-glr-script-out .. code-block:: none theta After = [1.49043,0.991573,0.798252,0.199874] theta Before = [1.4, 1.2, 0.7, 0.2] .. GENERATED FROM PYTHON SOURCE LINES 285-286 Compute a 95% credibility interval for each marginal. .. GENERATED FROM PYTHON SOURCE LINES 288-294 .. code-block:: Python thetaPosterior = calibrationResult.getParameterPosterior() alpha = 0.95 dim = thetaPosterior.getDimension() for i in range(dim): print(thetaPosterior.getMarginal(i).computeBilateralConfidenceInterval(alpha)) .. rst-class:: sphx-glr-script-out .. code-block:: none [1.4721, 1.514] [0.969125, 1.02096] [0.794538, 0.802744] [0.199869, 0.19988] .. GENERATED FROM PYTHON SOURCE LINES 295-296 We see that the parameters are accurately estimated in this case. .. GENERATED FROM PYTHON SOURCE LINES 298-300 Increase the default number of points in the plots. This produces smoother spiky distributions. .. GENERATED FROM PYTHON SOURCE LINES 300-302 .. code-block:: Python ot.ResourceMap.SetAsUnsignedInteger("Distribution-DefaultPointNumber", 300) .. GENERATED FROM PYTHON SOURCE LINES 303-305 In order to see how the predicted outputs first to the observed outputs, we plot the outputs depending on the inputs. .. GENERATED FROM PYTHON SOURCE LINES 305-315 .. code-block:: Python # sphinx_gallery_thumbnail_number = 2 graph = calibrationResult.drawObservationsVsInputs() view = otv.View( graph, figure_kw={"figsize": (8.0, 6.0)}, legend_kw={"bbox_to_anchor": (1.0, 1.0), "loc": "upper left"}, ) plt.subplots_adjust(wspace=0.3, hspace=0.7, right=0.8) .. image-sg:: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_002.svg :alt: plot calibration deflection tube :srcset: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_002.svg :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 316-319 For all outputs, the predicted outputs of the model correspond to the observed outputs. .. GENERATED FROM PYTHON SOURCE LINES 321-323 The next cell plots the predicted outputs depending on the observed outputs. .. GENERATED FROM PYTHON SOURCE LINES 325-333 .. code-block:: Python graph = calibrationResult.drawObservationsVsPredictions() view = otv.View( graph, figure_kw={"figsize": (12.0, 4.0)}, legend_kw={"bbox_to_anchor": (1.0, 1.0), "loc": "upper left"}, ) plt.subplots_adjust(wspace=0.3, left=0.05, right=0.85) .. image-sg:: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_003.svg :alt: plot calibration deflection tube :srcset: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_003.svg :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 334-337 We see that, after calibration, the points are on the first diagonal of the plot: this shows that the calibration performs correctly. .. GENERATED FROM PYTHON SOURCE LINES 339-368 In the next cell, we analyse the residuals before and after calibration. In order to clearly see these results, the next table presents the true standard deviation of the output error of observation compared to the hypothesis used in Gaussian calibration. In a practical study, the true sigma is unknown. +-----------------+-----------------+-------------------+ | Output | Sigma True | Sigma hypothesis | +=================+=================+===================+ | Deflection | 0.1e-6 | 0.2e-6 | +-----------------+-----------------+-------------------+ | Left angle | 0.5e-6 | 0.3e-6 | +-----------------+-----------------+-------------------+ | Right angle | 0.5e-6 | 0.3e-6 | +-----------------+-----------------+-------------------+ **Table 3.** For each output, the true standard deviation of the output error of observation compared to the hypothesis used in Gaussian calibration. One of the hypotheses of the Gaussian calibration is that the observation errors are Gaussian. In order to check this hypothesis, we plot the distribution of the residuals before and after calibration. Furthermore, we plot the distribution of the observation errors, which is an hypothesis of the Gaussian calibration. Since there are three output, there are three residuals to check. .. GENERATED FROM PYTHON SOURCE LINES 370-378 .. code-block:: Python graph = calibrationResult.drawResiduals() view = otv.View( graph, figure_kw={"figsize": (13.0, 4.0)}, legend_kw={"bbox_to_anchor": (1.0, 1.0), "loc": "upper left"}, ) plt.subplots_adjust(wspace=0.3, left=0.05, right=0.7) .. image-sg:: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_004.svg :alt: Residual analysis :srcset: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_004.svg :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 379-396 We see that the distribution of the residuals after calibration is centered on zero: this is a good point, since this shows that we have roughly equal chances to over or under predict the output when we use the calibrated model. We see that the distribution of each the residuals after calibration is relatively close to the Gaussian assumption that we used. For the first output, i.e. the deflection, the calibrated distribution of the residuals has a distribution which has spread lower than the hypothesis. This corresponds to the parameters that we used, since the true standard deviation of the errors is equal to 0.1e-6 while we used the 0.2e-6 hypothesis. The opposite happens for the left and right angle residuals: the calibrated residuals are narrower than the normal hypothesis that we used. This is because we used 0.3e-6 as the hypothesis while the true value is 0.05e-5. .. GENERATED FROM PYTHON SOURCE LINES 398-399 Check that the results are Gaussian, using a Normal-plot. .. GENERATED FROM PYTHON SOURCE LINES 401-409 .. code-block:: Python graph = calibrationResult.drawResidualsNormalPlot() view = otv.View( graph, figure_kw={"figsize": (10.0, 4.0)}, legend_kw={"bbox_to_anchor": (1.0, 1.0), "loc": "upper left"}, ) plt.subplots_adjust(wspace=0.3, left=0.05, right=0.8) .. image-sg:: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_005.svg :alt: Residuals after calibration vs Gaussian hypothesis :srcset: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_005.svg :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 410-412 Finally, we observe the prior and posterior distribution of each parameter. .. GENERATED FROM PYTHON SOURCE LINES 414-422 .. code-block:: Python graph = calibrationResult.drawParameterDistributions() view = otv.View( graph, figure_kw={"figsize": (10.0, 4.0)}, legend_kw={"bbox_to_anchor": (1.0, 1.0), "loc": "upper left"}, ) plt.subplots_adjust(wspace=0.3, left=0.05, right=0.8) .. image-sg:: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_006.svg :alt: plot calibration deflection tube :srcset: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_006.svg :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 423-424 .. code-block:: Python otv.View.ShowAll() .. _sphx_glr_download_auto_calibration_least_squares_and_gaussian_calibration_plot_calibration_deflection_tube.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_calibration_deflection_tube.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_calibration_deflection_tube.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_calibration_deflection_tube.zip `