10from .Solver
import Solver
11from multigrid.petsc.api.actionsets.EnumerateDoFs
import EnumerateDoFs
12from multigrid.petsc.api.actionsets.InitCellDoFs
import InitCellDoFs
13from multigrid.petsc.api.actionsets.ProjectPETScSolutionBackOntoMesh
import (
14 ProjectPETScSolutionOnCellsBackOntoMesh,
16from multigrid.petsc.api.actionsets.PlotDGDataInPeanoBlockFormat
import (
17 PlotDGDataInPeanoBlockFormat,
19from multigrid.petsc.api.actionsets.PlotExactSolution
import PlotExactSolution
20from multigrid.petsc.api.actionsets.ImposeDirichletBoundaryConditionsWithInteriorPenaltyMethod
import (
21 ImposeDirichletBoundaryConditionsWithInteriorPenaltyMethod,
24from abc
import abstractmethod
32 Trigger assembly of PETSc matrix and also assemble rhs vector
36 TemplateTouchCellFirstTime =
"""
37 if (fineGridCell{{SOLVER_NAME}}PETScData.getType() == celldata::{{SOLVER_NAME}}PETScData::Type::Interior) {
38 std::pair<int,int> localCellIndex = std::make_pair(_spacetreeId, fineGridCell{{SOLVER_NAME}}PETScData.getUnknownBaseNumber());
39 int globalCellIndex = repositories::{{SOLVER_INSTANCE}}.getLocalToGlobalMap().getGlobalIndex(localCellIndex, ::petsc::LocalToGlobalMap::Type::Cell);
41 // ================================
42 // Left-hand side A_cc contribution
43 // ================================
44 auto lhsCellMatrix = repositories::{{SOLVER_INSTANCE}}.getLhsMatrix(marker.x(),marker.h());
46 logTraceInWith3Arguments( "touchCellFirstTime()", globalCellIndex, lhsCellMatrix.toString(), marker.toString() );
48 for (int row=0; row<repositories::{{SOLVER_INSTANCE}}.DoFsPerCell; row++)
49 for (int col=0; col<repositories::{{SOLVER_INSTANCE}}.DoFsPerCell; col++) {
50 repositories::{{SOLVER_INSTANCE}}.getLinearEquationSystem().insert(
53 lhsCellMatrix(row,col)
56 logTraceOut( "touchCellFirstTime()" );
58 // ================================
59 // Right-hand side vector contribution (multiply rhs (mass) matrix with rhs initial values
60 // ================================
61 auto rhsCellMatrix = repositories::{{SOLVER_INSTANCE}}.getRhsMatrix(marker.x(),marker.h());
63 for (int row=0; row<repositories::{{SOLVER_INSTANCE}}.DoFsPerCell; row++) {
65 for (int col=0; col<repositories::{{SOLVER_INSTANCE}}.DoFsPerCell; col++) {
66 rhs += rhsCellMatrix(row,col) * fineGridCell{{SOLVER_NAME}}.getRhs(col);
68 repositories::{{SOLVER_INSTANCE}}.getLinearEquationSystem().insert(
69 globalCellIndex+row, rhs
73 auto projectionCellToFaceMatrix = repositories::{{SOLVER_INSTANCE}}.getProjectionOfCellDataOntoFace(marker.x(),marker.h());
74 auto projectionFaceToCellMatrix = repositories::{{SOLVER_INSTANCE}}.getProjectionOfRiemannSolutionOntoCell(marker.x(),marker.h());
75 int dofsPerFace = repositories::{{SOLVER_INSTANCE}}.NodesPerFace*repositories::{{SOLVER_INSTANCE}}.FaceUnknowns;
77 for (int d=0; d<Dimensions; d++) {
78 // =================================
79 // Project to left face along axis d
80 // =================================
82 fineGridFaces{{SOLVER_NAME}}PETScData(d).getType()==facedata::{{SOLVER_NAME}}PETScData::Type::Interior
84 fineGridFaces{{SOLVER_NAME}}PETScData(d).getType()==facedata::{{SOLVER_NAME}}PETScData::Type::Boundary
86 std::pair<int,int> localFirstDoFIndexOfLeftFace = std::make_pair(_spacetreeId, fineGridFaces{{SOLVER_NAME}}PETScData(d).getUnknownBaseNumber());
87 int globalFirstDoFIndexOfLeftFace = repositories::{{SOLVER_INSTANCE}}.getLocalToGlobalMap().getGlobalIndex(localFirstDoFIndexOfLeftFace, ::petsc::LocalToGlobalMap::Type::Face);
89 assertion1(globalFirstDoFIndexOfLeftFace>=0, marker.toString());
90 logTraceInWith5Arguments( "touchCellFirstTime::LeftProjection", globalFirstDoFIndexOfLeftFace, globalCellIndex , projectionCellToFaceMatrix, projectionFaceToCellMatrix, marker.toString() );
92 for (int row=0; row<dofsPerFace; row++ ) {
93 for (int col=0; col<repositories::{{SOLVER_INSTANCE}}.DoFsPerCell; col++) {
94 logTraceIn("CellToFace");
95 repositories::{{SOLVER_INSTANCE}}.getLinearEquationSystem().insert(
96 globalFirstDoFIndexOfLeftFace + row + dofsPerFace,
98 projectionCellToFaceMatrix(d * dofsPerFace + row,col)
100 logTraceOut("CellToFace");
102 logTraceInWith1Argument("FaceToCellInsertion", projectionFaceToCellMatrix(col, d * dofsPerFace + row));
103 repositories::{{SOLVER_INSTANCE}}.getLinearEquationSystem().insert(
105 globalFirstDoFIndexOfLeftFace + row + 2 * dofsPerFace,
106 projectionFaceToCellMatrix(col, d * dofsPerFace + row)
108 logTraceOut("FaceToCell");
111 logTraceOut( "touchCellFirstTime::LeftProjection" );
115 fineGridFaces{{SOLVER_NAME}}PETScData(d+Dimensions).getType()==facedata::{{SOLVER_NAME}}PETScData::Type::Interior
117 fineGridFaces{{SOLVER_NAME}}PETScData(d+Dimensions).getType()==facedata::{{SOLVER_NAME}}PETScData::Type::Boundary
119 std::pair<int,int> localFirstDoFIndexOfRightFace = std::make_pair(_spacetreeId, fineGridFaces{{SOLVER_NAME}}PETScData(d+Dimensions).getUnknownBaseNumber());
120 int globalFirstDoFIndexOfRightFace = repositories::{{SOLVER_INSTANCE}}.getLocalToGlobalMap().getGlobalIndex(localFirstDoFIndexOfRightFace, ::petsc::LocalToGlobalMap::Type::Face);
122 assertion1(globalFirstDoFIndexOfRightFace>=0, marker.toString());
124 logTraceInWith2Arguments( "touchCellFirstTime::RightProjection", globalFirstDoFIndexOfRightFace, marker.toString() );
126 for (int row=0; row<dofsPerFace; row++ ) {
127 for (int col=0; col<repositories::{{SOLVER_INSTANCE}}.DoFsPerCell; col++) {
128 repositories::{{SOLVER_INSTANCE}}.getLinearEquationSystem().insert(
129 globalFirstDoFIndexOfRightFace + row,
131 projectionCellToFaceMatrix(d * dofsPerFace + row + Dimensions*dofsPerFace,col)
133 repositories::{{SOLVER_INSTANCE}}.getLinearEquationSystem().insert(
135 globalFirstDoFIndexOfRightFace + row + 2 * dofsPerFace,
136 projectionFaceToCellMatrix(col, d * dofsPerFace + row + Dimensions*dofsPerFace)
140 } // end of if interior face
142 logTraceOut( "touchCellFirstTime::RightProjection" );
148 TemplateTouchFaceFirstTime =
"""
149 auto RiemannSolverMatrix = repositories::{{SOLVER_INSTANCE}}.getRiemannSolver(marker.x(),marker.h());
150 int dofsPerFace = repositories::{{SOLVER_INSTANCE}}.NodesPerFace*repositories::{{SOLVER_INSTANCE}}.FaceUnknowns;
151 if ( fineGridFace{{SOLVER_NAME}}PETScData.getType() == facedata::{{SOLVER_NAME}}PETScData::Type::Interior ) {
152 std::pair<int,int> localFirstDoFIndex = std::make_pair(_spacetreeId, fineGridFace{{SOLVER_NAME}}PETScData.getUnknownBaseNumber());
153 int globalFirstDoFIndex = repositories::{{SOLVER_INSTANCE}}.getLocalToGlobalMap().getGlobalIndex(localFirstDoFIndex, ::petsc::LocalToGlobalMap::Type::Face);
155 assertion( globalFirstDoFIndex>=0 );
157 logTraceInWith2Arguments("touchFaceFirstTime", globalFirstDoFIndex, RiemannSolverMatrix);
158 for (int row=0; row<dofsPerFace; row++)
160 // we have col<2*dofsPerFace here since we have left and right projections here.
161 // ie, we have a certain number of "true" dofsPerFace and then twice as many
162 // helper dofs to hold the projections.
163 // In this loop, we are setting the values of the true face Dofs, using the
164 // left and right projections. This is why we get the global index of the
165 // face and offset by 2*dofsPerFace: this will index the true dofs,
166 // which are enumerated AFTER the projections.
167 for (int col=0; col<2*dofsPerFace; col++) {
168 repositories::{{SOLVER_INSTANCE}}.getLinearEquationSystem().insert(
169 globalFirstDoFIndex + 2*dofsPerFace + row,
170 globalFirstDoFIndex + col,
171 RiemannSolverMatrix(row, col)
175 // 3*dofsPerFace so that each of the -, + and solution variables receive an identity here.
176 for (int i=0; i<3*dofsPerFace; i++)
178 repositories::{{SOLVER_INSTANCE}}.getLinearEquationSystem().insert(
179 globalFirstDoFIndex + i,
180 globalFirstDoFIndex + i,
185 logTraceOut("touchFaceFirstTime");
188 else if ( fineGridFace{{SOLVER_NAME}}PETScData.getType() == facedata::{{SOLVER_NAME}}PETScData::Type::Boundary ){
189 // add some more identities!
203 super(AssemblePetscMatrix, self).
__init__()
205 self.
d[
"SOLVER_INSTANCE"] = solver.instance_name()
206 self.
d[
"SOLVER_NAME"] = solver.typename()
211 Provide C++ code snippet for peano4.api.solversteps.ActionSet.OPERATION_TOUCH_VERTEX_FIRST_TIME
212 Provide C++ code snippet for peano4.api.solversteps.ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME
214 Only touchVertexFirstTime is an event where this action set actually
215 does something: It inserts the template TemplateTouchVertexFirstTime and
216 replaces it with entries from the dictionary. The latter is befilled
219 We actually do something during touchVertexFirstTime and touchCellFirstTime. We insert the
220 appropriate template into each.
226 == peano4.api.solversteps.ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME
232 == peano4.api.solversteps.ActionSet.OPERATION_TOUCH_FACE_FIRST_TIME
241 Configure name of generated C++ action set
243 This action set will end up in the directory observers with a name that
244 reflects how the observer (initialisation) is mapped onto this action
245 set. The name pattern is ObserverName2ActionSetIdentifier where this
246 routine co-determines the ActionSetIdentifier. We make is reflect the
250 return __name__.replace(
".py",
"").replace(
".",
"_")
255 The action set that Peano will generate that corresponds to this class
256 should not be modified by users and can safely be overwritten every time
257 we run the Python toolkit.
265 Consult petsc.Project for details
268#include "repositories/SolverRepository.h"
269#include "tarch/la/Matrix.h"
281 Define body of constructor
283 @see get_attributes()
287 _spacetreeId = treeNumber;
294 Discontinuous Galerkin Solver with PETSc
296 ## The weak formulation
298 To translate a PDE into an equation system, we express the solution
300 @f$ u = \sum _i u_i \phi _i @f$
302 as sum over shape functions @f$ \phi _i @f$.
303 The shape functions in this class are locally continuous, but their linear
304 combination is not. We test this setup against test functions @f$ v @f$.
305 Each test function is actually any of the shape functions @f$ \phi _i @f$.
306 Drawing both shapes and test functions from the same function space means that
307 we follow a ***Ritz-Galerkin*** approach.
310 Let @f$ \mathcal{L}(u) @f$ be the differential operator on the left-hand side
311 of the PDE, i.e. let's assume that we solve
317 A weak formulation means that we multiple both sides with a test function and
318 then integrate over the whole thing. As we take all these tests from the same
319 function space as the shape functions, we know that they all have local
320 support.Consequently, our test integral "shrinks" down to the support of the
324 \int _\Omega \mathcal{L}(u) \cdot v dx = \int_{\text{cell}_v} \mathcal{L}(u) \cdot v dx
327 as the product disappears everywhere outside of the cell that hosts the test
328 function of interest.
331 Once again, we can integrate by parts to get rid of the highest derivative in
332 our partial differential operator @f$ \mathcal{L}(u) @f$, but this time, we will
333 get an expression of the form
337 \int _\Omega \mathcal{L}(u) \cdot v dx
339 - \int _\Omega \left( \tilde{\mathcal{L}}(u), \nabla v \right) dx
340 + \int _{\partial \text{cell}_v} (n,\tilde{\mathcal{M}}(u)) v dS(x)
343 - \int _{\text{cell}_v} \left( \tilde{\mathcal{L}}(u), \nabla v \right) dx
344 + \int _{\partial \text{cell}_v} (n,\tilde{\mathcal{M}}(\hat u )) v dS(x)
346 & = & \int _{\text{cell}_v} f \cdot v dx.
349 We reduced the order of the deriative within @f$ \mathcal{L}(u) @f$ and got a
350 new operator @f$ \tilde{\mathcal{L}} @f$.
351 If @f$ \mathcal{L}(u) @f$ is dominated by a second derivative, @f$ \tilde{\mathcal{L}} @f$
352 hosts only first-order derivatives.
353 But this is a Pyrrhic victory:
354 We now get an additional PDE term over the cell faces.
359 1. the jump terms along the faces do not disappear, i.e. they do not cancel out
360 from left and right as they do in a Continuous Galerkin formulation.
361 2. Even worse, they refer to a value @f$ u @f$ which technically does not
362 exist, as there is no (unique) solution along the face. We only have a
363 left @f$ u^- @f$ and a right @f$ u^+ @f$ solution. Therefore, I explicitly
364 write @f$ \hat u @f$ in the equation above. It denotes that we haven't yet
365 decided what the function looks like along the face.
366 3. We now have cell integrals to evaluate, and there are additional face
367 integrals. The latter ones couple neighbouring cells.
369 We end up with a linear equation system
373 where x has @f$ |\mathbb{C}| \cdot K \cdot (p+1)^d @f$ entries. @f$ \mathbb{C} @f$
374 is set of cells in the mesh.
377 ## An operator language and temporary variables
379 Before we dive into examples or discuss how to map this formalism onto code, we
380 introduce an operator language. That is, we break down the overall computation
381 into small tasks. These tasks will be found 1:1 in the code later on. Furthermore,
382 we gain some freedom by breaking things down into tiny bits and pieces: We can
383 alter individual ones or puzzle them together in various ways.
385 We introduce a few operators (functions) to break down the overall computational
386 scheme into a sequence/set of computations:
388 - The operator @f$ A_{cc} @f$ takes the dofs within a cell and computes the
389 term @f$ - \int _{\text{cell}_v} \left( \tilde{\mathcal{L}}(u), \nabla v \right) dx @f$.
390 It takes the @f$ K (p+1)^d @f$ values per cell and yields @f$ K (p+1)^d @f$
391 equations/updates from the cell. In classes like petsc.solvers.DiscontinuousGalerkinDiscretisation
392 this matrix is called cell_cell_lhs_matrix.
393 - Let's introduce temporary variables on the face. Those are the
394 @f$ u^+ @f$ and @f$ u^- @f$ values, i.e. we store @f$ 2K (p+1)^{d-1} @f$
395 degrees of freedom on the face. Those are not really degrees of freedom.
396 They will be mere projection, i.e. simply encode what the solution along
398 - The operator @f$ A_{cf} @f$ takes the solution from a cell and projects it
399 onto a face. Let @f$ u^+ @f$ and @f$ u^- @f$ denote the solution left or
400 right of a face (from the face's point of view). For each of the @f$ 2d @f$
401 faces of a cell, the operator @f$ P_{cf} @f$ yields either the
402 @f$ u^+ @f$ or @f$ u^- @f$.
403 - The operator @f$ A_{ff} @f$ operates on a face. It takes
404 @f$ u^+ @f$ and @f$ u^- @f$ and yields something
405 that "reconstructs" the solution and applies the flux operator on it.
406 This is the Riemann solver and hence linear algebraises the
407 @f$ \tilde{\mathcal{M}}(\hat u ) @f$ from above.
408 - The operator @f$ A_{fc} @f$ takes the @f$ \hat u @f$ on the face and yields
409 the updates for the cell. It evaluates @f$ \int _{\partial \text{cell}_v} (n,\tilde{\mathcal{M}}(\hat u )) v dS(x) @f$.
412 <div style="background-color: #cfc ; padding: 10px; border: 1px solid green;">
413 Within Peano, it is important to distinguish data on cell and faces carefully
414 from each other. Furthermore
415 (i) we can read data associated with faces within cells;
416 (ii) we can never read data from neighbouring cells within a cell;
417 (iii) we can never access adjacent cell data from a face.
422 The overall scheme in operator notation thus reads
425 A_{cc} + A_{fc} \circ A_{ff} \circ A_{cf}
429 i.e. we evaluate the cell contributions and add the face contributions
430 which in turn results from a concatenation of three operators:
431 Project solution onto face, solve a Riemann problem there, and then
432 take the result and project it back onto the cell. The projection onto
433 the face is a purely geoemtric thing: Once we know the polynomials
434 chosen within the cell, we can evaluate what the solution looks like
435 depending on the weights (unknowns within the degree of freedom).
436 With that knowledge, we can determine what the solution on the face
437 looks like. We use the same polynomial space there (restricted to the
438 submanifold) and therefore can express the face representation through
439 polynomial weights (left and right of the face), too. For each pair of
440 the polynomial weights, we can solve the Riemann problem and store the
441 outcome in further weights. That is, we represent the outcome of the
442 Riemann problem again in the polynomial space on the faces. Finally,
443 we take this representation, test it against the test functions,
444 integrate over the face and write the contributions back into the cell.
449 Effectively, our approach blows up the equation system to solve into
454 A_{cc} & A_{fc} & 0 & 0 \\
455 0 & id & -A_{ff}|_+ & -A_{ff}|_- \\
456 -id & 0 & A_{cf}|_+ & 0 \\
457 -id & 0 & 0 & A_{cf}|_-
460 x_{c} \\ x_f \\ x^+ \\ x^-
469 @todo We need a nice illustration here of all the function spaces
471 where we have to specify the involved matrices further.
472 The @f$ x_c @f$ are the real degrees of freedom, i.e. the weights within
473 the cells which effectively span the solution.
474 The @f$ x_\pm @f$ encode the projection of these polynomials onto the faces.
475 These are not real degrees of freedom, as they always result directly from
477 The @f$ x_f @f$ encode the reconstructed solution on the faces and hold the
478 average of the @f$ x_\pm @f$ values.
479 This setup means our total matrix is no longer square.
480 @f$ A_{cc} @f$ is square, with @f$ |\mathbb{C}| \cdot (p+1)^d @f$ rows,
481 where @f$ |\mathbb{C}| @f$ is the number of cells in the mesh.
482 @f$ A_{fc} @f$ has the same number of rows, but @f$ |\mathbb{F}| \cdot (p+1)^{d-1} @f$
483 columns, since this part has to "hit" @f$ x_f @f$.
484 @f$ A_{ff} @f$ has @f$ |\mathbb{F}| \cdot (p+1)^{d-1} @f$ rows, and twice as many
485 columns (note that @f$ | x_\pm| \ = \ 2 |x_f| @f$ ).
486 Finally, @f$ A_{cf} @f$ has @f$ |\mathbb{C}| \cdot (p+1)^d @f$ rows and
487 @f$ 2|\mathbb{F}| \cdot (p+1)^{d-1} @f$ columns, since this part "hits"
490 Our global matrix is no longer square. We have
491 @f$ 2 |\mathbb{C}| \cdot (p+1)^d + |\mathbb{F}| \cdot (p+1)^{d-1} @f$ rows
493 @f$ |\mathbb{C}| \cdot (p+1)^d + 3|\mathbb{F}| \cdot (p+1)^{d-1} @f$ columns.
498 <div style="background-color: #cfc ; padding: 10px; border: 1px solid green;">
499 The write-down as one big matrix as above works if and only if the
500 chosen Riemann solver yield a linear combination of the @f$ u^-/u^+ @f$
501 or @f$ x^-/x^+ @f$ values respectively. In many sophisticated solvers,
502 it will not be linear. In this case, the system becomes a non-linear
508 The data storage within a cell is not prescribed by Peano, i.e. you can,
509 in principle decide if you want to reorder the @ref page_multigrid_terminology "nodes within the cell"
510 or you can decide to order the degrees of freedom overall as SoA as opposed
511 to AoS. At the end of the day, Peano maintains an array of doubles per
512 cell and does not really care about the semantics of those. However, we
513 strongly recommend that you stick to the default configuration where
516 @image html degree_of_freedom_semantics.png
518 - Nodes are enumerated following our @ref page_multigrid_terminology "dimension-generic conventions".
519 - Data are stored as an Array of Structs (AoS), i.e. first all the unknowns
520 of the first node, then all of the second, and so forth.
522 If you change any ordering, you have to take this into account for all
523 associated operators (such as projections onto the faces), but you also
524 will have to amend the plotters which are tied to these conventions.
528 - stored as AoS by default;
529 - per face, we first store the left projection @f$ x^- @f$, then the right projection @f$ x^+ @f$
530 and then the outcome of the flux or associated reconstruction. That is, all the @f$ x^- @f$
531 are held en bloc first before we hold @f$ x^+ @f$.
532 - Per @f$ x^\pm @f$, the storage of the nodes and unknowns
533 follows again the @ref page_multigrid_terminology "dimension-generic conventions".
535 It is important to recognise that we store three types of quantities
536 per unknown: Its left projection, its right projection, and its
537 outcome which can be either the flux or a reconstructed
538 income. The semantics of the outcome depend upon your operators, i.e.
539 they are not baked into the formalism. Furthermore, there is no
540 assumption about the spacing along the faces. Naturally, you might
541 assume that a Gauss-Lobatto layout within the cell implies a
542 Gauss-Lobatto distribution on the faces. However, no such thing
543 is encoded within the code, as we solely work with operators. They
544 have to encode the correct spacing.
546 Another assumptions is baked into the realisation as a default:
547 The polynomial degree on the facet result @f$ x_f @f$ equals the
548 polynomial degree within the cell.
550 @todo Different polynomial degrees are simple to realise. This is
551 something to do in the future. Note that +/- are to be
552 taken from the same space as the cell, as they are projections,
553 but maybe we want to alter this, and even provide completely
554 different degrees for the result of the Riemann solve.
560 Multiple examples are shipped with Peano which demonstrate how to use the
561 plain Discontiuous Galerking solver:
563 - benchmarks/multigrid/petsc/poisson/dg.py Hosts a simple solver for the
564 Poisson equation. All the rationale are discussed in @ref benchmarks_documentation_multigrid_petsc_poisson.
579 cell_cell_lhs_matrix,
580 cell_cell_rhs_matrix,
581 cell_cell_lhs_matrix_scaling,
582 cell_cell_rhs_matrix_scaling,
585 cell_to_face_matrix_scaling,
586 face_to_cell_matrix_scaling,
587 face_face_Riemann_problem_matrix,
588 quadrature_points_in_unit_interval,
589 gaussian_integration_points,
590 gaussian_integration_weights,
594 Constructor of DG class
597 ## Cell to face projection
599 Consult @ref page_multigrid_terminology "Peano's enumeration for multigrid" page
600 for info on the ordering. For 2d with a layout as below
602 @image documentation/Doxygen/Multigrid/face-ordering.png
604 the matrix is applied to
609 x_0^+ \\ x_1^+ \\ x_2^- \\ x_3^-
619 @param cell_cell_lhs_matrix: [Float] or []
620 Pass in [] if you prefer to assemble the matrix per cell yourself. This
621 is the @f$ \tilde{\mathcal{L}} @f$ part above. The ordering of the
622 degrees of freedom follows the discussion above. The matrix is from
623 @f$ K(p+1) \times K(p+1) @f$.
625 @param cell_cell_rhs_matrix: [Float] or []
626 Pass in [] if you prefer to assemble the matrix per cell yourself. This
627 matrix arises from @f$ \int f \cdot v \ dx @f$ and is applied to the nodal
628 values of the PDE within the quadrature nodes of a cell. The matrix is
629 from @f$ K(p+1) \times K(p+1) @f$.
631 @param cell_cell_lhs_matrix_scaling: Positive integer
632 The lhs matrix is scaled with @f$ h^x @f$ where the x is defined by this
633 parameter. If you don't specify an lhs matrix, i.e. you prefer to inject
634 this matrix manually, you can leave this parameter None, as it is not
637 @param cell_cell_rhs_matrix_scaling: Positive integer
638 The rhs matrix is scaled with @f$ h^x @f$ where the x is defined by this
639 parameter. If you don't specify a rhs matrix, i.e. you prefer to inject
640 this matrix manually, you can leave this parameter None, as it is not
643 @param cell_to_face_matrix: [Float]
644 If you study the global equation system above, you recognise that
645 this matrix is applied to the left or right solutions of a cell's
648 @param face_face_Riemann_problem_matrix: [Float] or []
649 Pass in [] if you prefer to assemble the matrix per cell yourself. This
650 matrix represents the actual Riemann solver. It accepts the left projection
651 @f$ u^- @f$ and @f$ u^+ @f$ and yields a "reconstructed" value at this
652 point passed into the differential operator. Therefore, this is a band
657 super(DiscontinuousGalerkinDiscretisation, self).
__init__(name, min_h, max_h)
679 assert len(quadrature_points_in_unit_interval) == len(
680 gaussian_integration_points,
681 "Something has gone wrong. These should all be same length for fixed polynomial degree",
683 assert len(quadrature_points_in_unit_interval) == len(
684 gaussian_integration_weights,
685 "Something has gone wrong. These should all be same length for fixed polynomial degree",
718 Initialise index model
720 There is an index data model, where all the vertices, faces and cells
721 are properly enumerated. This one is taken care of by the superclass.
722 The thing we have to add our our PDE-specific unknowns.
738 Tell the project's observer how to plot the data
740 Nothing fancy here. We add plotters from Peano's toolbox to visualise
741 solution and right-hand side.
744 observer.add_action_set(PlotDGDataInPeanoBlockFormat(self))
754 Solution initialisation
756 Close to trivial: Just add the action set petsc.actionsets.InitVertexDoFs
760 observer.add_action_set(
763 boundary_vertices_hold_data=
False,
764 boundary_faces_hold_data=
True,
768 observer.add_action_set(InitCellDoFs(self))
773 observer.add_action_set(
774 ImposeDirichletBoundaryConditionsWithInteriorPenaltyMethod(self)
782 observer.add_action_set(ProjectPETScSolutionOnCellsBackOntoMesh(self))
783 observer.add_action_set(PlotExactSolution(self))
789 The solver creates two classes: An abstract base class and its
790 implementations. The abstract base class will be overwritten if
791 there is one in the directory. I pipe all the Python constants
792 into this base class, so they are available in the C++ code.
794 The implementation file will not be overwritten, as I assume that
795 the users will write their own domain-specific stuff in there. If
796 it does not exist yet, I'll create an empty stub which can be
797 befilled with something meaningful.
799 Besides the creation of these two files, I also add the files to the
800 project artifacts and the makefile, so they are captured by the build
804 templatefile_prefix = os.path.dirname(os.path.realpath(__file__)) +
"/"
805 templatefile_prefix += self.__class__.__name__
811 "SOLVER_INCLUDES":
"",
832 generated_abstract_header_file = (
834 templatefile_prefix +
".Abstract.template.h",
835 templatefile_prefix +
".Abstract.template.cpp",
844 generated_solver_files = (
846 templatefile_prefix +
".template.h",
847 templatefile_prefix +
".template.cpp",
857 output.add(generated_abstract_header_file)
858 output.add(generated_solver_files)
859 output.makefile.add_h_file(
860 subdirectory +
"Abstract" + self.
_name +
".h", generated=
True
862 output.makefile.add_h_file(subdirectory + self.
_name +
".h", generated=
True)
863 output.makefile.add_cpp_file(
864 subdirectory +
"Abstract" + self.
_name +
".cpp", generated=
True
866 output.makefile.add_cpp_file(subdirectory + self.
_name +
".cpp", generated=
True)
872 Nothing is associated with the vertex. There's nothing to be done here.
881 In the DG scheme, we have a projection from the left and we have a
882 projection from the right. These values are proper projections, i.e.
883 they do not carry any semantics. Then we have to solve the Riemann
884 problem, and need one more unknown to store the outcome of that one.
893 This is the actual unknowns per cell
Trigger assembly of PETSc matrix and also assemble rhs vector.
get_constructor_body(self)
Define body of constructor.
get_action_set_name(self)
Configure name of generated C++ action set.
get_attributes(self)
Return attributes as copied and pasted into the generated class.
str TemplateTouchCellFirstTime
str TemplateTouchFaceFirstTime
get_includes(self)
Consult petsc.Project for details.
__init__(self, solver)
Yet to be written.
get_body_of_operation(self, operation_name)
Provide C++ code snippet for peano4.api.solversteps.ActionSet.OPERATION_TOUCH_VERTEX_FIRST_TIME Provi...
user_should_modify_template(self)
The action set that Peano will generate that corresponds to this class should not be modified by user...
Discontinuous Galerkin Solver with PETSc.
face_to_cell_matrix_scaling
number_of_matrix_entries_per_vertex(self)
Nothing is associated with the vertex.
add_to_init_petsc(self, observer)
Add whatever action set you want to use here.
add_implementation_files_to_project(self, namespace, output, subdirectory="")
The solver creates two classes: An abstract base class and its implementations.
quadrature_points_in_unit_interval
add_to_create_grid(self, observer)
Add whatever action set you want to use to observer.
__init__(self, name, polynomial_degree, dimensions, cell_unknowns, face_unknowns, min_h, max_h, cell_cell_lhs_matrix, cell_cell_rhs_matrix, cell_cell_lhs_matrix_scaling, cell_cell_rhs_matrix_scaling, cell_to_face_matrix, face_to_cell_matrix, cell_to_face_matrix_scaling, face_to_cell_matrix_scaling, face_face_Riemann_problem_matrix, quadrature_points_in_unit_interval, gaussian_integration_points, gaussian_integration_weights)
Constructor of DG class.
cell_cell_rhs_matrix_scaling
cell_cell_lhs_matrix_scaling
cell_to_face_matrix_scaling
number_of_matrix_entries_per_cell
gaussian_integration_points
add_to_plot(self, observer)
Tell the project's observer how to plot the data.
gaussian_integration_weights
add_to_enumerate_and_init_solution(self, observer)
Solution initialisation.
add_use_statements(self, observer)
Register the index numbers to be used in each and every mesh traversal.
add_to_assemble(self, observer)
Add whatever action set you want to use to observer.
add_to_Peano4_datamodel(self, datamodel, verbose)
Initialise index model.
number_of_matrix_entries_per_face(self)
In the DG scheme, we have a projection from the left and we have a projection from the right.
add_to_map_solution_onto_mesh(self, observer)
Add whatever action set you want to use to observer.
number_of_matrix_entries_per_cell(self)
This is the actual unknowns per cell.
face_face_Riemann_problem_matrix
Abstract base class for all PETSc solvers.
number_of_matrix_entries_per_cell(self)
Specialisation of array using Peano's tarch.
Default superclass for any data model in Peano which is stored within the grid.
Action set (reactions to events)