7from .Solver
import Solver
8from .actionsets.CollocatedSolver.InitDofs
import InitDofsCollocated
9from .actionsets.CollocatedSolver.UpdateSolution
import UpdateSolution
10from .actionsets.CollocatedSolver.ResetAndUpdateResidual
import ResetAndUpdateResidual
11from .actionsets.PlotVertexDataInPeanoBlockFormat
import PlotVertexDataInPeanoBlockFormat
13from abc
import abstractmethod
20 Matrix-free Collocated Solver for d-linear shape functions.
22 Mathematical and algorithmic descriptions are to follow later. For now,
23 we describe how to use this solver and a little about how it works under
26 Each vertex stores a certain number of values, given by the parameter
27 unknowns_per_vertex. In essence, if this parameter is more than one,
28 we are solving multiple different equations simultaneously, or we
29 can equivalently think of our PDE being vector-valued.
31 The user needs to provide an assembly matrix, and a mass matrix. If
32 our vector-valued PDE has \f$ K \f$ components, then each of these
33 matrices should be square, with \f$ K * 2^D \f$ rows.
35 In particular, they should be structured as block diagonals. Let
36 \f$ A_i \f$ be square with \f$ 2^D \f$ rows. Then the mass/assembly
37 matrices should be structured as follows:
39 \f$ diag( A_1, A_2, \dots A_K ) \f$.
41 During the actual solver step, we run through each equation one
42 after another, fetching the appropriate mass and assembly matrices
43 for the equation in hand.
45 At present, it hasn't been decided how to plot the output of multiple
46 equations, since only 1 is supported.
48 # Data held on the vertices
50 ## Solution (formerly named Value)
51 This array holds the actual solution which we later plot. This is updated when we touch a vertex
56 This array holds the right-hand side of the equation. We assign this in
57 experiment-specific implementation files.
60 This array holds the sum of the diagonals of the local assembly matrix. This is
61 set to 0 at the start of every solver step
64 This is used to store \f$ Mb - Ax \f$, i.e. the RHS multiplied by the matrix, and subtract
65 the solution multiplied by the assembly matrix.
71 After the grid is created, we run around the mesh and assign types to the vertices and cells.
74 - "Coarse" if the vertex is due to be refined
75 - "Interior" if it's not on the boundary
76 - "Boundary" if it is on the boundary
79 - "Coarse" if it's due to be refined
80 - Otherwise marked as "Interior"
84 There is only one action set in this solver. We do something non-trivial during touchCellFirstTime,
85 touchVertexFirstTime and touchVertexLastTime.
87 ### touchVertexFirstTime
89 We check that the Vertex is not a coarse grid vertex, then we set the residuals and the diagonals to 0.
91 ### touchCellFirstTime
93 All four vertices are in scope here. We create three vectors, each of length \f$ 2^D \f$ to hold
94 one value per vertex. For each vertex in the cell (regardless of whether it is on the boundary), we :
95 - Update the residual to be \f$ Mb - Ax \f$
96 - Increment the diagonal
98 ### touchVertexLastTime
99 We update the solution value (on all vertices) to be equal to the solution at the previous sweep, and we add on
100 \f$ \omega \times r / d \f$
101 where \f$ r \f$ and \f$ d \f$ stand for the residual and diagonal respectively.
103 # Enforcement of boundary conditions
108 We currently overcount the residual on vertices that are shared across boundaries. This isn't an issue at present,
109 since we only check for the max, which is unaffected by this bug. But something to fix at later date.
119 local_assembly_matrix,
120 local_assembly_matrix_scaling,
124 smoother_relaxation = 0.6,
125 custom_init_actionset = None,
126 custom_plot_actionset = None,
127 custom_init_vertex = "",
128 custom_boundary_conditions = "",
129 enable_plotting = True,
130 plot_predicate = "true"
134 Collocated low-order (d-linear) Finite Elements
137 super( CollocatedDLinearDiscretisationWithPointJacobi, self ).
__init__( name,
142 matrix_dims = (2**dimensions) * unknowns_per_vertex
176 super( CollocatedDLinearDiscretisationWithPointJacobi, self ).
add_use_statements(observer)
181 Tell the project's observer how to plot the data
183 Nothing fancy here. We add plotters from Peano's toolbox to visualise
184 solution and right-hand side.
204 Solution initialisation. We can either use the
205 standard initialisation procedure or pass in
206 another one when we instantiate this solver
217 descend_invocation_order = observer.highest_descend_invocation_order() + self.
_basic_descend_order + 1
218 observer.add_action_set(
UpdateSolution( self, descend_invocation_order+0,
False) )
225 The solver creates two classes: An abstract base class and its
226 implementations. The abstract base class will be overwritten if
227 there is one in the directory. I pipe all the Python constants
228 into this base class, so they are available in the C++ code.
231 templatefile_prefix = os.path.dirname( os.path.realpath(__file__) ) +
"/templates/"
232 templatefile_prefix += self.__class__.__name__
238 "SOLVER_INCLUDES":
"",
256 templatefile_prefix +
".Abstract.template.h",
257 templatefile_prefix +
".Abstract.template.cpp",
265 templatefile_prefix +
".template.h",
266 templatefile_prefix +
".template.cpp",
274 output.add( generated_abstract_header_file )
275 output.add( generated_solver_files )
276 output.makefile.add_h_file( subdirectory +
"Abstract" + self.
_name +
".h", generated=
True )
277 output.makefile.add_h_file( subdirectory + self.
_name +
".h", generated=
True )
278 output.makefile.add_cpp_file( subdirectory +
"Abstract" + self.
_name +
".cpp", generated=
True )
279 output.makefile.add_cpp_file( subdirectory + self.
_name +
".cpp", generated=
True )
286 if( !marker.willBeRefined() ) {
288 // naive += with the diag
289 setDiag( getDiag() + neighbour.getDiag() );
291 // ditto for residual
292 setResidual( getResidual() + neighbour.getResidual() );
Specialisation of array using Peano's tarch.
Action set (reactions to events)
Matrix-free Collocated Solver for d-linear shape functions.
_abstract_solver_implementation_extras
add_to_init_solution(self, observer)
Solution initialisation.
_local_assembly_matrix_scaling
_unknowns_per_vertex_node
add_use_statements(self, observer)
This routine should still be called even if overwritten in child class.
add_implementation_files_to_project(self, namespace, output, subdirectory="", abstract_overwrite=True)
The solver creates two classes: An abstract base class and its implementations.
__init__(self, name, unknowns_per_vertex, dimensions, min_h, max_h, local_assembly_matrix, local_assembly_matrix_scaling, mass_matrix, mass_matrix_scaling, solver_tolerance, smoother_relaxation=0.6, custom_init_actionset=None, custom_plot_actionset=None, custom_init_vertex="", custom_boundary_conditions="", enable_plotting=True, plot_predicate="true" # enable custom plotting behaviour)
Collocated low-order (d-linear) Finite Elements.
_custom_boundary_conditions
add_to_plot(self, observer)
Tell the project's observer how to plot the data.
add_to_Peano4_datamodel(self, datamodel, verbose)
add_to_solve(self, observer)
_abstract_solver_header_extras
get_vertex_merge_method(self)
add_to_create_grid(self, observer)
Abstract base class for matrix free solvers.
_abstract_solver_header_extras
_abstract_solver_implementation_extras
In touchVertexFirstTime, we set the type of vertex we see (either Interior, Boundary or Coarse),...
Action set implementing the core of the collocated solver.
This action set goes first, so that if we've done at least one sweep, we can update the solution base...