Peano
Loading...
Searching...
No Matches
ErrorMeasurement.py
Go to the documentation of this file.
1# This file is part of the Peano project. For conditions of distribution and
2# use, please see the copyright notice at www.peano-framework.org
3import jinja2
4
5from .PDETerms import PDETerms
6
7
9 """!
10 Error measurement tool for ExaHyPE 2 solvers, this is the base class that must
11 be specialised for different solvers.
12
13 Used by calling the corresponding specialisation by calling it using the solver
14 instance as an argument. For an example, see /applications/exahype/aderdg
15 i.e. ErrorMeasurement(solver=theSolver)
16
17 When called, it adds an additional function analyticalSolution() to the user-defined
18 code snippets, through which the user can define what the solution should be.
19
20 The errormeasurement also adds a postprocessing step to the corresponding solver,
21 which computes the L0, L2 and L_inf error between the computed solution and the
22 analytical solution at each data point over the domain. These are then summed up
23 over the entire volume to get the integrated errors over the entire domain.
24
25 Finally, these are added to a GlobalDatabase object by the global master thread, and
26 outputted to csv files at regular intervals.
27
28 @parameters:
29
30 solver: the solver for which the errors should be measured
31
32 error_measurement_implementation: allows one to specify the analytical
33 solution directly instead of manually filling it in the user-defined
34 code snippets, analogously to fluxes and such in the solvers.
35
36 delta_between_database_flushes: how often should the entire database be
37 printed to a file. By default the database is only printed once at the
38 end of the entire simulation, but this parameters can be used to produce
39 intermediary results
40
41 output_file_name: specify what the output .csv files should be named
42
43 data_delta_between_snapshots: which data deltas should be used for the
44 database, i.e. if a measurement already exists for the given timestamp
45 but the difference is greater than this value, the existing measurement
46 is replaced.
47
48 time_delta_between_snapshots: how often a new measurement should be added
49 to the database. By default the database is updated every timestep, but
50 using this parameter it can be set to only happen at regular intervals,
51 analogously to plotting in ExaHyPE2.
52
53 clear_database_after_flush: If the parameter "delta_between_database_flushes"
54 has been set and several database flushes are going to occur, this
55 parameter can be used to flush the database between each flush in order
56 to avoid printing redundant information.
57
58 """
59
61 self,
62 solver,
63 error_measurement_implementation,
64 delta_between_database_flushes,
65 output_file_name,
66 data_delta_between_snapshots,
67 time_delta_between_snapshots,
68 clear_database_after_flush,
69 ):
70 solver._constructor_implementation += (
72 delta_between_database_flushes=delta_between_database_flushes,
73 output_file_name=output_file_name,
74 data_delta_between_snapshots=data_delta_between_snapshots,
75 time_delta_between_snapshots=time_delta_between_snapshots,
76 clear_database_after_flush=clear_database_after_flush,
77 )
78 )
79
80 solver.add_user_solver_includes(
81 """
82#include "toolbox/blockstructured/GlobalDatabase.h"
83"""
84 )
85
86 solver._abstract_solver_user_declarations += """
87public:
88 toolbox::blockstructured::GlobalDatabase _errorDatabase;
89 double _errors[3] = {0.0, 0.0, 0.0};
90 void setError(double* error);
91"""
92
93 solver._abstract_solver_user_definitions += """
94void {{"{{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}"}}::setError(double* error) {
95 tarch::multicore::Lock lock(_semaphore);
96 _errors[0] += error[0];
97 _errors[1] += error[1];
98 _errors[2] = std::max(_errors[2], error[2]);
99}
100"""
101
102 if error_measurement_implementation == PDETerms.User_Defined_Implementation:
103 print(error_measurement_implementation)
104 print(PDETerms.User_Defined_Implementation)
105 solver._solver_user_declarations += create_solver_user_declarations()
106 solver._solver_user_definitions += create_solver_user_definitions()
107 solver._abstract_solver_user_declarations += (
109 )
110 else:
111 solver._abstract_solver_user_definitions += (
113 error_measurement_implementation
114 )
115 )
116 solver._abstract_solver_user_declarations += (
118 )
119
120
122 delta_between_database_flushes,
123 output_file_name,
124 data_delta_between_snapshots,
125 time_delta_between_snapshots,
126 clear_database_after_flush,
127):
128 Template = jinja2.Template(
129 """
130 if (tarch::mpi::Rank::getInstance().isGlobalMaster()) {
131 _errorDatabase.setDeltaBetweenTwoDatabaseFlushes({{FLUSH_DELTA}});
132 _errorDatabase.setOutputFileName("{{FILENAME}}");
133 _errorDatabase.setDataName("l0-error,l2-error,l_inf-error");
134 // _errorDatabase.setOutputPrecision({{OUTPUT_PRECISION}});
135 _errorDatabase.setDataDeltaBetweenTwoSnapshots({{DATA_DELTA}}, {{USE_RELATIVE_DELTAS}});
136 _errorDatabase.setTimeDeltaBetweenTwoSnapshots({{TIME_DELTA}});
137 _errorDatabase.clearDatabaseAfterFlush( {{CLEAR_DATABASE_AFTER_FLUSH}});
138 std::fill_n(_errors, 3, 0.0);
139 }
140""",
141 undefined=jinja2.DebugUndefined,
142 )
143
144 d = {}
145 d["FLUSH_DELTA"] = delta_between_database_flushes
146 d["FILENAME"] = output_file_name
147 d["DATA_DELTA"] = data_delta_between_snapshots
148 d["USE_RELATIVE_DELTAS"] = "false"
149 d["TIME_DELTA"] = time_delta_between_snapshots
150 d["CLEAR_DATABASE_AFTER_FLUSH"] = "true" if clear_database_after_flush else "false"
151 return Template.render(**d)
152
153
154def create_finish_time_step_implementation_for_error_measurement(guard):
155 return (
156 """
157 if ("""
158 + guard
159 + """) {
160 #ifdef Parallel
161 double errorsThisTimeStamp[3] = {_errors[0], _errors[1], _errors[2]};
162
163 tarch::mpi::Rank::getInstance().allReduce(
164 &errorsThisTimeStamp[0],
165 &_errors[0],
166 1,
167 MPI_DOUBLE,
168 MPI_SUM,
169 [&]() -> void { tarch::services::ServiceRepository::getInstance().receiveDanglingMessages(); }
170 );
171
172 tarch::mpi::Rank::getInstance().allReduce(
173 &errorsThisTimeStamp[1],
174 &_errors[1],
175 1,
176 MPI_DOUBLE,
177 MPI_SUM,
178 [&]() -> void { tarch::services::ServiceRepository::getInstance().receiveDanglingMessages(); }
179 );
180
181 tarch::mpi::Rank::getInstance().allReduce(
182 &errorsThisTimeStamp[2],
183 &_errors[2],
184 1,
185 MPI_DOUBLE,
186 MPI_MAX,
187 [&]() -> void { tarch::services::ServiceRepository::getInstance().receiveDanglingMessages(); }
188 );
189 #endif
190
191 if (tarch::mpi::Rank::getInstance().isGlobalMaster()) {
192 _errors[1] = std::sqrt(_errors[1]);
193 _errorDatabase.addGlobalSnapshot(_minTimeStampThisTimeStep, 3, _errors);
194 }
195
196 std::fill_n(_errors, 3, 0.0);
197 }
198"""
199 )
200
201
203 return (
204 """
205 /**
206 * Exact solution of the equation at a given point and time
207 *
208 * @param x Position
209 * @param t Time
210 * @param dt Timestep size
211 * @param sol Analytical solution of the equation
212 */
213 virtual void analyticalSolution(
214 const tarch::la::Vector<Dimensions, double>& x,
215 const double t,
216 const double dt,
217 const double* Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
218 double* solution // solution[{{NUMBER_OF_UNKNOWNS}}]
219 )"""
220 + (" = 0" if user_defined else " final")
221 + ";"
222 )
223
224
225def create_solver_user_abstract_definitions(error_measurement_implementation):
226 return (
227 """
228 void {{"{{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}"}}::analyticalSolution(
229 const tarch::la::Vector<Dimensions, double>& x,
230 const double t,
231 const double dt,
232 const double* Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
233 double* solution // solution[{{NUMBER_OF_UNKNOWNS}}]
234 ) {
235"""
236 + error_measurement_implementation
237 + """
238}
239"""
240 )
241
242
244 return """
245 virtual void analyticalSolution(
246 const tarch::la::Vector<Dimensions, double>& x,
247 const double t,
248 const double dt,
249 const double* Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
250 double* solution // solution[{{NUMBER_OF_UNKNOWNS}}]
251 ) override;
252"""
253
254
256 return """
257 void {{"{{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}"}}::analyticalSolution(
258 const tarch::la::Vector<Dimensions, double>& x,
259 const double t,
260 const double dt,
261 const double* Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
262 double* solution // solution[{{NUMBER_OF_UNKNOWNS}}]
263 ) {
264 logTraceInWith2Arguments("analyticalSolution(...)", x, t);
265
266 // @todo Implement your stuff here
267
268 logTraceOut("analyticalSolution(...)");
269 }
270"""
Error measurement tool for ExaHyPE 2 solvers, this is the base class that must be specialised for dif...
__init__(self, solver, error_measurement_implementation, delta_between_database_flushes, output_file_name, data_delta_between_snapshots, time_delta_between_snapshots, clear_database_after_flush)
create_solver_user_abstract_definitions(error_measurement_implementation)
create_solver_user_abstract_declarations(user_defined)
create_constructor_implementation_for_error_measurement(delta_between_database_flushes, output_file_name, data_delta_between_snapshots, time_delta_between_snapshots, clear_database_after_flush)