7
7
To compute the adjoint you must specify code for the functional
8
8
derivative. If the functional is also specified, then it will be
9
9
output in the .stat file.</a:documentation>
11
<element name="replay_forward_run">
12
<a:documentation>Rerun the forward equation using libadjoint.
13
This is a debugging option to check if the libadjoint callbacks are implemented correctly.</a:documentation>
18
<element name="html_output">
19
<a:documentation>Activate the visualisation of the forward and adjoint equations solved.
20
This option creates an html file for both the forward and adjoint system.</a:documentation>
25
11
<element name="functional">
26
12
<a:documentation>A functional to be computed.
53
39
This code must compute a real number J, which is the value of the functional associated with this particular
56
Here is a simple example for a tracking functional, measuring the L2-norm of the error between the
57
solution TracerField and a given field TracerObservations:
42
Here is a simple example for the functional that evaluates the L2-norm of a field "LayerThickness" at time T=1:
58
43
<span font_desc="monospace 10" foreground="blue">
60
observ = states[n]["Fluid"].scalar_fields["TracerObservations"]
61
soln = states[n]["Fluid"].scalar_fields["TracerField"]
62
coord = states[n]["Fluid"].vector_fields["Coordinate"]
65
for ele in range(coord.ele_count):
66
t = Transform(coord, ele) # transform to physical
67
shape = soln.ele_shape(ele)
68
mass = t.shape_shape(shape, shape) # the local mass matrix for this element
69
ele_error = observ.ele_val(ele) - soln.ele_val(ele)
70
J = J + 0.5 * numpy.dot(ele_error, numpy.dot(mass, ele_error))
45
T = 1.0 # the time at which to evaluate
46
if time &lt; T &lt;= time+dt:
48
eta_prev = states[n-1]["Fluid"].scalar_fields["LayerThickness"]
49
eta = states[n]["Fluid"].scalar_fields["LayerThickness"]
51
# We want to temporally interpolate to evaluate eta at t=1.0
52
alpha = (time + dt - T) / dt
53
assert 0 &lt;= alpha &lt; 1
54
tmp_eta = alpha * eta_prev.val + (1-alpha) * eta.val
56
# Now we want to integrate that over space
57
coord = states[0]["Fluid"].vector_fields["Coordinate"]
58
assert eta.element_count == eta_prev.element_count == coord.element_count
59
for ele in range(coord.element_count):
60
t = Transform(ele, coord)
61
shape = eta_prev.ele_shape(ele)
62
mass = t.shape_shape(shape, shape)
63
nodes = eta_prev.ele_nodes(ele)
64
J = J + numpy.dot(tmp_eta[nodes], numpy.dot(mass, tmp_eta[nodes]))
73
This applies for a steady-state simulation; for a time-dependent simulation
74
one should either evaluate the fields at a particular time, or integrate
76
67
<span weight="bold">
77
68
If you intend to use automatic differentiation, and want to use
78
69
primitives such as sin, cos, exp, etc., you must use those
110
101
derivative, which is a scalar/vector/tensor field associated with the derivative to be computed.
112
103
This code must set the entries of derivative.val. The code should check which variable we are differentiating
113
with respect to by inspecting derivative.name.
115
Here is a simple example for a tracking functional, measuring the L2-norm of the error between the
116
solution TracerField and a given field TracerObservations at each timestep:
117
<span font_desc="monospace 10" foreground="blue">
119
observ = states[n]["Fluid"].scalar_fields["TracerObservations"]
120
soln = states[n]["Fluid"].scalar_fields["TracerField"]
121
coord = states[n]["Fluid"].vector_fields["Coordinate"]
122
derivative.val[:] = 0.0
124
if derivative.name == "TracerField": # the functional only depends on this
125
for ele in range(coord.ele_count):
126
t = Transform(coord, ele) # transform to physical
127
shape = soln.ele_shape(ele)
128
mass = t.shape_shape(shape, shape) # the local mass matrix for this element
129
ele_error = observ.ele_val(ele) - soln.ele_val(ele)
130
derivative.addto(derivative.ele_nodes(ele), numpy.dot(mass, ele_error))
133
This applies for a steady-state simulation; for a time-dependent simulation
134
one should either evaluate the fields at a particular time, or integrate
135
through time.</a:documentation>
104
with respect to by inspecting derivative.name.</a:documentation>
136
105
<attribute name="name">
137
106
<value>functional_derivative</value>
147
116
This code defines a function that informs the model what variables at which time levels
148
117
will be necessary for the functional computation at this point.
150
Here is a simple example for a tracking functional, measuring the L2-norm of the error between the
151
solution TracerField and a given field TracerObservations at each timestep:
119
Here is a simple example for the functional that evaluates the L2-norm of a field "LayerThickness" at time T=1:
152
120
<span font_desc="monospace 10" foreground="blue">
153
121
def dependencies(times, timestep):
154
return {"Fluid::TracerObservations": [timestep],
155
"Fluid::TracerField": [timestep],
156
"Fluid::Coordinate": [timestep]}
122
if times[0] &lt; 1.0 &lt;= times[1]:
123
return {"Fluid::Coordinate": [0],
124
"Fluid::LayerThickness": [timestep-1, timestep]}
158
128
</a:documentation>
159
129
<attribute name="name">
138
<element name="debug">
139
<a:documentation>Debugging options for adjoint model development</a:documentation>
141
<element name="replay_forward_run">
142
<a:documentation>Rerun the forward equation using libadjoint.
143
This is a debugging option to check if the libadjoint callbacks are implemented correctly.</a:documentation>
148
<element name="html_output">
149
<a:documentation>Activate the visualisation of the forward and adjoint equations solved.
150
This option creates an html file for both the forward and adjoint system.</a:documentation>
155
<element name="check_action_transposes">
156
<a:documentation>Check the transposes of all action callbacks.</a:documentation>
169
164
<define name="adjoint_storage">