12 Action set implementing the facet update of the continuous Galerkin solver
14 There are two key elements/events here:
16 - When we hit the face, we compute the update due to the Jacobi solver and
17 subsequently clear all the data that is accumulated. We don't need it
18 anymore as we have already determined the face update.
19 - When we hit the cell, we first map the facet update onto the cell. Now we
20 have an updated cell guess. After that, we immediately compute the residual
21 and throw it back onto the facet.
23 The latter step might seem to be stupid: After all, we could first update the
24 cell interior and then use the updated solution to determine a residual for
25 the facet. This would be a proper block-Jacobi. However, I prefer a pure
26 Jacobi here, as it allows us to deploy the block update onto a separate task.
28 The key properties of the solver that we use here are the following ones:
30 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31self._degrees_of_freedom_per_cell = unknowns_per_node * ( polynomial_degree + 1) ** dimensions
32self._degrees_of_freedom_per_face = unknowns_per_node * ( polynomial_degree + 1) ** (dimensions-1)
33self._inner_degrees_of_freedom_per_cell = unknowns_per_node * ( polynomial_degree - 1) ** dimensions
35self._cell_data.data.add_attribute(peano4.dastgen2.Peano4DoubleArray( "solution", str(self._degrees_of_freedom_per_cell) ))
36self._cell_data.data.add_attribute(peano4.dastgen2.Peano4DoubleArray( "residual", str(self._degrees_of_freedom_per_cell) ))
37self._cell_data.data.add_attribute(peano4.dastgen2.Peano4DoubleArray( "rhs", str(self._degrees_of_freedom_per_cell) ))
39self._face_data.data.add_attribute(peano4.dastgen2.Peano4DoubleArray( "residual", str(self._degrees_of_freedom_per_face) ))
40self._face_data.data.add_attribute(peano4.dastgen2.Peano4DoubleArray( "diagonal", str(self._degrees_of_freedom_per_face) ))
41self._face_data.data.add_attribute(peano4.dastgen2.Peano4DoubleArray( "deltaU", str(self._degrees_of_freedom_per_face) ))
42 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47 templateTouchFaceFirstTime=
"""
49 fineGridFace{{SOLVER_NAME}}.getType() == facedata::{{SOLVER_NAME}}::Type::Interior
51 repositories::{{SOLVER_INSTANCE}}.updateFace()
53 logTraceInWith3Arguments( "touchFaceFirstTime", fineGridFace{{SOLVER_NAME}}.getResidual(), fineGridFace{{SOLVER_NAME}}.getDiagonal(), marker.toString() );
55 for (int i=0; i<repositories::{{SOLVER_INSTANCE}}.FaceUnknowns; i++) {
56 // in the first step, diagonal is zero
57 if ( tarch::la::equals(fineGridFace{{SOLVER_NAME}}.getDiagonal(i),0.0) ) {
58 fineGridFace{{SOLVER_NAME}}.setDeltaU( i, 0.0 );
61 double du = repositories::{{SOLVER_INSTANCE}}.OmegaFace / fineGridFace{{SOLVER_NAME}}.getDiagonal(i) * fineGridFace{{SOLVER_NAME}}.getResidual(i);
62 repositories::{{SOLVER_INSTANCE}}.updateGlobalResidual( fineGridFace{{SOLVER_NAME}}.getResidual(i), marker.h() );
63 repositories::{{SOLVER_INSTANCE}}.updateGlobalSolutionUpdates( du, marker.h() );
65 assertion( not std::isnan(du) );
66 fineGridFace{{SOLVER_NAME}}.setDeltaU( i, du );
68 fineGridFace{{SOLVER_NAME}}.setResidual( i, 0.0 );
69 fineGridFace{{SOLVER_NAME}}.setDiagonal( i, 0.0 );
72 logTraceOutWith1Argument( "touchFaceFirstTime", fineGridFace{{SOLVER_NAME}}.getDeltaU() );
75 for (int i=0; i<repositories::{{SOLVER_INSTANCE}}.FaceUnknowns; i++) {
76 fineGridFace{{SOLVER_NAME}}.setDeltaU( i, 0.0 );
77 fineGridFace{{SOLVER_NAME}}.setResidual( i, 0.0 );
78 fineGridFace{{SOLVER_NAME}}.setDiagonal( i, 0.0 );
83 templateTouchCellFirstTime =
"""
85 fineGridCell{{SOLVER_NAME}}.getType() == celldata::{{SOLVER_NAME}}::Type::Interior
87 repositories::{{SOLVER_INSTANCE}}.updateCell()
89 logTraceInWith2Arguments("touchCellFirstTime", marker.toString(), fineGridCell{{SOLVER_NAME}}.toString());
91 // ==============================
92 // project updates into the cells
93 // ==============================
94 // @todo Very similar to Alex's matrix calibration discussion on Slack,
95 // there is some scaling missing here.
96 for (int d=0; d<Dimensions; d++) {
97 int unknownInPreimage = 0;
98 dfore(node,repositories::{{SOLVER_INSTANCE}}.PolyDegree+1,d,0) {
99 tarch::la::Vector< Dimensions, int > nodeOnLeftSideOfImage = node;
100 tarch::la::Vector< Dimensions, int > nodeOnRightSideOfImage = node;
101 nodeOnLeftSideOfImage(d) = 0;
102 nodeOnRightSideOfImage(d) = repositories::{{SOLVER_INSTANCE}}.PolyDegree;
104 for (int unknown=0; unknown<repositories::{{SOLVER_INSTANCE}}.UnknownsPerCellNode; unknown++) {
105 int unknownInLeftImage = peano4::utils::dLinearised( nodeOnLeftSideOfImage, repositories::{{SOLVER_INSTANCE}}.PolyDegree+1) * repositories::{{SOLVER_INSTANCE}}.UnknownsPerCellNode + unknown;
106 int unknownInRightImage = peano4::utils::dLinearised( nodeOnRightSideOfImage, repositories::{{SOLVER_INSTANCE}}.PolyDegree+1) * repositories::{{SOLVER_INSTANCE}}.UnknownsPerCellNode + unknown;
109 update = fineGridFaces{{SOLVER_NAME}}( d ).getDeltaU(unknownInPreimage);
110 assertion( update==update );
111 assertion( not std::isnan(update) );
112 fineGridCell{{SOLVER_NAME}}.setSolution(
114 fineGridCell{{SOLVER_NAME}}.getSolution(unknownInLeftImage) +
117 update = fineGridFaces{{SOLVER_NAME}}( d+Dimensions ).getDeltaU(unknownInPreimage);
118 assertion( not std::isnan(update) );
119 fineGridCell{{SOLVER_NAME}}.setSolution(
121 fineGridCell{{SOLVER_NAME}}.getSolution(unknownInRightImage) +
130 logTraceOutWith2Arguments("touchCellFirstTime", marker.toString(), fineGridCell{{SOLVER_NAME}}.toString());
136 super( UpdateFacets, self ).
__init__()
138 self.
d[
"SOLVER_INSTANCE"] = solver.instance_name()
139 self.
d[
"SOLVER_NAME"] = solver.typename()
143 if operation_name==peano4.solversteps.ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME:
146 if operation_name==peano4.solversteps.ActionSet.OPERATION_TOUCH_FACE_FIRST_TIME:
154 Configure name of generated C++ action set
156 This action set will end up in the directory observers with a name that
157 reflects how the observer (initialisation) is mapped onto this action
158 set. The name pattern is ObserverName2ActionSetIdentifier where this
159 routine co-determines the ActionSetIdentifier. We make is reflect the
163 return __name__.replace(
".py",
"").replace(
".",
"_")
168 The action set that Peano will generate that corresponds to this class
169 should not be modified by users and can safely be overwritten every time
170 we run the Python toolkit.
178 We need the solver repository in this action set, as we directly access
179 the solver object. We also need access to Peano's d-dimensional loops.
183#include "../repositories/SolverRepository.h"
184#include "peano4/utils/Loop.h"
Action set implementing the facet update of the continuous Galerkin solver.
get_body_of_operation(self, operation_name)
Return actual C++ code snippets to be inserted into C++ code.
str templateTouchFaceFirstTime
get_includes(self)
We need the solver repository in this action set, as we directly access the solver object.
str templateTouchCellFirstTime
get_action_set_name(self)
Configure name of generated C++ action set.
user_should_modify_template(self)
The action set that Peano will generate that corresponds to this class should not be modified by user...
Action set (reactions to events)