9.3.2. Making parameters via bundles

Let us start from a bundle that simply initializes some parameters from the list. It is fairly simple:

 1from gna.bundle.bundle import TransformationBundle
 2
 3class parameters_ex01(TransformationBundle):
 4    def __init__(self, *args, **kwargs):
 5        TransformationBundle.__init__(self, *args, **kwargs)
 6        self.check_nidx_dim(0,0)
 7
 8    def define_variables(self):
 9        for parname, parcfg in self.cfg.pars.items(nested=True):
10            self.reqparameter(parname, None, cfg=parcfg)

The parameters_ex01 bundle class contains two methods __init__() and define_variables(). The constructor

1    def __init__(self, *args, **kwargs):
2        TransformationBundle.__init__(self, *args, **kwargs)
3        self.check_nidx_dim(0,0)

passes all the arguments to the common bundle costructor, which initializes configuration, multidimensional index, etc. As this particular bundle can not handle indexing, it checks that the number of dimensions is within limits \([0,0]\).

The second method is called to initialize parameters. For each name, par pair from the configuration it initializes a parameter.

1    def define_variables(self):
2        for parname, parcfg in self.cfg.pars.items(nested=True):
3            self.reqparameter(parname, None, cfg=parcfg)

Again parameters_ex01 in a sense a function, which reads its argument from configuration dictionary.

In order to use the bundle one needs to execute its configuration. See the following example:

 1from gna.bundle import execute_bundle
 2from gna.configurator import NestedDict, uncertaindict, uncertain
 3from gna.env import env
 4
 5#
 6# Bundle configuration
 7#
 8cfg = NestedDict(
 9    bundle = dict(
10        name='parameters',
11        version='ex01',
12        ),
13    pars = uncertaindict(
14        [
15            ( 'par_a',   (1.0, 1.0,  'percent') ),
16            ( 'par_b',   (2.0, 0.01, 'relative') ),
17            ( 'par_c',   (3.0, 0.5,  'absolute') ),
18            ( 'group.a', (1.0, 'free' ) ),
19            ( 'group.b', (1.0, 'fixed', 'Labeled fixed parameter' ) )
20            ],
21        ),
22)
23
24#
25# Execute bundle configuration
26#
27b1 = execute_bundle(cfg)
28
29#
30# Print the parameters
31#
32env.globalns.printparameters(labels=True)

We start from making a dictionary with configuration:

 1cfg = NestedDict(
 2    bundle = dict(
 3        name='parameters',
 4        version='ex01',
 5        ),
 6    pars = uncertaindict(
 7        [
 8            ( 'par_a',   (1.0, 1.0,  'percent') ),
 9            ( 'par_b',   (2.0, 0.01, 'relative') ),
10            ( 'par_c',   (3.0, 0.5,  'absolute') ),
11            ( 'group.a', (1.0, 'free' ) ),
12            ( 'group.b', (1.0, 'fixed', 'Labeled fixed parameter' ) )
13            ],
14        ),
15)

The bundle specifies the bundle that should read the configuration and make parameters. The only other field is a dictionary with parameter specifications. We use uncertaindict() for this. Its signature is similar to the python dict() signature: first argument is a list with (key, value) pairs, other arguments are named and represent key=value pairs as well.

The possible variants of parameter definitions should be readable. First line

            ( 'par_a',   (1.0, 1.0,  'percent') ),

defines parameter par_a with central value of 1 and relative uncertainty of 1%, expressed in percents.

            ( 'par_b',   (2.0, 0.01, 'relative') ),

defines parameter par_b with central value of 2 and relative uncertainty of 1%, expressed in relative units.

            ( 'par_c',   (3.0, 0.5,  'absolute') ),

defines parameter par_c with central value of 3 and absolute uncertainty of 0.5.

            ( 'group.a', (1.0, 'free' ) ),

defines parameter a in a nested namespace group with default value of 1. The parameter is free.

            ( 'group.b', (1.0, 'fixed', 'Labeled fixed parameter' ) )

defines parameter b in a nested namespace group with value of 1. The parameter is fixed.

Extra argument may be added to each line defining the parameters label as it is done in the last example.

Finally we execute the bundle configuration as follows:

b1 = execute_bundle(cfg)

The function returns parameters_ex01 class instance. After execution the global namespace contains all the parameters defined:

env.globalns.printparameters(labels=True)
Variables in namespace '':
  par_a                =          1 │           1±        0.01 [          1%] │
  par_b                =          2 │           2±        0.02 [          1%] │
  par_c                =          3 │           3±         0.5 [    16.6667%] │
Variables in namespace 'group':
  a                    =          1 │           1±         inf [free]         │
  b                    =          1 │                 [fixed]                 │ Labeled fixed parameter

Such an approach enables the user to detach the configuration from the actual code. In the same time the piece of configuration indicates which code should handle it. The code of the parameters_ex01 is meant to be immutable for backwards compatibility. Alternative behaviour should be achieved by introducing other versions of the bundle or other bundles.