Peano
Loading...
Searching...
No Matches
DGCGCoupling.py
Go to the documentation of this file.
1from peano4.solversteps.ActionSet import ActionSet
2
3import dastgen2
4import peano4
5import jinja2
6
7
9 cg_solver,
10 ):
11 """!
12
13 Prepare CG solver for coupling and ensure that both solvers are invoked in the correct order
14
15 Throughtout the mesh traversal steps from coarse to fine grid (descend), the
16 DG solver is to be executed before(!) the CG solver. It is the DG solver
17 which we equip with a preprocessing step, so we know that we are on the safe
18 side here.
19
20 We also introduce a new helper value for the CG solver: newValue has,
21 after each traversal, the injected value of the solution. We can then roll
22 it over if we aim for a FAS-type implementation. Further to that, we have
23 the solvers new rhs, which we again use for the next iteration, and its
24 previous (old) value which we use to compute the delta.
25
26 @see AbstractDGCGCoupling for a description of where the individual values are used.
27
28 """
29 assert cg_solver._unknowns_per_vertex_node==dg_solver._unknowns_per_cell_node
30 cg_solver._vertex_data.data.add_or_replace_attribute( peano4.dastgen2.Peano4DoubleArray( "sumOfInjectedValues", str(cg_solver._unknowns_per_vertex_node) ) )
31 cg_solver._vertex_data.data.add_or_replace_attribute( peano4.dastgen2.Peano4DoubleArray( "oldU", str(cg_solver._unknowns_per_vertex_node) ) )
32 cg_solver._vertex_data.data.add_or_replace_attribute( peano4.dastgen2.Peano4DoubleArray( "newRestrictedRhs", str(cg_solver._unknowns_per_vertex_node) ) )
33 cg_solver._vertex_data.data.add_or_replace_attribute( peano4.dastgen2.Peano4DoubleArray( "delta", str(cg_solver._unknowns_per_vertex_node) ) )
34 cg_solver._vertex_data.data.add_or_replace_attribute( dastgen2.attributes.Integer( "numberOfRestrictions" ) )
35
36
38 """!
39
40 Couple the solution and updates of two different solvers
41
42
43 ## Usage
44
45 This action set has to be used as a preprocessing step of the CG:
46
47 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
48 solver.preprocessing_action_set = mghype.matrixfree.solvers.api.actionsets.AbstractDGCGCoupling(
49 solver, # dg_solver
50 ...
51 )
52 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
53
54 I recommend not to use the coupling directly, but one of its subclasses.
55
56
57 ## Behaviour
58
59 We have a new variable SumOfInjectedValues. This one is set to zero at the end
60 of touchVertexFirstTime(), i.e. at the begin of a mesh sweep. In each fine
61 grid cell, i.e. each cell carrying a DG polynomial, we evaluate this
62 polynomial's value in the @f$ 2^d @f$ vertices (corners) of the cell. Of
63 these values, we restrict @f$ 2^{=-d} @f$th of its value to the next coarser
64 mesh level. Prior to the start of a new mesh sweep, SumOfInjectedValues holds
65 the average value of the solution in a vertex. This is just before we
66 clear it again, i.e. we can plug into touchVertexFirstTime() just before we
67 clear this field to read our a coarsened representation of the solution at
68 this point.
69
70
71
72 ## Realisation
73
74 This class takes the solution of a DG solver and injects the current solution
75 onto the vertices. For this, it simply averages the @f$ 2^d @f$ different
76 values of the DG polynomials into the vertex. We do this only for unrefined
77 vertices obviously.
78
79 To realise this behaviour, we rely on functions held within
80 AbstractDGCGCoupling.h.
81 It is important that prepare_and_order_DG_CG_solvers() has been invoked for
82 the two solvers whenever we use this action set.
83
84 """
85
86
87 __TemplateTouchVertexFirstTime="""
88 if (
89 fineGridVertex{{CG_SOLVER_NAME}}.getType() != vertexdata::{{CG_SOLVER_NAME}}::Type::Coarse
90 ) {
91
92 if ({{PREDICATE_INJECT_AND_RESTRICT}}) {
93 mghype::matrixfree::solvers::dgcgcoupling::rollOverAndPrepareCGVertex(
94 fineGridVertex{{CG_SOLVER_NAME}},
95 true, // restrictRhsAndInjectSolution
96 {{USE_FAS}}
97 );
98 }
99
100
101 /*
102 We aim to visit this section just before we prolongate. Passing false to
103 restrictRhsAndInjectSolution has the effect of setting delta to the "value"
104 parameter, ie we pick up the final solution to be interpolated during
105 touchCellFirstTime.
106 */
107 else if ( {{PREDICATE_PROLONGATE}} ) {
108 mghype::matrixfree::solvers::dgcgcoupling::rollOverAndPrepareCGVertex(
109 fineGridVertex{{CG_SOLVER_NAME}},
110 false, // restrictRhsAndInjectSolution
111 {{USE_FAS}}
112 );
113 }
114 }
115 """
116
117
118 templateTouchCellFirstTime="""
119 // ============================
120 // Interpolation
121 // ============================
122 const double additiveMultigridRelaxation = 0.0;
123 if (
124 fineGridCell{{DG_SOLVER_NAME}}.getType() != celldata::{{DG_SOLVER_NAME}}::Type::Coarse
125 and
126 {{PREDICATE_PROLONGATE}}
127 ) {
128 logTraceInWith2Arguments("Prolongate()", (bool)({{PREDICATE_PROLONGATE}}), fineGridCell{{DG_SOLVER_NAME}}.toString());
129 constexpr int Cols = TwoPowerD * {{CG_SOLVER_NAME}}::VertexUnknowns;
130 constexpr int Rows = {{DG_SOLVER_NAME}}::NodesPerCell * {{DG_SOLVER_NAME}}::UnknownsPerCellNode;
131
132 static std::vector< tarch::la::Matrix< Rows, Cols, double > > matrices = {
133 {% for MATRIX in PROLONGATION_MATRIX %}
134 {
135 {{MATRIX[0]| join(", ")}}
136 {% for ROW in MATRIX[1:] %}
137 ,{{ROW | join(", ")}}
138 {% endfor %}
139 },
140 {% endfor %}
141 };
142
143 {% if PROLONGATION_MATRIX_SCALING is not defined %}
144 #error No scaling for prolongation matrix available.
145 {% endif %}
146
147 static std::vector<int> scaleFactors = {
148 {% for el in PROLONGATION_MATRIX_SCALING %}
149 {{el}},
150 {% endfor %}
151 };
152
153 tarch::la::Matrix< Rows, Cols, double > composedProlongationMatrix = ::mghype::composeMatrixFromHWeightedLinearCombination( matrices, scaleFactors, marker.h() );
154
155 fineGridCell{{DG_SOLVER_NAME}}.setSolution(
156 mghype::matrixfree::solvers::dgcgcoupling::prolongate<{{DG_SOLVER_NAME}}, {{CG_SOLVER_NAME}}>(
157 composedProlongationMatrix,
158 fineGridCell{{DG_SOLVER_NAME}}.getSolution(),
159 fineGridVertices{{CG_SOLVER_NAME}}
160 )
161 );
162 logTraceOutWith1Argument("Prolongate()", fineGridCell{{DG_SOLVER_NAME}}.toString());
163 }
164"""
165
166
167
168 __TemplateTouchCellLastTime_FAS="""
169 if (
170 fineGridCell{{DG_SOLVER_NAME}}.getType() != celldata::{{DG_SOLVER_NAME}}::Type::Coarse
171 and
172 {{PREDICATE_EVALUATE_RHS}}
173 ) {
174 assertionEquals( {{CG_SOLVER_NAME}}::VertexUnknowns, {{DG_SOLVER_NAME}}::UnknownsPerCellNode );
175
176 // ==========================================
177 // compute and restrict hierarchical residual
178 // ==========================================
179 {
180 static std::vector< tarch::la::Matrix< {{DG_SOLVER_NAME}}::NodesPerCell * {{DG_SOLVER_NAME}}::UnknownsPerCellNode, TwoPowerD * {{CG_SOLVER_NAME}}::VertexUnknowns, double > > prolongationMatrices = {
181 {% for MATRIX in PROLONGATION_MATRIX %}
182 {
183 {{MATRIX[0]| join(", ")}}
184 {% for ROW in MATRIX[1:] %}
185 ,{{ROW | join(", ")}}
186 {% endfor %}
187 },
188 {% endfor %}
189 };
190
191 {% if PROLONGATION_MATRIX_SCALING is not defined %}
192 #error No scaling for injection matrix available.
193 {% endif %}
194
195 static std::vector<int> prolongationMatricesScaleFactors = {
196 {% for el in PROLONGATION_MATRIX_SCALING %}
197 {{el}},
198 {% endfor %}
199 };
200
201 tarch::la::Matrix< {{DG_SOLVER_NAME}}::NodesPerCell * {{DG_SOLVER_NAME}}::UnknownsPerCellNode, TwoPowerD * {{CG_SOLVER_NAME}}::VertexUnknowns, double > composedProlongationMatrix = ::mghype::composeMatrixFromHWeightedLinearCombination( prolongationMatrices, prolongationMatricesScaleFactors, marker.h() );
202
203 static std::vector< tarch::la::Matrix< TwoPowerD * {{CG_SOLVER_NAME}}::VertexUnknowns, {{DG_SOLVER_NAME}}::NodesPerCell * {{DG_SOLVER_NAME}}::UnknownsPerCellNode, double > > restrictionMatrices = {
204 {% for MATRIX in RESTRICTION_MATRIX %}
205 {
206 {{MATRIX[0]| join(", ")}}
207 {% for ROW in MATRIX[1:] %}
208 ,{{ROW | join(", ")}}
209 {% endfor %}
210 },
211 {% endfor %}
212 };
213
214 {% if RESTRICTION_MATRIX_SCALING is not defined %}
215 #error No scaling for injection matrix available.
216 {% endif %}
217
218 static std::vector<int> restrictionMatricesScaleFactors = {
219 {% for el in INJECTION_MATRIX_SCALING %}
220 {{el}},
221 {% endfor %}
222 };
223
224 tarch::la::Matrix< TwoPowerD * {{CG_SOLVER_NAME}}::VertexUnknowns, {{DG_SOLVER_NAME}}::NodesPerCell * {{DG_SOLVER_NAME}}::UnknownsPerCellNode, double > composedRestrictionMatrix = ::mghype::composeMatrixFromHWeightedLinearCombination( restrictionMatrices, restrictionMatricesScaleFactors, marker.h() );
225
226 mghype::matrixfree::solvers::dgcgcoupling::computeAndRestrictHierarchicalResidual<{{DG_SOLVER_NAME}}, {{CG_SOLVER_NAME}}>(
227 composedProlongationMatrix,
228 composedRestrictionMatrix,
229 repositories::{{DG_SOLVER_INSTANCE}}.getMassMatrix( marker.x(), marker.h() ),
230 repositories::{{DG_SOLVER_INSTANCE}}.getLocalAssemblyMatrix(marker.x(), marker.h()),
231 fineGridCell{{DG_SOLVER_NAME}}.getSolution(),
232 fineGridCell{{DG_SOLVER_NAME}}.getRhs(),
233 fineGridVertices{{CG_SOLVER_NAME}}
234 );
235 }
236
237 // ============================
238 // inject solution back (accumulation)
239 // ============================
240 {
241 constexpr int Rows = TwoPowerD * {{CG_SOLVER_NAME}}::VertexUnknowns;
242 constexpr int Cols = {{DG_SOLVER_NAME}}::NodesPerCell * {{DG_SOLVER_NAME}}::UnknownsPerCellNode;
243
244 static std::vector< tarch::la::Matrix< Rows, Cols, double > > injectionMatrices = {
245 {% for MATRIX in INJECTION_MATRIX %}
246 {
247 {{MATRIX[0]| join(", ")}}
248 {% for ROW in MATRIX[1:] %}
249 ,{{ROW | join(", ")}}
250 {% endfor %}
251 },
252 {% endfor %}
253 };
254
255 {% if INJECTION_MATRIX_SCALING is not defined %}
256 #error No scaling for injection matrix available.
257 {% endif %}
258
259 static std::vector<int> injectionMatricesScaleFactors = {
260 {% for el in INJECTION_MATRIX_SCALING %}
261 {{el}},
262 {% endfor %}
263 };
264
265 tarch::la::Matrix< Rows, Cols, double > composedInjectionMatrix = ::mghype::composeMatrixFromHWeightedLinearCombination( injectionMatrices, injectionMatricesScaleFactors, marker.h() );
266
267 mghype::matrixfree::solvers::dgcgcoupling::injectSolution<{{DG_SOLVER_NAME}}, {{CG_SOLVER_NAME}}>(
268 composedInjectionMatrix,
269 fineGridCell{{DG_SOLVER_NAME}}.getSolution(),
270 fineGridVertices{{CG_SOLVER_NAME}}
271 );
272 }
273
274 // ==============
275 // Update counter
276 // ==============
277 mghype::matrixfree::solvers::dgcgcoupling::updateRestrictionCounters(
278 fineGridVertices{{CG_SOLVER_NAME}}
279 );
280 }
281"""
282
283
284 __TemplateTouchCellLastTime_CorrectionScheme="""
285 if (
286 fineGridCell{{DG_SOLVER_NAME}}.getType() != celldata::{{DG_SOLVER_NAME}}::Type::Coarse
287 and
288 {{PREDICATE_EVALUATE_RHS}}
289 ) {
290 logTraceIn("ComputeAndRestrictResidual");
291 assertionEquals( {{CG_SOLVER_NAME}}::VertexUnknowns, {{DG_SOLVER_NAME}}::UnknownsPerCellNode );
292
293 // =============================
294 // compute and restrict residual
295 // =============================
296 {
297 static std::vector< tarch::la::Matrix< TwoPowerD * {{CG_SOLVER_NAME}}::VertexUnknowns, {{DG_SOLVER_NAME}}::NodesPerCell * {{DG_SOLVER_NAME}}::UnknownsPerCellNode, double > > restrictionMatrices = {
298 {% for MATRIX in RESTRICTION_MATRIX %}
299 {
300 {{MATRIX[0]| join(", ")}}
301 {% for ROW in MATRIX[1:] %}
302 ,{{ROW | join(", ")}}
303 {% endfor %}
304 },
305 {% endfor %}
306 };
307
308 {% if RESTRICTION_MATRIX_SCALING is not defined %}
309 #error No scaling for injection matrix available.
310 {% endif %}
311
312 static std::vector<int> restrictionMatricesScaleFactors = {
313 {% for el in INJECTION_MATRIX_SCALING %}
314 {{el}},
315 {% endfor %}
316 };
317
318 tarch::la::Matrix< TwoPowerD * {{CG_SOLVER_NAME}}::VertexUnknowns, {{DG_SOLVER_NAME}}::NodesPerCell * {{DG_SOLVER_NAME}}::UnknownsPerCellNode, double > composedRestrictionMatrix = ::mghype::composeMatrixFromHWeightedLinearCombination( restrictionMatrices, restrictionMatricesScaleFactors, marker.h() );
319
320 // ============================
321 // update the solutions on all 4 adjacent faces so that we
322 // can correctly restrict the residual. by now, all
323 // projections have been set correctly, but we might
324 // redundantly set solutions...
325 // ============================
326
327 // vector to hold "updated" solutions
328 tarch::la::Vector< repositories::{{DG_SOLVER_INSTANCE}}.FaceUnknownsSolution*TwoTimesD, double > faceSolutions;
329
330 for (int f=0; f<TwoPowerD; f++) {
331 for (int s=0; s<repositories::{{DG_SOLVER_INSTANCE}}.FaceUnknownsSolution; s++)
332 faceSolutions( f*repositories::{{DG_SOLVER_INSTANCE}}.FaceUnknownsSolution + s ) = fineGridFaces{{DG_SOLVER_NAME}}(f).getSolution(s);
333 }
334
335 mghype::matrixfree::solvers::dgcgcoupling::computeAndRestrictResidual<{{DG_SOLVER_NAME}}, {{CG_SOLVER_NAME}}>(
336 composedRestrictionMatrix,
337 repositories::{{DG_SOLVER_INSTANCE}}.getMassMatrix( marker.x(), marker.h() ),
338 repositories::{{DG_SOLVER_INSTANCE}}.getLocalAssemblyMatrix(marker.x(), marker.h()),
339 fineGridCell{{DG_SOLVER_NAME}}.getSolution(),
340 fineGridCell{{DG_SOLVER_NAME}}.getRhs(),
341 repositories::{{DG_SOLVER_INSTANCE}}.getCellFromFaceMatrix( marker.x(), marker.h() ) * faceSolutions,
342 fineGridVertices{{CG_SOLVER_NAME}}
343 );
344 }
345
346 // ============================
347 // inject solution back (accumulation)
348 // ============================
349 {
350 constexpr int Rows = TwoPowerD * {{CG_SOLVER_NAME}}::VertexUnknowns;
351 constexpr int Cols = {{DG_SOLVER_NAME}}::NodesPerCell * {{DG_SOLVER_NAME}}::UnknownsPerCellNode;
352
353 static std::vector< tarch::la::Matrix< Rows, Cols, double > > injectionMatrices = {
354 {% for MATRIX in INJECTION_MATRIX %}
355 {
356 {{MATRIX[0]| join(", ")}}
357 {% for ROW in MATRIX[1:] %}
358 ,{{ROW | join(", ")}}
359 {% endfor %}
360 },
361 {% endfor %}
362 };
363
364 {% if INJECTION_MATRIX_SCALING is not defined %}
365 #error No scaling for injection matrix available.
366 {% endif %}
367
368 static std::vector<int> injectionMatricesScaleFactors = {
369 {% for el in INJECTION_MATRIX_SCALING %}
370 {{el}},
371 {% endfor %}
372 };
373
374 tarch::la::Matrix< Rows, Cols, double > composedInjectionMatrix = ::mghype::composeMatrixFromHWeightedLinearCombination( injectionMatrices, injectionMatricesScaleFactors, marker.h() );
375
376 mghype::matrixfree::solvers::dgcgcoupling::injectSolution<{{DG_SOLVER_NAME}}, {{CG_SOLVER_NAME}}>(
377 composedInjectionMatrix,
378 fineGridCell{{DG_SOLVER_NAME}}.getSolution(),
379 fineGridVertices{{CG_SOLVER_NAME}}
380 );
381 }
382
383 // ==============
384 // Update counter
385 // ==============
386 mghype::matrixfree::solvers::dgcgcoupling::updateRestrictionCounters(
387 fineGridVertices{{CG_SOLVER_NAME}}
388 );
389 logTraceOut("ComputeAndRestrictResidual");
390 }
391"""
392
393 def __init__(self,
394 dg_solver,
395 cg_solver,
396 prolongation_matrix,
397 prolongation_matrix_scaling,
398 restriction_matrix,
399 restriction_matrix_scaling,
400 injection_matrix,
401 injection_matrix_scaling,
402 use_fas
403 ):
404 """!
405
406 Construct action set
407
408 @param prolongation_matrix Please consult the action set ComputeAndRestrictBiasedHierarchicalResidual.
409
410 @param prolongation_matrix_scaling Please consult the action set ComputeAndRestrictBiasedHierarchicalResidual.
411
412 @param injection_matrix: [ @f$ \mathbb{R}^{2^dK \times (p+1}^dK } @f$ ]
413 Sequence of matrices. Each takes the solution over the cell spanned by
414 @f$ (p+1}^dK @f$ weights and maps them onto @f$ K @f$ quantities on the
415 vertices. These quantities are typically just the value of the polynomial
416 in the vertex, but you can pick other schemes, too. Most of the time, it
417 will be a single injection (with one scaling, see below). To be in line
418 with the other signatures, you can however specify the total injection through a
419 sequence of matrices, each one with its own @f$ h^s @f$ scaling.
420
421 @param injection_matrix_scaling: [ Integer ]
422 Specifies a sequence of values @f$ s @f$. They define with which
423 @f$ h^s @f$ the corresponding matrices in injection_matrix are to be
424 scaled. That is, if you pass in a [3,0], then the first matrix in
425 injection_matrix will be scaled with @f$ h^3 @f$ and the second one
426 with one. If you work with a simple function evaluation as injection,
427 then you are fine with one matrix, and its scaline will be [ 0 ].
428
429 @param use_fas: Boolean
430 If this flag is set, we realise a FAS following the HTMG idea by
431 Griebel et al.
432
433 """
434 super( AbstractDGCGCoupling, self ).__init__(
435 0, #descend_invocation_order -> will be ignored
436 False # parallel
437 )
438
440 cg_solver,
441 )
442
443 dg_solver._basic_descend_order = cg_solver._basic_descend_order - 1
444
445 self.d = {}
446 self.d["DG_SOLVER_INSTANCE"] = dg_solver.instance_name()
447 self.d["DG_SOLVER_NAME"] = dg_solver.typename()
448 self.d["CG_SOLVER_INSTANCE"] = cg_solver.instance_name()
449 self.d["CG_SOLVER_NAME"] = cg_solver.typename()
450
451 self.d["INJECTION_MATRIX"] = injection_matrix
452 self.d["INJECTION_MATRIX_SCALING"] = injection_matrix_scaling
453 self.d["PROLONGATION_MATRIX"] = prolongation_matrix
454 self.d["PROLONGATION_MATRIX_SCALING"] = prolongation_matrix_scaling
455 self.d["RESTRICTION_MATRIX"] = restriction_matrix
456 self.d["RESTRICTION_MATRIX_SCALING"] = restriction_matrix_scaling
457
458 self.d["PREDICATE_INJECT_AND_RESTRICT"] = "true"
459 self.d["PREDICATE_PROLONGATE"] = "true"
460 self.d["PREDICATE_EVALUATE_RHS"] = "true"
461
462 if use_fas:
463 self.d["USE_FAS"] = "true"
464 self._use_fas = use_fas
465 else:
466 self.d["USE_FAS"] = "false"
467 self._use_fas = use_fas
468
469
470 def get_body_of_operation(self,operation_name):
471 result = ""
472 if operation_name==peano4.solversteps.ActionSet.OPERATION_TOUCH_VERTEX_FIRST_TIME:
473 result = jinja2.Template(self.__TemplateTouchVertexFirstTime).render(**self.d)
474 pass
475 if operation_name==peano4.solversteps.ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME:
476 result = jinja2.Template(self.templateTouchCellFirstTime).render(**self.d)
477 pass
478 if self._use_fas and operation_name==peano4.solversteps.ActionSet.OPERATION_TOUCH_CELL_LAST_TIME:
479 result = jinja2.Template(self.__TemplateTouchCellLastTime_FAS).render(**self.d)
480 pass
481 if not self._use_fas and operation_name==peano4.solversteps.ActionSet.OPERATION_TOUCH_CELL_LAST_TIME:
482 result = jinja2.Template(self.__TemplateTouchCellLastTime_CorrectionScheme).render(**self.d)
483 pass
484 return result
485
487 """!
488
489 Configure name of generated C++ action set
490
491 This action set will end up in the directory observers with a name that
492 reflects how the observer (initialisation) is mapped onto this action
493 set. The name pattern is ObserverName2ActionSetIdentifier where this
494 routine co-determines the ActionSetIdentifier. We make is reflect the
495 Python class name.
496
497 """
498 return __name__.replace(".py", "").replace(".", "_")
499
501 """!
502
503 The action set that Peano will generate that corresponds to this class
504 should not be modified by users and can safely be overwritten every time
505 we run the Python toolkit.
506
507 """
508 return False
509
510 def get_includes(self):
511 """!
512
513 We need the solver repository in this action set, as we directly access
514 the solver object. We also need access to Peano's d-dimensional loops.
515
516 """
517 return """
518#include "../repositories/SolverRepository.h"
519#include "peano4/utils/Loop.h"
520#include "mghype/mghype.h"
521#include "mghype/matrixfree/solvers/DGCGCoupling.h"
522"""
523
524
526 """!
527
528 Introduce additive CC Coupling
529
530 The control logic here is simplistic and prescripted. We follow the
531 following steps for the additive solver with one iteration:
532
533 1. Pre step
534 - Interpolate correction, i.e. sum all the hierarchies up.
535 This happens in touchCellFirstTime().
536 - Compute and restrict residual and inject solution (if FAS).
537 This happens in touchCellLastTime().
538 - Suspend both solvers, but let DG solver project its solution onto the
539 faces.
540 2. Compute step
541 - All solvers compute.
542 - DG solver can project solution onto faces.
543 - Return to step 1.
544
545 Nothing stops us from repeating the step (2) multiple times, which gives
546 us the opportunity to play around with various multigrid schemes.
547 If we are in the last sweep of (2), the projection onto the faces of the
548 DG solver is not necessary. We'll overwrite this solution a minute later
549 anyway.
550
551 ## Realisation
552
553 This action set will map onto a class of its own. We give the class a
554 class attribute which we increment by one in each step. We then make the
555 actual logic depend upon this counter, as we inject the predicates into
556 the superclass: That is, the superclass has some boolean expressions which
557 allow us to switch its features on and off. We make those guys depends upon
558 the new counter.
559
560 """
561 def __init__(self,
562 dg_solver,
563 cg_solver,
564 prolongation_matrix,
565 prolongation_matrix_scaling,
566 restriction_matrix,
567 restriction_matrix_scaling,
568 injection_matrix,
569 injection_matrix_scaling,
570 use_fas,
571 smoothing_steps_per_cycle = 1
572 ):
573 super( AdditiveDGCGCoupling, self ).__init__(
574 dg_solver,
575 cg_solver,
576 prolongation_matrix,
577 prolongation_matrix_scaling,
578 restriction_matrix,
579 restriction_matrix_scaling,
580 injection_matrix,
581 injection_matrix_scaling,
582 use_fas
583 )
584 self.dd["PREDICATE_INJECT_AND_RESTRICT"] = "CycleCounter==0"
585 self.dd["PREDICATE_PROLONGATE"] = "CycleCounter==0"
586 self.dd["PREDICATE_EVALUATE_RHS"] = "CycleCounter==0"
587 self.dd["SMOOTHING_STEPS_PER_CYCLE"] = smoothing_steps_per_cycle
588
589 assert smoothing_steps_per_cycle>=1, "at least one smoothing step required"
590
591
592 def get_attributes(self):
593 """!
594
595 Add a new static attribute to the class.
596
597 """
598 return """
599 static int CycleCounter;
600"""
601
602
603 def get_static_initialisations(self, full_qualified_classname):
604 """!
605
606 Initialise the new counter.
607
608 """
609 return "int " + full_qualified_classname + "::CycleCounter = -1;"
610
611
613 return jinja2.Template( """
614 CycleCounter++;
615
616 if (CycleCounter==0) {
617 logInfo( "prepareTraversal(...)", "pre-step: prolong updates and restrict (new) residual, but do not yet run any solver" );
618 repositories::instanceOf{{CG_SOLVER_NAME}}.suspend();
619 repositories::instanceOf{{DG_SOLVER_NAME}}.suspend(true);
620 }
621 else if (CycleCounter=={{SMOOTHING_STEPS_PER_CYCLE}}) {
622 logInfo( "prepareTraversal(...)", "last smoothing step" );
623 CycleCounter = -1;
624 }
625 else {
626 logInfo( "prepareTraversal(...)", "normal smoothing step" );
627 }
628""").render( **self.dd )
629
630
631
633 """!
634
635 Introduce multiplicative CC Coupling
636
637 The control logic here is simplistic and prescripted. We follow the
638 following steps for the additive solver with one iteration:
639
640 1. Pre First smoothing step
641 - When we touchVertexFirstTime, we pass over rollOverAndPrepareCGVertex,
642 which has the effect of taking whatever is in the CG solution
643 and writing it into the Delta. This is then interpolated during
644 touchCellFirstTime.
645 - Interpolate correction, i.e. sum all the hierarchies up.
646 This happens in touchCellFirstTime().
647 - Suspend CG solver
648 - Suspend DG solver
649 - Let DG solver project data onto faces
650 2. DG smoothing step
651 - Suspend CG solver
652 - Run DG solver
653 3. Nth DG smoothing step
654 - Still run DG solver (finish smoothing)
655 During touchCellLastTime, we:
656 - Compute hierarchical residual
657 - Restrict
658 - Suspend CG solver
659 These steps will set newRestrictedRhs correctly
660 4. Any CG solver
661 On the first CG smoothing step, we should, during
662 touchVertexFirstTime, pass over rollOverAndPrepareCGVertex
663 which takes newRestrictedRhs and writes it into rhs, and
664 we reset value to 0.
665 - Suspend DG solver
666
667 ## Realisation
668
669 This action set will map onto a class of its own. We give the class a
670 class attribute which we increment by one in each step. We then make the
671 actual logic depend upon this counter, as we inject the predicates into
672 the superclass: That is, the superclass has some boolean expressions which
673 allow us to switch its features on and off. We make those guys depends upon
674 the new counter.
675
676 """
677 def __init__(self,
678 dg_solver,
679 cg_solver,
680 prolongation_matrix,
681 prolongation_matrix_scaling,
682 restriction_matrix,
683 restriction_matrix_scaling,
684 injection_matrix,
685 injection_matrix_scaling,
686 use_fas,
687 smoothing_steps_DG = 5,
688 smoothing_steps_CG = -1,
689 ):
690 """!
691
692 Construct the solver
693
694 @param smoothing_steps_DG: positive integer
695
696 @param smoothing_steps_CG: positive integer or -1
697 The -1 indicates that we wait for full convergence on the coarse
698 mesh.
699
700 """
701 super( MultiplicativeDGCGCoupling, self ).__init__(
702 dg_solver,
703 cg_solver,
704 prolongation_matrix,
705 prolongation_matrix_scaling,
706 restriction_matrix,
707 restriction_matrix_scaling,
708 injection_matrix,
709 injection_matrix_scaling,
710 use_fas
711
712 )
713
714 # f-string isn't happy unless i do it like this
715 cg_solver_name = self.dd["CG_SOLVER_NAME"]
716 dg_solver_name = self.dd["DG_SOLVER_NAME"]
717
718 # We have finished DG smoothing, and are on first stage of CG Smoothing. Everything important
719 # happens during touchVertexFirstTime, so we can combine. In particular, touchVertexFirstTime
720 # on the DGCGCoupling action set is where we bring the restrictedRhs to the acutal rhs, ie
721 # prepare us to solve the CG problem again.
722 # We incremented CGCycleCounter after we disabled the DG solver, hence the comparison with 1.
723 self.dd["PREDICATE_INJECT_AND_RESTRICT"] = f"DGCycleCounter>DGSmoothingSteps and CGCycleCounter==1"
724
725 # We've just reset everything, so it's time to interpolate.
726 self.dd["PREDICATE_PROLONGATE"] = f"DGCycleCounter==1 and CGCycleCounter==0"
727
728 # final DG stage. This is where we compute the residual for the CG vertices.
729 # we compare with > because the final time we enter prepareTraversal, DGCycleCounter==DGSmoothingSteps.
730 # Then we increment and continue on the DG solver anyway. Here we compute and restrict the residual
731 # during touchCellLastTime.
732 self.dd["PREDICATE_EVALUATE_RHS"] = f"DGCycleCounter>DGSmoothingSteps and CGCycleCounter==0"
733
734 assert smoothing_steps_DG>=1, "at least one smoothing step required"
735 assert smoothing_steps_CG>=1 or smoothing_steps_CG==-1, "at least one smoothing step required"
736
737 # Logically speaking, the only thing we do on the "final" sweep is send the face solutions down to
738 # the coupler to calculate the residual, which we restrict. So we add on another sweep here so that
739 # we perform the exact number of sweeps that the caller asked for.
740 self.smoothing_steps_DG = smoothing_steps_DG + 1
741 self.smoothing_steps_CG = smoothing_steps_CG
742
743 self.cg_solver = cg_solver
744
745
746 def get_attributes(self):
747 """!
748
749 Add a new static attribute to the class.
750
751 """
752
753 if self.smoothing_steps_CG==-1:
754 smoothing_steps_CG_string = "std::numeric_limits<int>::max()"
755 else:
756 smoothing_steps_CG_string = self.smoothing_steps_CG
757
758 CG_solver_tolerance = self.cg_solver._solver_tolerance
759
760 return """
761 static constexpr int DGSmoothingSteps = {};
762 static constexpr int CGSmoothingSteps = {};
763 static constexpr double CGSolverTolerance = {};
764 static int DGCycleCounter;
765 static int CGCycleCounter;
766""".format(self.smoothing_steps_DG, smoothing_steps_CG_string, CG_solver_tolerance)
767
768
769 def get_static_initialisations(self, full_qualified_classname):
770 """!
771
772 Initialise the new counter.
773
774 """
775 return """
776int """ + full_qualified_classname + """::DGCycleCounter = 0;
777int """ + full_qualified_classname + """::CGCycleCounter = 0;
778"""
779
781 return jinja2.Template( """
782 logTraceInWith3Arguments("PrepareTraversal", DGCycleCounter, CGCycleCounter, repositories::instanceOf{{CG_SOLVER_NAME}}.getGlobalResidualMaxNorm());
783 if (DGCycleCounter>0 and DGCycleCounter<DGSmoothingSteps) {
784 repositories::instanceOf{{CG_SOLVER_NAME}}.suspend();
785 DGCycleCounter++;
786 logInfo( "prepareTraversal(...)", "run DG smoother step, disable CG solver" );
787 }
788 else if (
789 DGCycleCounter>0 and DGCycleCounter==DGSmoothingSteps
790 ) {
791 // same as above, but we need to make sure final update residual is halted
792 logInfo( "prepareTraversal(...)", "run final DG smoother step, disable CG solver" );
793 DGCycleCounter++;
794 repositories::instanceOf{{CG_SOLVER_NAME}}.suspend();
795 repositories::instanceOf{{DG_SOLVER_NAME}}.suspend(false, true);
796 }
797
798 else if (
799 DGCycleCounter>DGSmoothingSteps
800 and
801 CGCycleCounter<CGSmoothingSteps
802 and not
803 (
804 repositories::instanceOf{{CG_SOLVER_NAME}}.getGlobalResidualMaxNorm() > 0.0
805 and
806 repositories::instanceOf{{CG_SOLVER_NAME}}.getGlobalResidualMaxNorm() <= CGSolverTolerance
807 )
808 ) {
809 /*
810 We haven't reached our termination condition for CG solver yet
811 */
812 repositories::instanceOf{{DG_SOLVER_NAME}}.suspend(false, false);
813 CGCycleCounter++;
814 logInfo( "prepareTraversal(...)", "run CG smoother step, disable DG solver. CG residual="<< repositories::instanceOf{{CG_SOLVER_NAME}}.getGlobalResidualMaxNorm());
815 }
816 else {
817 DGCycleCounter = 1;
818 CGCycleCounter = 0;
819 repositories::instanceOf{{DG_SOLVER_NAME}}.suspend(true, false);
820 repositories::instanceOf{{CG_SOLVER_NAME}}.suspend();
821 logInfo( "prepareTraversal(...)", "suspend all solvers, interpolate CG->DG and project new solution onto faces" );
822 }
823 logTraceOutWith5Arguments("PrepareTraversal", DGCycleCounter, CGCycleCounter, repositories::instanceOf{{DG_SOLVER_NAME}}.isSuspended(), repositories::instanceOf{{DG_SOLVER_NAME}}.projectOntoFaces(), repositories::instanceOf{{CG_SOLVER_NAME}}.isSuspended());
824""").render( **self.dd )
Specialisation of dastgen2.attributes.DoubleArray which relies on Peano's tarch.
Action set (reactions to events)
Definition ActionSet.py:6
Couple the solution and updates of two different solvers.
user_should_modify_template(self)
The action set that Peano will generate that corresponds to this class should not be modified by user...
get_includes(self)
We need the solver repository in this action set, as we directly access the solver object.
__init__(self, dg_solver, cg_solver, prolongation_matrix, prolongation_matrix_scaling, restriction_matrix, restriction_matrix_scaling, injection_matrix, injection_matrix_scaling, use_fas)
Construct action set.
get_body_of_operation(self, operation_name)
Return actual C++ code snippets to be inserted into C++ code.
get_action_set_name(self)
Configure name of generated C++ action set.
get_attributes(self)
Add a new static attribute to the class.
get_static_initialisations(self, full_qualified_classname)
Initialise the new counter.
__init__(self, dg_solver, cg_solver, prolongation_matrix, prolongation_matrix_scaling, restriction_matrix, restriction_matrix_scaling, injection_matrix, injection_matrix_scaling, use_fas, smoothing_steps_per_cycle=1)
Construct action set.
get_static_initialisations(self, full_qualified_classname)
Initialise the new counter.
__init__(self, dg_solver, cg_solver, prolongation_matrix, prolongation_matrix_scaling, restriction_matrix, restriction_matrix_scaling, injection_matrix, injection_matrix_scaling, use_fas, smoothing_steps_DG=5, smoothing_steps_CG=-1)
Construct the solver.
get_attributes(self)
Add a new static attribute to the class.
prepare_CG_correction_solvers(dg_solver, cg_solver)
Prepare CG solver for coupling and ensure that both solvers are invoked in the correct order.