DUNE-ACFEM (2.5.1)

transientadaptivealgorithm.hh
1#ifndef __DUNE_ACFEM_ALGORITHMS_TRANSIENT_ADAPTIVE_ALGORITHM_HH__
2#define __DUNE_ACFEM_ALGORITHMS_TRANSIENT_ADAPTIVE_ALGORITHM_HH__
3
4#include <dune/fem/solver/timeprovider.hh>
5#include "../algorithms/femschemeinterface.hh"
6
7// for log-file
8#include <fstream>
9
10namespace Dune {
11
12 namespace ACFem {
13
42 template<class TimeProvider>
43 static inline
44 double adaptiveAlgorithm(TransientAdaptiveFemScheme& scheme,
45 TimeProvider& timeProvider,
46 double endTime,
47 const std::string& prefix_ = "")
48 {
49 std::string prefix = prefix_ == std::string("") ? prefix_ : prefix_ + ".";
50
51 const bool verbose = Dune::Fem::Parameter::getValue<int>("fem.verboserank", -1) != -1;
52
53 bool restart = Dune::Fem::Parameter::getValue<bool>(prefix + "restart", false);
54
55 // initialtimeStep from initilized TimeProvider.
56 double timeStep = timeProvider.deltaT();
57 // The time-step and mu are intentionally non-const. timeStep is
58 // only the initial time-step size for the "implicit"
59 // time-adaptation method
60
61 const double tolerance = Dune::Fem::Parameter::getValue<double>(prefix + "adaptation.tolerance", 1e-2);
62 const double initialTolerance =
63 tolerance * Dune::Fem::Parameter::getValue<double>(prefix + "adaptation.initialToleranceFraction", 0.2);
64 const double spaceTolerance =
65 tolerance * Dune::Fem::Parameter::getValue<double>(prefix + "adaptation.spaceToleranceFraction", 0.4);
66 const double timeTolerance =
67 tolerance * Dune::Fem::Parameter::getValue<double>(prefix + "adaptation.timeToleranceFraction", 0.4);
68 const double minDeltaT =
69 Dune::Fem::Parameter::getValue<double>(prefix + "adaptation.time.minimalStep", -1);
70 const double maxDeltaT =
71 Dune::Fem::Parameter::getValue<double>(prefix + "adaptation.time.maximalStep", -1);
72
73 const int maximumIterations =
74 Dune::Fem::Parameter::getValue<int>(prefix + "adaptation.maximumIterations", 10);
75 const int spaceMaximumIterations =
76 Dune::Fem::Parameter::getValue<int>(prefix + "adaptation.space.maximumIterations", 10);
77 const int initialMaximumIterations =
78 Dune::Fem::Parameter::getValue<int>(prefix + "adaptation.initial.maximumIterations", 10);
79
80 const std::string timeStrategyNames[] = { "explicit", "implicit" };
81 enum { explicitTimeStrategy, implicitTimeStrategy }; // by purpose explicit == false
82 const int timeStrategy = Dune::Fem::Parameter::getEnum(prefix + "adaptation.time.strategy", timeStrategyNames, explicitTimeStrategy);
83 const double timeNarrowFactor = Dune::Fem::Parameter::getValue<double>(prefix + "adaptation.time.narrowFactor", M_SQRT1_2);
84 const double timeRelaxFactor = Dune::Fem::Parameter::getValue<double>(prefix + "adaptation.time.relaxFactor", M_SQRT2);
85 const double timeRelaxTolerance =
86 timeTolerance * Dune::Fem::Parameter::getValue<double>(prefix + "adaptation.time.relaxToleranceFraction", 0.3);
87
88 // construct a file-name template in order to dump statistical data to disk
89 int writeCount = 0;
90 std::string dataPath = Dune::Fem::Parameter::commonOutputPath() + "/";
91 dataPath += Dune::Fem::Parameter::getValue<std::string>("fem.io.path", "./") + "/";
92
93 /*
94 *
95 ****************************************************************************
96 *
97 * Algorithm starts from here. First try to create a good initial
98 * approximation, then run the adaptive space-time method which is
99 * also implemented in the ALBERTA toolbox
100 *
101 */
102
103 /******************** Compute an initial approximation *********************/
104
105 double maxError;
106 double maxEstimate;
107 double estimate;
108
109 Dune::Fem::persistenceManager << maxError;
110 Dune::Fem::persistenceManager << maxEstimate;
111
112 if (restart) {
113 scheme.restart(/* checkpoint name taken from parameter file */);
114 } else {
115 scheme.initialize();
116
117 // Compute an initial estimate
118 estimate = scheme.initialEstimate();
119
120 int cnt = 0;
121 while (estimate > initialTolerance && ++cnt < initialMaximumIterations) {
122
123 // mark element for adaptation
124 scheme.initialMarking(initialTolerance);
125
126 // actual refine or coarsen
127 scheme.adapt();
128
129 // Compute initial approximation
130 scheme.initialize();
131
132 estimate = scheme.initialEstimate();
133 }
134 assert(cnt < initialMaximumIterations);
135
136 maxError = estimate; // actually the initial error
137 maxEstimate = 0.0;
138
139 scheme.output();
140 }
141
142 if (timeStrategy == explicitTimeStrategy) {
143
144 /****************** variant with fixed time step size ********************/
145
146 // ??? really ???
147 //estimate = scheme.estimate();
148 //maxEstimate = std::max(maxEstimate, estimate);
149
150 // time loop
151 while (timeProvider.time() < endTime) {
152
153 if (Dune::Fem::Parameter::verbose()) {
154 std::cout << "**** Starting time-step " << timeProvider.timeStep() << "@" << timeProvider.time() << std::endl;
155 }
156
157 if ( timeProvider.timeStep() > 0 ) {
158 // Mark for refinement and coarsening
159 scheme.mark(spaceTolerance);
160
161 // adapt the mesh
162 scheme.adapt();
163 }
164
165 // solve on the new mesh
166 scheme.solve();
167
168 // estimate the error
169 estimate = scheme.estimate();
170
171 int cnt = 0;
172
173 while (estimate > spaceTolerance && cnt < spaceMaximumIterations ) {
174 // Mark for refinement and coarsening
175 scheme.mark(spaceTolerance);
176
177 // adapt the mesh
178 scheme.adapt();
179
180 // solve on the new mesh
181 scheme.solve();
182
183 // estimate the error
184 estimate = scheme.estimate();
185
186 ++cnt;
187 }
188
189 // Switch to the next time step in order to be able to
190 // compute the exact "error".
191 scheme.next();
192 timeProvider.next(timeStep);
193
194 // calculate standard error
195 double error = scheme.error();
196
197 if (Dune::Fem::Parameter::verbose()) {
198 std::cout << "Error: " << error << std::endl;
199 std::cout << "Estimate: " << estimate << std::endl;
200 }
201
202 maxError = std::max(error, maxError);
203 maxEstimate = std::max(estimate + scheme.timeEstimate(), maxEstimate);
204
205 // write fem data
206 if ((writeCount = scheme.output()) >= 0) {
207 // FIXME: should in principle only generated on one machine
208 std::string name = Dune::Fem::generateFilename(dataPath + prefix_ + "-errorlog", writeCount);
209 std::ofstream f;
210 f.open(name, std::ios::out|std::ios::trunc);
211
212 f << std::scientific << std::setprecision( 18 );
213 f <<
214 "#TimeStep "
215 "Time "
216 "DeltaT "
217 "Estimate "
218 "Error "
219 "Dofs" << std::endl;
220 f << std::setw(10) << std::left << timeProvider.timeStep() - 1 // already at next step
221 << std::setw(30) << timeProvider.time() // already at next step
222 << std::setw(30) << timeStep // old == new step size
223 << std::setw(30) << estimate
224 << std::setw(30) << error
225 << std::setw(30) << scheme.size()
226 << std::endl;
227
228 f.close();
229 }
230 }
231
232 } else { // implicitTimeStrategy
233
234 /***************** variant with adaptive time step size ******************/
235
236 // time loop
237 while (timeProvider.time() < endTime) {
238
239 double spaceEstimate;
240 double timeEstimate;
241
242 if (Dune::Fem::Parameter::verbose()) {
243 std::cout << "**** Starting time-step " << timeProvider.timeStep() << "@" << timeProvider.time() << std::endl;
244 }
245
246 int cnt = 0;
247 do {
248
249 if (Dune::Fem::Parameter::verbose()) {
250 std::cout << "Solving with step-size " << timeStep << std::endl;
251 }
252
253 // solve on the new mesh
254 scheme.solve();
255
256 // estimate the error
257 spaceEstimate = scheme.estimate();
258 timeEstimate = scheme.timeEstimate();
259
260 if (Dune::Fem::Parameter::verbose()) {
261 std::cout << "spaceEstimate " << spaceEstimate << " (tolerance: " << spaceTolerance << ")" << std::endl
262 << "timeEstimate " << timeEstimate << " (tolerance: " << timeTolerance << ")" << std::endl;
263 }
264
265 if (++cnt > maximumIterations) {
266 // or terminate with error?
267 break;
268 }
269
270 // First reduce the time-error
271 if (timeEstimate > timeTolerance && timeStep > minDeltaT) {
272 timeStep *= timeNarrowFactor;
273 timeStep = std::max(minDeltaT, timeStep);
274 timeProvider.init(timeStep);
275 continue;
276 }
277
278 // Space adaptivity loop
279 int spaceCnt = 0;
280 do {
281 // Mark for refinement and coarsening
282 if (scheme.mark(spaceTolerance)) {
283 scheme.adapt();
284 scheme.solve();
285 spaceEstimate = scheme.estimate();
286 timeEstimate = scheme.timeEstimate();
287 if (timeEstimate > timeTolerance && timeStep > minDeltaT) {
288 if (Dune::Fem::Parameter::verbose()) {
289 std::cout << "Estimate: " << timeEstimate
290 << " (tolerance: " << timeTolerance << ")"
291 << std::endl;
292 std::cout << "timeEstimate > timeTolerance, restart"
293 << std::endl;
294 }
295 timeStep *= timeNarrowFactor;
296 timeStep = std::max(minDeltaT, timeStep);
297 timeProvider.init(timeStep);
298 break;
299 }
300 }
301 if (++spaceCnt > spaceMaximumIterations) {
302 break;
303 }
304 } while (spaceEstimate > spaceTolerance);
305 } while (timeEstimate > timeTolerance);
306
307 if (timeEstimate <= timeRelaxTolerance) {
308 timeStep *= timeRelaxFactor;
309 if (maxDeltaT > 0) {
310 timeStep = std::min(maxDeltaT, timeStep);
311 }
312 }
313
314 // Switch to the next time step in order to be able to
315 // compute the exact "error".
316
317 scheme.next();
318
319 // remember for statistics
320 double oldDeltaT = timeProvider.deltaT();
321 timeProvider.next(timeStep);
322
323 // calculate error
324 double error = scheme.error();
325
326 if (verbose) {
327 size_t size = scheme.size();
328 if (Dune::Fem::Parameter::verbose()) {
329 std::cout << "Error : " << error << std::endl;
330 std::cout << "Space Estimate: " << spaceEstimate << std::endl;
331 std::cout << "Time Estimate : " << timeEstimate << std::endl;
332 std::cout << "#DoFs : " << size << std::endl;
333 }
334 }
335
336 maxError = std::max(error, maxError);
337 maxEstimate = std::max(spaceEstimate + timeEstimate, maxEstimate);
338
339 // write fem data
340 if ((writeCount = scheme.output()) >= 0) {
341 // FIXME: should in principle only generated on one machine
342 std::string name = Dune::Fem::generateFilename(dataPath + prefix_ + "-errorlog", writeCount);
343 std::ofstream f;
344 f.open(name, std::ios::out|std::ios::trunc);
345
346 f << std::scientific << std::setprecision( 18 );
347 f <<
348 "#TimeStep "
349 "Time "
350 "DeltaT "
351 "spaceEstimate "
352 "timeEstimate "
353 "Estimate "
354 "Error "
355 "Dofs" << std::endl;
356 f << std::setw(10) << std::left << timeProvider.timeStep() - 1 // already at next step
357 << std::setw(30) << timeProvider.time() // already at next step
358 << std::setw(30) << oldDeltaT // already at next step
359 << std::setw(30) << spaceEstimate
360 << std::setw(30) << timeEstimate
361 << std::setw(30) << spaceEstimate + timeEstimate
362 << std::setw(30) << error
363 << std::setw(30) << scheme.size()
364 << std::endl;
365
366 f.close();
367 }
368
369 }
370
371 }
372
373 return maxEstimate;
374 }
375
377
378 } // ACFem
379
380} // Dune
381
382#endif // __DUNE_ACFEM_ALGORITHMS_TRANSIENT_ADAPTIVE_ALGORITHM_HH__
static std::pair< double, double > adaptiveAlgorithm(AdaptiveFemScheme &scheme, const std::string &prefix_="")
Stationary adaptive algorithm like adapt_method_stat() from poor old ALBERTA.
Definition: stationaryadaptivealgorithm.hh:39
LocalFunctionWrapper< LocalMaxAdapter< GridFunction1, GridFunction2 >, typename GridFunction1::GridPartType > max(const Fem::Function< typename GridFunction1::FunctionSpaceType, GridFunction1 > &f1, const Fem::Function< typename GridFunction2::FunctionSpaceType, GridFunction2 > &f2, const std::string &name="")
Pointwise maximum of two given functions.
Definition: maxfunction.hh:121
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Mar 12, 23:28, 2025)