deal.II version GIT relicensing-2291-g668cd86249 2024-12-24 11:30:00+00:00
|
#include <deal.II/algorithms/theta_timestepping.h>
Public Member Functions | |
ThetaTimestepping (OperatorBase &op_explicit, OperatorBase &op_implicit) | |
virtual void | operator() (AnyData &out, const AnyData &in) override |
virtual void | notify (const Event &) override |
void | set_output (OutputOperator< VectorType > &output) |
void | parse_parameters (ParameterHandler ¶m) |
double | current_time () const |
double | theta () const |
double | theta (double new_theta) |
const TimestepData & | explicit_data () const |
const TimestepData & | implicit_data () const |
TimestepControl & | timestep_control () |
void | clear_events () |
template<class Archive > | |
void | serialize (Archive &ar, const unsigned int version) |
EnableObserverPointer functionality | |
Classes derived from EnableObserverPointer provide a facility to subscribe to this object. This is mostly used by the ObserverPointer class. | |
void | subscribe (std::atomic< bool > *const validity, const std::string &identifier="") const |
void | unsubscribe (std::atomic< bool > *const validity, const std::string &identifier="") const |
unsigned int | n_subscriptions () const |
template<typename StreamType > | |
void | list_subscribers (StreamType &stream) const |
void | list_subscribers () const |
Static Public Member Functions | |
static void | declare_parameters (ParameterHandler ¶m) |
static ::ExceptionBase & | ExcInUse (int arg1, std::string arg2, std::string arg3) |
static ::ExceptionBase & | ExcNoSubscriber (std::string arg1, std::string arg2) |
Protected Attributes | |
Event | notifications |
Private Types | |
using | map_value_type = decltype(counter_map)::value_type |
using | map_iterator = decltype(counter_map)::iterator |
Private Member Functions | |
void | check_no_subscribers () const noexcept |
Private Attributes | |
TimestepControl | control |
double | vtheta |
bool | adaptive |
TimestepData | d_explicit |
TimestepData | d_implicit |
ObserverPointer< OperatorBase, ThetaTimestepping< VectorType > > | op_explicit |
ObserverPointer< OperatorBase, ThetaTimestepping< VectorType > > | op_implicit |
ObserverPointer< OutputOperator< VectorType >, ThetaTimestepping< VectorType > > | output |
std::atomic< unsigned int > | counter |
std::map< std::string, unsigned int > | counter_map |
std::vector< std::atomic< bool > * > | validity_pointers |
const std::type_info * | object_info |
Static Private Attributes | |
static std::mutex | mutex |
Application class performing the theta timestepping scheme.
The theta scheme is an abstraction of implicit and explicit Euler schemes, the Crank-Nicolson scheme and linear combinations of those. The choice of the actual scheme is controlled by the parameter theta as follows.
For fixed theta, the Crank-Nicolson scheme is the only second order scheme. Nevertheless, further stability may be achieved by choosing theta larger than ½, thereby introducing a first order error term. In order to avoid a loss of convergence order, the adaptive theta scheme can be used, where theta=½+c dt.
Assume that we want to solve the equation u' + F(u) = 0 with a step size k. A step of the theta scheme can be written as
\[ M u_{n+1} + \theta k F(u_{n+1}) = M u_n - (1-\theta)k F(u_n). \]
Here, M is the mass matrix. We see, that the right hand side amounts to an explicit Euler step with modified step size in weak form (up to inversion of M). The left hand side corresponds to an implicit Euler step with modified step size (right hand side given). Thus, the implementation of the theta scheme will use two Operator objects, one for the explicit, one for the implicit part. Each of these will use its own TimestepData to account for the modified step sizes (and different times if the problem is not autonomous). Note that once the explicit part has been computed, the left hand side actually constitutes a linear or nonlinear system which has to be solved.
ThetaTimestepping uses AnyData for communicating vectors and time step information. With outer or inner Operator objects. It does not use itself the input vectors provided, but forwards them to the explicit and implicit operators.
The explicit Operator op_explicit receives in its input in first place the vector "Previous iterate", which is the solution value after the previous timestep. It is followed by all vectors provided to ThetaTimestepping::operator() as input argument. op_explicit is supposed to write its result into the first position of its output argument, labeled "Result".
The implicit Operator op_implicit receives the result of op_explicit in its first input vector labeled "Previous time". It is followed by all vectors provided to ThetaTimestepping::operator() as input argument. The output of op_implicit is directly written into the output argument given to ThetaTimestepping.
Since the introduction of AnyData, ThetaTimestepping is able to communicate the current time step information through AnyData as well. Therefore, the AnyData objects handed as input to op_explicit and op_implicit contain two entries of type const double*
named "Time" and "Timestep". Note that "Time" refers to the time at the beginning of the current step for op_explicit and at the end for op_implicit, respectively.
The use ThetaTimestepping is more complicated than for instance Newton, since the inner operators will usually need to access the TimeStepData. Thus, we have a circular dependency of information, and we include the following example for its use.
First, we define the two operators used by ThetaTimestepping and call them Implicit
and Explicit
. They both share the public interface of Operator, and additionally provide storage for the matrices to be used and a pointer to TimestepData. Note that we do not use a ObserverPointer here, since the TimestepData will be destroyed before the operator.
These operators will be implemented after the main program. But let us look first at how they get used. First, let us define a matrix to be used for our system and also an OutputOperator in order to write the data of each timestep to a file.
Now we create objects for the implicit and explicit parts of the steps as well as the ThetaTimestepping itself. We initialize the timestepping with the output operator in order to be able to see the output in every step.
The next step is providing the vectors to be used. value
is filled with the initial value and is also the vector where the solution at each timestep will be. Because the interface of Operator has to be able to handle several vectors, we need to store it in an AnyData object. Since our problem has no additional parameters, the input AnyData object remains empty.
Finally, we are ready to tell the solver, that we are starting at the initial timestep and run it.
Besides the main function, we need to define the members functions of the implicit and explicit operators. First the constructor, which simply copies the system matrix into the member pointer for later use.
Now we need to study the application of the implicit and explicit operator. We assume that the pointer matrix
points to the matrix created in the main program (the constructor did this for us). Here, we first get the time step size from the AnyData object that was provided as input. Then, if we are in the first step or if the timestep has changed, we fill the local matrix \(m\), such that with the given matrix \(M\), it becomes
\[ m = I - \Delta t M. \]
After we have worked off the notifications, we clear them, such that the matrix is only generated when necessary.
Now we multiply the input vector with the new matrix and store on output.
The code for the implicit operator is almost the same, except that we change the sign in front of the timestep and use the inverse of the matrix.
Definition at line 286 of file theta_timestepping.h.
|
privateinherited |
The data type used in counter_map.
Definition at line 238 of file enable_observer_pointer.h.
|
privateinherited |
The iterator type used in counter_map.
Definition at line 243 of file enable_observer_pointer.h.
Algorithms::ThetaTimestepping< VectorType >::ThetaTimestepping | ( | OperatorBase & | op_explicit, |
OperatorBase & | op_implicit | ||
) |
Constructor, receiving the two operators stored in op_explicit and op_implicit. For their meaning, see the description of those variables.
|
overridevirtual |
The timestepping scheme.
in | is ignored by ThetaTimestepping, but is merged into the AnyData objects used as input for the operators op_explicit and op_implicit. |
out | in its first argument must contain a pointer to a VectorType instance, which contains the initial value when the operator is called. It contains the final value when the operator returns. |
Implements Algorithms::OperatorBase.
|
overridevirtual |
Register an event triggered by an outer iteration.
Reimplemented from Algorithms::OperatorBase.
|
inline |
Define an operator which will output the result in each step. Note that no output will be generated without this.
Definition at line 462 of file theta_timestepping.h.
|
static |
Declare parameters in a parameter handler.
void Algorithms::ThetaTimestepping< VectorType >::parse_parameters | ( | ParameterHandler & | param | ) |
Read the parameters in the ParameterHandler.
|
inline |
The current time in the timestepping scheme.
Definition at line 488 of file theta_timestepping.h.
|
inline |
The weight between implicit and explicit part.
Definition at line 470 of file theta_timestepping.h.
|
inline |
Set a new weight and return the old
Definition at line 478 of file theta_timestepping.h.
|
inline |
The data handed to the op_explicit time stepping operator.
The time in here is the time at the beginning of the current step, the time step is (1-theta) times the actual time step.
Definition at line 439 of file theta_timestepping.h.
|
inline |
The data handed to the op_implicit time stepping operator.
The time in here is the time at the beginning of the current step, the time step is theta times the actual time step.
Definition at line 447 of file theta_timestepping.h.
|
inline |
Allow access to the control object.
Definition at line 455 of file theta_timestepping.h.
|
inherited |
Clear all notifications.
Definition at line 46 of file operator.cc.
|
inherited |
Subscribes a user of the object by storing the pointer validity
. The subscriber may be identified by text supplied as identifier
.
Definition at line 131 of file enable_observer_pointer.cc.
|
inherited |
Unsubscribes a user from the object.
identifier
and the validity
pointer must be the same as the one supplied to subscribe(). Definition at line 151 of file enable_observer_pointer.cc.
|
inlineinherited |
Return the present number of subscriptions to this object. This allows to use this class for reference counted lifetime determination where the last one to unsubscribe also deletes the object.
Definition at line 322 of file enable_observer_pointer.h.
|
inlineinherited |
List the subscribers to the input stream
.
Definition at line 339 of file enable_observer_pointer.h.
|
inherited |
List the subscribers to deallog
.
Definition at line 199 of file enable_observer_pointer.cc.
|
inlineinherited |
Read or write the data of this object to or from a stream for the purpose of serialization using the BOOST serialization library.
This function does not actually serialize any of the member variables of this class. The reason is that what this class stores is only who subscribes to this object, but who does so at the time of storing the contents of this object does not necessarily have anything to do with who subscribes to the object when it is restored. Consequently, we do not want to overwrite the subscribers at the time of restoring, and then there is no reason to write the subscribers out in the first place.
Definition at line 331 of file enable_observer_pointer.h.
|
privatenoexceptinherited |
Check that there are no objects subscribing to this object. If this check passes then it is safe to destroy the current object. It this check fails then this function will either abort or print an error message to deallog (by using the AssertNothrow mechanism), but will not throw an exception.
Definition at line 53 of file enable_observer_pointer.cc.
|
private |
The object controlling the time step size and computing the new time in each step.
Definition at line 382 of file theta_timestepping.h.
|
private |
The control parameter theta in the range [0,1]
. It defaults to 0.5.
Definition at line 388 of file theta_timestepping.h.
|
private |
Use adaptive theta if true
. Not yet implemented.
Definition at line 392 of file theta_timestepping.h.
|
private |
The data for the explicit part of the scheme.
Definition at line 397 of file theta_timestepping.h.
|
private |
The data for the implicit part of the scheme.
Definition at line 402 of file theta_timestepping.h.
|
private |
The operator computing the explicit part of the scheme. This will receive in its input data the value at the current time with name "Current time solution". It should obtain the current time and time step size from explicit_data().
Its return value is \( Mu+cF(u) \), where \(u\) is the current state vector, \(M\) the mass matrix, \(F\) the operator in space and \(c\) is the adjusted time step size \((1-\theta) \Delta t\).
Definition at line 415 of file theta_timestepping.h.
|
private |
The operator solving the implicit part of the scheme. It will receive in its input data the vector "Previous time". Information on the timestep should be obtained from implicit_data().
Its return value is the solution u of Mu-cF(u)=f, where f is the dual space vector found in the "Previous time" entry of the input data, M the mass matrix, F the operator in space and c is the adjusted time step size \( \theta \Delta t\)
Definition at line 427 of file theta_timestepping.h.
|
private |
The operator writing the output in each time step
Definition at line 433 of file theta_timestepping.h.
|
protectedinherited |
Accumulate events here. If any of those is set, the function solve() of a terminal application must take care of reassembling the matrix.
Definition at line 96 of file operator.h.
|
mutableprivateinherited |
Store the number of objects which subscribed to this object. Initially, this number is zero, and upon destruction it shall be zero again (i.e. all objects which subscribed should have unsubscribed again).
The creator (and owner) of an object is counted in the map below if HE manages to supply identification.
We use the mutable
keyword in order to allow subscription to constant objects also.
This counter may be read from and written to concurrently in multithreaded code: hence we use the std::atomic
class template.
Definition at line 227 of file enable_observer_pointer.h.
|
mutableprivateinherited |
In this map, we count subscriptions for each different identification string supplied to subscribe().
Definition at line 233 of file enable_observer_pointer.h.
|
mutableprivateinherited |
In this vector, we store pointers to the validity bool in the ObserverPointer objects that subscribe to this class.
Definition at line 249 of file enable_observer_pointer.h.
|
mutableprivateinherited |
Pointer to the typeinfo object of this object, from which we can later deduce the class name. Since this information on the derived class is neither available in the destructor, nor in the constructor, we obtain it in between and store it here.
Definition at line 257 of file enable_observer_pointer.h.
|
staticprivateinherited |
A mutex used to ensure data consistency when accessing the mutable
members of this class. This lock is used in the subscribe() and unsubscribe() functions, as well as in list_subscribers()
.
Definition at line 280 of file enable_observer_pointer.h.