Merge lp:~libadjoint/libadjoint/time-functionals into lp:libadjoint

Proposed by Patrick Farrell
Status: Merged
Merged at revision: 347
Proposed branch: lp:~libadjoint/libadjoint/time-functionals
Merge into: lp:libadjoint
Diff against target: 269 lines (+114/-7)
5 files modified
include/libadjoint/adj_adjointer_routines.h (+3/-0)
include/libadjoint/adj_data_structures.h (+2/-0)
python/libadjoint/libadjoint.py (+78/-7)
src/adj_adjointer_routines.c (+29/-0)
src/adj_fortran.F90 (+2/-0)
To merge this branch: bzr merge lp:~libadjoint/libadjoint/time-functionals
Reviewer Review Type Date Requested Status
Simon Funke Approve
Review via email: mp+113216@code.launchpad.net

Description of the change

Changes to support the general syntax for Functionals in dolfin-adjoint.

To post a comment you must log in.
Revision history for this message
Simon Funke (simon-funke) wrote :

Please add the missing docstrings for AdjointerTime.finish and .next

Otherwise, looks good.

review: Approve
352. By Patrick Farrell

Add some docstrings

Revision history for this message
Simon Funke (simon-funke) wrote :

dolfin_adjoint/functional.py, line 13:
 There is a remaining "FIX THIS" comment?

dolfin_adjoint/utils.py, line 10:
 importing adj_html is not required in this module. I suggest to remove this line.

review: Needs Fixing
Revision history for this message
Simon Funke (simon-funke) wrote :

Looks good, ship it!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/libadjoint/adj_adjointer_routines.h'
2--- include/libadjoint/adj_adjointer_routines.h 2012-03-26 11:29:30 +0000
3+++ include/libadjoint/adj_adjointer_routines.h 2012-07-03 15:37:21 +0000
4@@ -49,6 +49,9 @@
5 int adj_variable_known(adj_adjointer* adjointer, adj_variable var, int* known);
6 int adj_get_variable_value(adj_adjointer* adjointer, adj_variable var, adj_vector* value);
7
8+int adj_set_finished(adj_adjointer* adjointer, int finished);
9+int adj_get_finished(adj_adjointer* adjointer, int* finished);
10+
11 #ifndef ADJ_HIDE_FROM_USER
12 int adj_set_storage_memory_copy(adj_adjointer* adjointer, adj_variable* var);
13 int adj_set_storage_memory_incref(adj_adjointer* adjointer, adj_variable* var);
14
15=== modified file 'include/libadjoint/adj_data_structures.h'
16--- include/libadjoint/adj_data_structures.h 2012-03-26 08:49:18 +0000
17+++ include/libadjoint/adj_data_structures.h 2012-07-03 15:37:21 +0000
18@@ -294,6 +294,8 @@
19 adj_func_callback_list functional_list;
20 adj_func_deriv_callback_list functional_derivative_list;
21 adj_parameter_source_callback_list parameter_source_list;
22+
23+ int finished; /* Is the annotation finished? */
24 } adj_adjointer;
25
26 int adj_create_variable(char* name, int timestep, int iteration, int auxiliary, adj_variable* var);
27
28=== modified file 'python/libadjoint/libadjoint.py'
29--- python/libadjoint/libadjoint.py 2012-06-05 07:57:02 +0000
30+++ python/libadjoint/libadjoint.py 2012-07-03 15:37:21 +0000
31@@ -78,6 +78,17 @@
32 else:
33 raise AttributeError
34
35+ def __setattr__(self, key, val):
36+ if key == "timestep":
37+ self.var.timestep = val
38+ elif key == "iteration":
39+ self.var.iteration = val
40+ elif key == "type":
41+ type_map = {'ADJ_FORWARD': 1, 'ADJ_ADJOINT': 2, 'ADJ_TLM': 3}
42+ self.var.type = type_map[val]
43+ else:
44+ object.__setattr__(self, key, val)
45+
46 def __eq__(self, other):
47
48 if not isinstance(other, Variable):
49@@ -350,7 +361,7 @@
50 def __init__(self):
51 pass
52
53- def __call__(self, adjointer, dependencies, values):
54+ def __call__(self, adjointer, timestep, dependencies, values):
55 '''__call__(self, dependencies, values)
56
57 Evaluate functional given dependencies with values. The result must be a scalar.
58@@ -412,7 +423,7 @@
59 values = [vector(values_c[i]) for i in range(ndepends_c)]
60
61 # Now call the callback we've been given
62- output_c[0] = self(adjointer, dependencies, values)
63+ output_c[0] = self(adjointer, timestep, dependencies, values)
64
65 functional_type = ctypes.CFUNCTYPE(None, ctypes.POINTER(clib.adj_adjointer), ctypes.c_int, ctypes.c_int, ctypes.POINTER(clib.adj_variable), ctypes.POINTER(clib.adj_vector), ctypes.c_char_p, ctypes.POINTER(ctypes.c_double))
66 return functional_type(cfunc)
67@@ -614,13 +625,58 @@
68 ctypes.POINTER(clib.adj_vector), ctypes.c_int, ctypes.POINTER(None), ctypes.POINTER(clib.adj_matrix))
69 return rhs_deriv_assembly_type(cfunc)
70
71+class AdjointerTime(object):
72+ """class to facilitate recording the simulation time at which timesteps occur"""
73+ def __init__(self, adjointer):
74+ self.time_levels = []
75+ self.finished = False
76+ self.adjointer = adjointer
77+
78+ def start(self, time):
79+ """start(self, time)
80+ Set the start time of the simulation."""
81+
82+ if len(self.time_levels)!=0:
83+ raise exceptions.LibadjointErrorInvalidInputs(
84+ "time.start() called after simulation started!")
85+
86+ self.time_levels = [time]
87+
88+ def finish(self):
89+ """finish()
90+ Record that the annotation has finished."""
91+ self.finished = True
92+ clib.adj_set_finished(self.adjointer.adjointer, 1)
93+
94+ def next(self, time):
95+ """Increment the timestep counter, and mark the end of the timestep."""
96+
97+ if self.finished:
98+ raise exceptions.LibadjointErrorInvalidInputs(
99+ "time.next() called after simulation finished!")
100+
101+ if self.time_levels==[]:
102+ raise exceptions.LibadjointErrorInvalidInputs(
103+ "time.next() called before time started!")
104+
105+ self.time_levels.append(time)
106+ timestep = len(self.time_levels) - 2
107+ self.adjointer.set_times(timestep, self.time_levels[-2], self.time_levels[-1])
108+
109+ def reset(self):
110+ self.__init__(self.adjointer)
111+
112+
113 class Adjointer(object):
114 def __init__(self, adjointer=None):
115 self.functions_registered = []
116 self.set_function_apis()
117
118- self.equation_timestep=[]
119+ self.equation_timestep = []
120
121+ # This gets clobbered during casting.
122+ self.time = AdjointerTime(self)
123+
124 if adjointer is None:
125 self.adjointer = clib.adj_adjointer()
126 clib.adj_create_adjointer(self.adjointer)
127@@ -688,6 +744,7 @@
128 self.adjointer_created = True
129 self.c_object = self.adjointer
130 self.__register_data_callbacks__()
131+ self.time.reset()
132
133 def __del__(self):
134 if self.adjointer_created:
135@@ -706,6 +763,10 @@
136 timestep_count = ctypes.c_int()
137 clib.adj_timestep_count(self.adjointer, timestep_count)
138 return timestep_count.value
139+ if name == "finished":
140+ finished = ctypes.c_int()
141+ clib.adj_get_finished(self.adjointer, finished)
142+ return finished.value
143 else:
144 raise AttributeError(name)
145
146@@ -767,7 +828,7 @@
147
148 clib.adj_register_parameter_source_callback(self.adjointer, str(parameter), cfunc)
149
150- def __set_functional_dependencies__(self, functional, timestep):
151+ def set_functional_dependencies(self, functional, timestep):
152
153 dependencies = functional.dependencies(self,timestep)
154
155@@ -819,7 +880,7 @@
156 Evaluate the functional provided at t=timestep.'''
157
158 self.__register_functional__(functional)
159- self.__set_functional_dependencies__(functional, timestep)
160+ self.set_functional_dependencies(functional, timestep)
161
162 output=clib.c_double()
163
164@@ -862,7 +923,7 @@
165 def get_adjoint_equation(self, equation, functional):
166
167 self.__register_functional__(functional)
168- self.__set_functional_dependencies__(functional, self.equation_timestep[equation])
169+ self.set_functional_dependencies(functional, self.equation_timestep[equation])
170
171 lhs = clib.adj_matrix()
172 rhs = clib.adj_vector()
173@@ -878,7 +939,7 @@
174 def get_adjoint_solution(self, equation, functional):
175
176 self.__register_functional__(functional)
177- self.__set_functional_dependencies__(functional, self.equation_timestep[equation])
178+ self.set_functional_dependencies(functional, self.equation_timestep[equation])
179
180 output = clib.adj_vector()
181 adj_var = clib.adj_variable()
182@@ -947,6 +1008,16 @@
183 def forget_tlm_values(self, equation):
184 clib.adj_forget_tlm_values(self.adjointer, equation)
185
186+ def set_times(self, timestep, start, end):
187+ clib.adj_timestep_set_times(self.adjointer, timestep, start, end)
188+
189+ def get_times(self, timestep):
190+ start = adj_scalar()
191+ end = adj_scalar()
192+
193+ clib.adj_timestep_get_times(self.adjointer, timestep, start, end)
194+ return (start.value, end.value)
195+
196 def __register_data_callbacks__(self):
197 self.__register_data_callback__('ADJ_VEC_DUPLICATE_CB', self.__vec_duplicate_callback__)
198 self.__register_data_callback__('ADJ_VEC_DESTROY_CB', self.__vec_destroy_callback__)
199
200=== modified file 'src/adj_adjointer_routines.c'
201--- src/adj_adjointer_routines.c 2012-06-27 10:54:40 +0000
202+++ src/adj_adjointer_routines.c 2012-07-03 15:37:21 +0000
203@@ -62,6 +62,8 @@
204 adjointer->parameter_source_list.firstnode = NULL;
205 adjointer->parameter_source_list.lastnode = NULL;
206
207+ adjointer->finished = ADJ_FALSE;
208+
209 for (i = 0; i < ADJ_NO_OPTIONS; i++)
210 adjointer->options[i] = 0; /* 0 is the default for all options */
211
212@@ -2437,6 +2439,7 @@
213 int adj_timestep_set_functional_dependencies(adj_adjointer* adjointer, int timestep, char* functional, int ndepends, adj_variable* dependencies)
214 {
215 int i;
216+ int j;
217 int ierr;
218
219 adj_functional_data* functional_data_ptr = NULL;
220@@ -2511,6 +2514,21 @@
221 /* Record that this variable is necessary for the functional evaluation at this point in time */
222 ierr = adj_append_unique(&(data_ptr->depending_timesteps), &(data_ptr->ndepending_timesteps), timestep);
223 if (ierr != ADJ_OK) return adj_chkierr_auto(ierr);
224+
225+ /* Set that the j'th dependency is necessary for this guy's adjoint equation */
226+ for (j = 0; j < ndepends; j++)
227+ {
228+ adj_variable_data* other_data_ptr;
229+ ierr = adj_find_variable_data(&(adjointer->varhash), &(dependencies[j]), &other_data_ptr);
230+ if (ierr == ADJ_ERR_HASH_FAILED)
231+ continue;
232+
233+ if (other_data_ptr->equation >= 0)
234+ {
235+ ierr = adj_append_unique(&(data_ptr->adjoint_equations), &(data_ptr->nadjoint_equations), other_data_ptr->equation);
236+ if (ierr != ADJ_OK) return adj_chkierr_auto(ierr);
237+ }
238+ }
239 }
240 /* We are done */
241 return ADJ_OK;
242@@ -2743,3 +2761,14 @@
243 return ADJ_OK;
244 }
245
246+int adj_set_finished(adj_adjointer* adjointer, int finished)
247+{
248+ adjointer->finished = finished;
249+ return ADJ_OK;
250+}
251+
252+int adj_get_finished(adj_adjointer* adjointer, int* finished)
253+{
254+ *finished = adjointer->finished;
255+ return ADJ_OK;
256+}
257
258=== modified file 'src/adj_fortran.F90'
259--- src/adj_fortran.F90 2012-04-12 15:46:20 +0000
260+++ src/adj_fortran.F90 2012-07-03 15:37:21 +0000
261@@ -145,6 +145,8 @@
262 type(adj_func_callback_list) :: functional_list
263 type(adj_func_deriv_callback_list) :: functional_derivative_list
264 type(adj_parameter_source_callback_list) :: parameter_source_list
265+
266+ integer(kind=c_int) :: finished
267 end type adj_adjointer
268
269 type, bind(c) :: adj_vector

Subscribers

People subscribed via source and target branches