Documentation / User's manual in C++ :
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
.
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.
The example script below uses the TFiniteDifferences
class
to compute and display local sensitivity indices:
{
// loading the flowrateModel function
gROOT->LoadMacro("UserFunctions.C");
// Define the DataServer and add the attributes (stochastic variables here)
TDataServer *tds = new TDataServer("tdsflowreate", "DataBase flowreate");
tds->addAttribute( new TUniformDistribution("rw", 0.05, 0.15));
tds->addAttribute( new TUniformDistribution("r", 100.0, 50000.0));
tds->addAttribute( new TUniformDistribution("tu", 63070.0, 115600.0));
tds->addAttribute( new TUniformDistribution("tl", 63.1, 116.0));
tds->addAttribute( new TUniformDistribution("hu", 990.0, 1110.0));
tds->addAttribute( new TUniformDistribution("hl", 700.0, 820.0));
tds->addAttribute( new TUniformDistribution("l", 1120.0, 1680.0));
tds->addAttribute( new 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
TFiniteDifferences * tfindef = new TFiniteDifferences(tds,"flowrateModel", "rw:r:tu:tl:hu:hl:l:kw", "y", "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
First, it is necessary to define the uncertain parameters and to add them to a TDataServer
object:
// Define the DataServer
TDataServer *tds = new TDataServer("tdsflowreate", "DataBase flowreate");
tds->addAttribute( new TUniformDistribution("rw", 0.05, 0.15));
tds->addAttribute( new TUniformDistribution("r", 100.0, 50000.0));
tds->addAttribute( new TUniformDistribution("tu", 63070.0, 115600.0));
tds->addAttribute( new TUniformDistribution("tl", 63.1, 116.0));
tds->addAttribute( new TUniformDistribution("hu", 990.0, 1110.0));
tds->addAttribute( new TUniformDistribution("hl", 700.0, 820.0));
tds->addAttribute( new TUniformDistribution("l", 1120.0, 1680.0));
tds->addAttribute( new 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);
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.
The constructor prototype used with an analytic function is:
// Create a TFiniteDifferences object with an analytic function
TFiniteDifferences(TDataServer *tds, const char *fcn, TString sensitiveAtt, TString outputAtt, TString samplingOption="steps=1%")
TFiniteDifferences(TDataServer *tds, void * fcn(double *,double *), TString sensitiveAtt, TString outputAtt, TString samplingOption="steps=1%")
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:
TFiniteDifferences * tfindef = new TFiniteDifferences(tds,"flowrateModel", "rw:r:tu:tl:hu:hl:l:kw", "y", "steps=0.5%");
The constructor prototype used with a code is:
// Create a TFiniteDifferences object with a code
TFiniteDifferences(TDataServer *tds, TCode *fcode, TString sensitiveAtt="", TString 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
TString sJDDReference = TString("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
TOutputFileRow *fout = new TOutputFileRow("_output_flowrate_withRow_.dat");
// The attribute in the output file
fout->addAttribute(new TAttribute("yhat"));
// Instanciation de mon code
TCode *mycode = new TCode(tds, "flowrate -s -k");
// Adding the outputfile to the tcode object
mycode->addOutputFile( fout );
TFiniteDifferences * tfindefC = new TFiniteDifferences(tds,mycode);
The constructor prototype used with a code is:
// Create a TFiniteDifferences object with a runner
TFiniteDifferences(TDataServer *tds, TRun *run, TString sensitiveAtt="", TString 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
TKeyScript infile("flowrate_input_with_keys.in");
// provide the input and their key
infile.setInputs(8, tds->getAttribute("rw"), "Rw", tds->getAttribute("r"), "R",
tds->getAttribute("tu"), "Tu", tds->getAttribute("tl"), "Tl", tds->getAttribute("hu"), "Hu",
tds->getAttribute("hl"), "Hl", tds->getAttribute("l"), "L", tds->getAttribute("kw"), "Kw");
TAttribute yhat("yhat");
// The output file of the code
TKeyResult outfile("_output_flowrate_withKey_.dat");
// The attribute in the output file
outfile.addOutput(&yhat, "yhat");
// Instanciation de mon code
TCodeEval code("flowrate -s -k");
// Adding the intput/output file to the code
code.addInputFile(&infile);
code.addOutputFile(&outfile);
TSequentialRun run(&code);
run.startSlave();
if(run.onMaster())
{
TFiniteDifferences * tfindefR = new TFiniteDifferences(tds, &run);
// ....
}
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(TDataServer *tds, TString inputAtt, TString outputAtt, TString sensitiveAtt=TString(""))
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
TDataServer *tdsFilled = new TDataServer();
tdsFilled->fileDataRead("sampleFiniteDifferencesFlowrateModel.dat");
tdsFilled->getAttribute("flowrateModel")->setOutput(); // Mark the output
TFiniteDifferences * tfindef2 = new TFiniteDifferences(tdsFilled, TString("rw:r:tu:tl:hu:hl:l:kw"), TString("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
;
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.