.. 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-38 .. code-block:: Python from openturns.usecases import deflection_tube import openturns as ot import openturns.viewer as otv from matplotlib import pylab as plt ot.Log.Show(ot.Log.NONE) .. GENERATED FROM PYTHON SOURCE LINES 39-42 Create a calibration problem ---------------------------- We load the model from the use case module : .. GENERATED FROM PYTHON SOURCE LINES 44-48 .. 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 49-53 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 55-56 We create a sample out of our input distribution : .. GENERATED FROM PYTHON SOURCE LINES 58-62 .. code-block:: Python sampleSize = 100 inputSample = dt.inputDistribution.getSample(sampleSize) inputSample[0:5] .. raw:: html
ForceLengthLocationExternal diameterInternal diameterYoung Modulus
00.99057691.510.80.1195443.3
11.052561.510.80.1198526
20.89603311.510.80.1197851.2
31.0573981.510.80.1200036.7
41.0088691.510.80.1197215.1


.. GENERATED FROM PYTHON SOURCE LINES 63-64 We take the image of our input sample by the model : .. GENERATED FROM PYTHON SOURCE LINES 66-69 .. code-block:: Python outputDeflection = dt.model(inputSample) outputDeflection[0:5] .. raw:: html
DeflectionLeft angleRight angle
0-7.003919e-06-1.400784e-051.75098e-05
1-7.326614e-06-1.465323e-051.831653e-05
2-6.258339e-06-1.251668e-051.564585e-05
3-7.304704e-06-1.460941e-051.826176e-05
4-7.069166e-06-1.413833e-051.767292e-05


.. GENERATED FROM PYTHON SOURCE LINES 70-74 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 76-81 .. 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 82-86 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 88-93 .. 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.163228e-06-1.410771e-051.753855e-05
1-7.452763e-06-1.449212e-051.838678e-05
2-6.33502e-06-1.256392e-051.626712e-05
3-7.265429e-06-1.522145e-051.823709e-05
4-7.065494e-06-1.457829e-051.76351e-05


.. GENERATED FROM PYTHON SOURCE LINES 94-95 We now extract the observed inputs from the input sample. .. GENERATED FROM PYTHON SOURCE LINES 97-103 .. 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
00.9905769195443.3
11.05256198526
20.8960331197851.2
31.057398200036.7
41.008869197215.1


.. GENERATED FROM PYTHON SOURCE LINES 104-107 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 109-115 .. 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
00.9905769195443.3-7.163228e-06-1.410771e-051.753855e-05
11.05256198526-7.452763e-06-1.449212e-051.838678e-05
20.8960331197851.2-6.33502e-06-1.256392e-051.626712e-05
31.057398200036.7-7.265429e-06-1.522145e-051.823709e-05
41.008869197215.1-7.065494e-06-1.457829e-051.76351e-05


.. GENERATED FROM PYTHON SOURCE LINES 116-120 .. 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.png :alt: plot calibration deflection tube :srcset: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 121-130 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 132-139 .. 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 140-147 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 149-160 .. 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 161-189 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 191-194 .. 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 195-223 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 225-230 .. 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 231-241 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 243-250 .. 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 251-255 .. code-block:: Python calibrationFunction.setParameter(thetaPrior) predictedOutput = calibrationFunction(observedInput) predictedOutput[0:5] .. raw:: html
DeflectionLeft angleRight angle
0-2.968605e-06-9.895348e-061.607994e-05
1-3.105378e-06-1.035126e-051.68208e-05
2-2.652591e-06-8.841971e-061.43682e-05
3-3.096092e-06-1.032031e-051.67705e-05
4-2.996259e-06-9.987531e-061.622974e-05


.. GENERATED FROM PYTHON SOURCE LINES 256-259 Calibration with Gaussian non linear calibration ------------------------------------------------ We are finally able to use the :class:`~openturns.GaussianNonLinearCalibration`. .. GENERATED FROM PYTHON SOURCE LINES 261-270 .. code-block:: Python algo = ot.GaussianNonLinearCalibration( calibrationFunction, observedInput, observedOutput, thetaPrior, parameterCovariance, errorCovariance, ) .. GENERATED FROM PYTHON SOURCE LINES 271-272 The :meth:`~openturns.GaussianNonLinearCalibration.run` method launches the optimization algorithm. .. GENERATED FROM PYTHON SOURCE LINES 274-277 .. code-block:: Python algo.run() calibrationResult = algo.getResult() .. GENERATED FROM PYTHON SOURCE LINES 278-281 Analysis of the results ----------------------- The :meth:`~openturns.CalibrationResult.getParameterMAP` method returns the optimized parameters. .. GENERATED FROM PYTHON SOURCE LINES 283-287 .. 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.50671,1.0088,0.801516,0.199872] theta Before = [1.4, 1.2, 0.7, 0.2] .. GENERATED FROM PYTHON SOURCE LINES 288-289 Compute a 95% credibility interval for each marginal. .. GENERATED FROM PYTHON SOURCE LINES 291-297 .. 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.48811, 1.52898] [0.985314, 1.03571] [0.797819, 0.80569] [0.199866, 0.199877] .. GENERATED FROM PYTHON SOURCE LINES 298-299 We see that the parameters are accurately estimated in this case. .. GENERATED FROM PYTHON SOURCE LINES 301-303 Increase the default number of points in the plots. This produces smoother spiky distributions. .. GENERATED FROM PYTHON SOURCE LINES 303-305 .. code-block:: Python ot.ResourceMap.SetAsUnsignedInteger("Distribution-DefaultPointNumber", 300) .. GENERATED FROM PYTHON SOURCE LINES 306-308 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 308-318 .. 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.png :alt: plot calibration deflection tube :srcset: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_002.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 319-322 For all outputs, the predicted outputs of the model correspond to the observed outputs. .. GENERATED FROM PYTHON SOURCE LINES 324-326 The next cell plots the predicted outputs depending on the observed outputs. .. GENERATED FROM PYTHON SOURCE LINES 328-336 .. 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.png :alt: plot calibration deflection tube :srcset: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_003.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 337-340 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 342-371 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 373-381 .. 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.png :alt: Residual analysis :srcset: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_004.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 382-399 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 401-402 Check that the results are Gaussian, using a Normal-plot. .. GENERATED FROM PYTHON SOURCE LINES 404-412 .. 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.png :alt: Residuals after calibration vs Gaussian hypothesis :srcset: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_005.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 413-415 Finally, we observe the prior and posterior distribution of each parameter. .. GENERATED FROM PYTHON SOURCE LINES 417-427 .. 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) otv.View.ShowAll() .. image-sg:: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_006.png :alt: plot calibration deflection tube :srcset: /auto_calibration/least_squares_and_gaussian_calibration/images/sphx_glr_plot_calibration_deflection_tube_006.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 428-429 Reset default settings .. GENERATED FROM PYTHON SOURCE LINES 429-430 .. code-block:: Python ot.ResourceMap.Reload() .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 3.870 seconds) .. _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 `