Custom: Module with initialization

This examples demonstrates how to make a module with an ininitialization function.

Constant values and other parameters can be passed into the __init__() function, allowing more complex functionality in a module. The values passed into __init__() can be used in the response and sensitivity calculation.

10 import pymoto as pym
11
12
13 class ModuleWithInit(pym.Module):
14     """ This module takes a parameter during initialization
15     Example usage:
16     >>> import pymoto as pym
17     >>> x = pym.Signal('x', state=3.5)
18     >>> y = pym.Signal('y')
19     >>> y = WithInit(1.2, optional_value='bar')(x, y)  # doctest: +ELLIPSIS
20     [WithInit] Prepare my module
21     value = 1.2
22     optional_value = bar
23     [WithInit] Do my response calculation
24     Message = bar, x = 3.5, y=4.2
25     ...
26     >>> y.state
27     4.2
28     """
29     def __init__(self, value, optional_value='foo'):
30         """ This prepare is called during initialization of the module, and can be used for set-up """
31         print(f'[{type(self).__name__}] Initialize my module')
32         print(f'value = {value}')
33         print(f'optional_value = {optional_value}')
34         self.value = value
35         self.optional_value = optional_value
36
37     def __call__(self, x):
38         print(f'[{type(self).__name__}] Do my response calculation')
39         y = x * self.value
40         print(f"Message = {self.optional_value}, x = {x}, y={y}")
41         return y
42
43     def _sensitivity(self, df_dy):
44         print(f'[{type(self).__name__}] Do my sensitivity calculation')
45         return df_dy * self.value
46
47
48 if __name__ == "__main__":
49     print(__doc__)
50     print("_" * 80)
51     print("-- Module setup")
52
53     # Create signals for the inputs. The argument is the 'tag' of the signal, which is optional.
54     # The tag of the signal can be seen as its name, which can be useful for printing and debugging
55     x = pym.Signal("x", 2.0)
56
57     print(f"\nState initialized to {x.tag} = {x.state}")
58
59     # The module is instantiated using the constructor. The values used in the `__init__` function can be passed here.
60     print("Create Module:")
61     my_module = ModuleWithInit(3.14, optional_value='bar')   # Module with extra (constant) parameters
62
63     # After the module is created, it is connected to the input signal.
64     # It will be run once and an output signal is created.
65     print("\n-- Connect module and run forward analysis:")
66     y = my_module(x)
67     y.tag = 'y'  # Set a name for the output signal
68
69     # The state of the output signal can be accessed using `state` again
70     print(f"The result: {y.tag} = {y.state}")
71
72     print("\n-- Sensitivity analysis by back-propagation")
73     # Calculate sensitivities
74     print("\nSeed dy/dy = 1.0, so we can calculate dy/dx")
75     # An initial 'seed' sensitivity of the response you're interested in needs to be set. We can do this by setting
76     # the `sensitivity` property
77     y.sensitivity = 1.0
78     my_module.sensitivity()
79     # The sensitivities of the input signals can now be accessed by <Signal>.sensitivity
80     print(f"dy/d{x.tag} = {x.sensitivity}")
81
82     # You can always check your module with finite differencing
83     pym.finite_difference([x], y, random=False)

Gallery generated by Sphinx-Gallery