English Français

Documentation / User's manual in Python : PDF version

VI.2. The finite differences method

VI.2. The finite differences method

VI.2.1. General presentation of finite difference sensitivity indices

The finite differences method is among the simplest one. The resulting sensitivity index of an input variable with respect to an output is an estimation of the derivative of versus , , around a nominal value . In this implementation of the method, the estimation is obtained by applying an OAT design-of-experiments (One-At-a-Time, c.f. Section III.6) to the studied model. For each input's nominal value, we define a range . The resulting estimate of the partial derivative around the nominal value is then given by

.

VI.2.2. Computation of local sensitivity indices with the finite differences method

In Uranie, computing local sensitivity indices around a nominal value with the finite differences method is dealt with the eponymous class TFiniteDifferences which inherits from the TSensitivity class.

This class handles all the steps to compute local indices:

  • generating the deterministic sample;
  • running the code or the analytic function to get the target attribute;
  • computing local indices for each input variable.

VI.2.2.1. Example: simple computation of sensitivity indices with TFiniteDifferences

The example script below uses the TFiniteDifferences class to compute and display local sensitivity indices:

"""
Example of finite difference approach
"""
from rootlogon import ROOT, DataServer, Sensitivity

# loading the flowrateModel function
ROOT.gROOT.LoadMacro("UserFunctions.C")

# Define the DataServer  and add the attributes (stochastic variables here)
tds = DataServer.TDataServer("tdsflowreate", "DataBase flowreate")
tds.addAttribute(DataServer.TUniformDistribution("rw", 0.05, 0.15))
tds.addAttribute(DataServer.TUniformDistribution("r", 100.0, 50000.0))
tds.addAttribute(DataServer.TUniformDistribution("tu", 63070.0, 115600.0))
tds.addAttribute(DataServer.TUniformDistribution("tl", 63.1, 116.0))
tds.addAttribute(DataServer.TUniformDistribution("hu", 990.0, 1110.0))
tds.addAttribute(DataServer.TUniformDistribution("hl", 700.0, 820.0))
tds.addAttribute(DataServer.TUniformDistribution("l", 1120.0, 1680.0))
tds.addAttribute(DataServer.TUniformDistribution("kw", 9855.0, 12045.0))

# Set nominal values
tds.getAttribute("rw").setDefaultValue(0.075)
tds.getAttribute("r").setDefaultValue(25000.0)
tds.getAttribute("tu").setDefaultValue(90000.0)
tds.getAttribute("tl").setDefaultValue(90.0)
tds.getAttribute("hu").setDefaultValue(1050.0)
tds.getAttribute("hl").setDefaultValue(760.0)
tds.getAttribute("l").setDefaultValue(1400.0)
tds.getAttribute("kw").setDefaultValue(10500.0)

# Create a TFiniteDifferences object and compute indexes
tfindef = Sensitivity.TFiniteDifferences(tds, "flowrateModel",
                                         "rw:r:tu:tl:hu:hl:l:kw",
                                         "flowrateModel", "steps=0.5%")
tfindef.computeIndexes()

tfindef.getSensitivityMatrix().Print()

The result of this script is shown below:

1x8 matrix is as follows

     |      0    |      1    |      2    |      3    |      4    |
----------------------------------------------------------------------
   0 |       1019  -3.586e-07   1.265e-09    0.001265      0.1321 


     |      5    |      6    |      7    |
----------------------------------------------------------------------
   0 |    -0.1321    -0.02729    0.003639 

VI.2.2.2. Specifying the input parameters

First, it is necessary to define the uncertain parameters and to add them to a TDataServer object:

# Define the DataServer
tds = DataServer.TDataServer("tdsflowreate", "DataBase flowreate")
tds.addAttribute(DataServer.TUniformDistribution("rw", 0.05, 0.15))
tds.addAttribute(DataServer.TUniformDistribution("r", 100.0, 50000.0))
tds.addAttribute(DataServer.TUniformDistribution("tu", 63070.0, 115600.0))
tds.addAttribute(DataServer.TUniformDistribution("tl", 63.1, 116.0))
tds.addAttribute(DataServer.TUniformDistribution("hu", 990.0, 1110.0))
tds.addAttribute(DataServer.TUniformDistribution("hl", 700.0, 820.0))
tds.addAttribute(DataServer.TUniformDistribution("l", 1120.0, 1680.0))
tds.addAttribute(DataServer.TUniformDistribution("kw", 9855.0, 12045.0))

Then, the nominal values of each input parameters must be set (using the method TAttribute::setDefaultValue):

# Set the nominal values
tds.getAttribute("rw").setDefaultValue(0.075)
tds.getAttribute("r").setDefaultValue(25000.0)
tds.getAttribute("tu").setDefaultValue(90000.0)
tds.getAttribute("tl").setDefaultValue(90.0)
tds.getAttribute("hu").setDefaultValue(1050.0)
tds.getAttribute("hl").setDefaultValue(760.0)
tds.getAttribute("l").setDefaultValue(1400.0)
tds.getAttribute("kw").setDefaultValue(10500.0)

VI.2.2.3. TFiniteDifferences constructor

There are four different constructors to build a TFiniteDifferences object, each corresponding to a different problem:

  • the model is an analytic function run by Uranie,
  • the model is a code run by Uranie,
  • the outputs of the model are already computed and saved in a TDataServer object.
  • the model is either a function or a code and the problem is specified through a Relauncher architecture.

VI.2.2.3.1. TFiniteDifferences constructor for an analytic function

The constructor prototype used with an analytic function is:

# Create a TFiniteDifferences object with an analytic function
TFiniteDifferences(tds, fcn, sensitiveAtt, outputAtt, samplingOption="steps=1%")  # fcn is a string
TFiniteDifferences(tds, fcn, sensitiveAtt, outputAtt, samplingOption="steps=1%")  # fcn is a function-pointer

This constructor takes five arguments:

  • a pointer to a TDataServer object,

  • a pointer to an analytic function (a const char that represents the function's name when it has been loaded in ROOT's memory) or a pointer to this function (see Section I.2.5),

  • a TString to specify the names of the input factors separated by ':' (ex. "rw:r:tu:tl:hu:hl:l:kw"),

  • a TString to specify the names output variables of the model,

  • a TString to specify the sample options, its default value is the string "steps=1%".

The options available are the options of the method Sampler::TOATSampling . They are written as strings of the form:"steps=x", where "x" can either be a real value (e.g. "steps=3.1415") or a percentage of the nominal value (e.g. "steps=0.123%"). This "steps" value is the same for each input parameter.

Here is an example of how to use the constructor with an analytic function:

tfindef = Sensitivity.TFiniteDifferences(tds, "flowrateModel", "rw:r:tu:tl:hu:hl:l:kw", "y", "steps=0.5%")
VI.2.2.3.2. TFiniteDifferences constructor for a code

The constructor prototype used with a code is:

# Create a TFiniteDifferences object with a code
TFiniteDifferences(tds, fcode,  sensitiveAtt="", samplingOption="steps=1%")

This constructor takes four arguments:

  • a pointer to a TDataServer object,

  • a pointer to a TCode,

  • a TString to specify the names of the input factors separated by ':' (ex. "rw:r:tu:tl:hu:hl:l:kw"), its default value is the empty string ""

  • a TString to specify the sample options, its default value is the string "steps=1%".

The options available are the options of the method Sampler::TOATSampling. It's a string of the form:"steps=x", where "x" can either be a real value (e.g. "steps=3.1415") or a percentage of the nominal value (e.g. "steps=0.123%"). This "steps" value is the same for each input parameter.

Here is an example of the use of this constructor on the flowrate case:

# The reference input file
sJDDReference = "flowrate_input_with_keys.in"

# Set the reference input file and the key for each input attributes
tds.getAttribute("rw").setFileKey(sJDDReference, "Rw")
tds.getAttribute("r").setFileKey(sJDDReference, "R")
tds.getAttribute("tu").setFileKey(sJDDReference, "Tu")
tds.getAttribute("tl").setFileKey(sJDDReference, "Tl")
tds.getAttribute("hu").setFileKey(sJDDReference, "Hu")
tds.getAttribute("hl").setFileKey(sJDDReference, "Hl")
tds.getAttribute("l").setFileKey(sJDDReference, "L")
tds.getAttribute("kw").setFileKey(sJDDReference, "Kw")

# The output file of the code
fout = Launcher.TOutputFileRow("_output_flowrate_withRow_.dat")
# The attribute in the output file
fout.addAttribute(DataServer.TAttribute("yhat"))

# Instanciation de mon code
mycode = Launcher.TCode(tds, "flowrate -s -k")
# Adding the outputfile to the tcode object
mycode.addOutputFile(fout)

tfindefC = Sensitivity.TFiniteDifferences(tds, mycode)
VI.2.2.3.3. TFiniteDifferences constructor for a runner

The constructor prototype used with a code is:

# Create a TFiniteDifferences object with a runner
TFiniteDifferences(tds, run, sensitiveAtt = "", samplingOption = "steps=1%")

This constructor takes four arguments:

  • a pointer to a TDataServer object,

  • a pointer to a TRun,

  • a TString to specify the names of the input factors separated by ':' (ex. "rw:r:tu:tl:hu:hl:l:kw"), its default value is the empty string ""

  • a TString to specify the sample options, its default value is the string "steps=1%".

The options available are the options of the method Sampler::TOATSampling. It's a string of the form:"steps=x", where "x" can either be a real value (e.g. "steps=3.1415") or a percentage of the nominal value (e.g. "steps=0.123%"). This "steps" value is the same for each input parameter.

Here is an example of the use of this constructor on the flowrate case, using the code:

# The input file
infile = Relauncher.TKeyScript("flowrate_input_with_keys.in")
# provide the input and their key
infile.addInput(tds.getAttribute("rw"), "Rw")
infile.addInput(tds.getAttribute("r"), "R")
infile.addInput(tds.getAttribute("tu"), "Tu")
infile.addInput(tds.getAttribute("tl"), "Tl")
infile.addInput(tds.getAttribute("hu"), "Hu")
infile.addInput(tds.getAttribute("hl"), "Hl")
infile.addInput(tds.getAttribute("l"), "L")
infile.addInput(tds.getAttribute("kw"), "Kw")

yhat = DataServer.TAttribute("yhat")
# The output file of the code
outfile = Relauncher.TKeyResult("_output_flowrate_withKey_.dat")
# The attribute in the output file
outfile.addOutput(yhat, "yhat")

# Instanciation de mon code
code = Relauncher.TCodeEval("flowrate -s -k")
# Adding the intput/output file to the code
code.addInputFile(infile)
code.addOutputFile(outfile)

run = Relauncher.TSequentialRun(code)
run.startSlave()
if run.onMaster():

    tfindefR = Sensitivity.TFiniteDifferences(tds, run)
    # ....
VI.2.2.3.4. TFiniteDifferences constructor using a filled TDS

The two constructors before are used for cases where the computation of the model outputs are run from Uranie. However it is possible to compute the outputs of the model outside of Uranie then load them in a TDataServer object (via a file) and use that TDataServer object to compute the finite difference indices.

Be aware that in that case, because of the use of internal variables, it is necessary to use a sample of input parameters computed with Uranie, exported in a file and then completed with the outputs of the model.

The constructor prototype used with a TDataServer object already containing the simulations is:

 #  Create a TFiniteDifferences object with already filled TDS
TFiniteDifferences(tds, inputAtt, outputAtt, sensitiveAtt = "")

This constructor takes four arguments:

  • a pointer to a TDataServer object filled with data,

  • a TString to specify the names of all the input factors separated by ':' (ex. "rw:r:tu:tl:hu:hl:l:kw"),

  • a TString to specify the names of the output variables of the model,

  • a TString to specify the names of the inputs of the model which are studied, its default value is the empty string "".

Below is an example of the constructor with a TDataServer object filled:

# Define the DataServer and add the attributes
tdsFilled = DataServer.TDataServer()
tdsFilled.fileDataRead("sampleFiniteDifferencesFlowrateModel.dat")
tdsFilled.getAttribute("flowrateModel").setOutput()  # Mark the output

tfindef2 = Sensitivity.TFiniteDifferences(tdsFilled, "rw:r:tu:tl:hu:hl:l:kw", "flowrateModel")

Warning

This constructor uses a TDataServer object already filled with specific internal variables (__nominal_set__ and __modified_att__) and a specific sample!

There are several conditions to use it:

  • use the constructor without argument for the TDataServer;
  • the input factors sample must have been generated with the method TFiniteDifferences::generateSample;
  • the output factors of the model must have been specified with the method TAttribute::setOutput;

VI.2.2.4. Computing the indices

To compute the indices, run the method computeIndexes:

tfindef.computeIndexes()

Note that this method is all inclusive: it constructs the sample (if it does not exist), launches the simulations (if they are not already computed) and computes the indices.

VI.2.2.5. Extracting the indices

To extract the indices use the method getSensitivityMatrix:

matRes = tfindef.getSensitivityMatrix()
matRes.Print()
/language/en