Commit 756d9638 authored by Thomas Witkowski's avatar Thomas Witkowski
Browse files

Tutorial adapted to new AMDiS

parent 72340bdf
...@@ -46,7 +46,7 @@ public: ...@@ -46,7 +46,7 @@ public:
ProblemStatBase *prob2) ProblemStatBase *prob2)
: problem1(prob1), : problem1(prob1),
problem2(prob2) problem2(prob2)
{}; {}
\end{lstlisting} \end{lstlisting}
In the constructor pointers to the two problems are assigned to the private members \verb+problem1+ and \verb+problem2+. Note that the pointers point to the interface \verb+ProblemStatBase+ and not to\\ \verb+ProblemScal+. This leads to a more general implementation. If e.g. two vector valued problems should be coupled in the future, we could use our iteration class without modifications. In the constructor pointers to the two problems are assigned to the private members \verb+problem1+ and \verb+problem2+. Note that the pointers point to the interface \verb+ProblemStatBase+ and not to\\ \verb+ProblemScal+. This leads to a more general implementation. If e.g. two vector valued problems should be coupled in the future, we could use our iteration class without modifications.
...@@ -60,14 +60,14 @@ Now, we implement the needed interface methods: ...@@ -60,14 +60,14 @@ Now, we implement the needed interface methods:
MSG("\n"); MSG("\n");
MSG("begin of iteration %d\n", adaptInfo->getSpaceIteration()+1); MSG("begin of iteration %d\n", adaptInfo->getSpaceIteration()+1);
MSG("=============================\n"); MSG("=============================\n");
}; }
void endIteration(AdaptInfo *adaptInfo) { void endIteration(AdaptInfo *adaptInfo) {
FUNCNAME("StandardProblemIteration::endIteration()"); FUNCNAME("StandardProblemIteration::endIteration()");
MSG("\n"); MSG("\n");
MSG("end of iteration %d\n", adaptInfo->getSpaceIteration()+1); MSG("end of iteration %d\n", adaptInfo->getSpaceIteration()+1);
MSG("=============================\n"); MSG("=============================\n");
}; }
\end{lstlisting} \end{lstlisting}
These two functions are called at the beginning and at the end of each iteration. Here, we only prompt some output. These two functions are called at the beginning and at the end of each iteration. Here, we only prompt some output.
...@@ -78,19 +78,19 @@ The method \verb+oneIteration+ is the crucial part of our implementation: ...@@ -78,19 +78,19 @@ The method \verb+oneIteration+ is the crucial part of our implementation:
Flag oneIteration(AdaptInfo *adaptInfo, Flag toDo = FULL_ITERATION) Flag oneIteration(AdaptInfo *adaptInfo, Flag toDo = FULL_ITERATION)
{ {
Flag flag, markFlag; Flag flag, markFlag;
if(toDo.isSet(MARK)) markFlag = problem1->markElements(adaptInfo); if (toDo.isSet(MARK)) markFlag = problem1->markElements(adaptInfo);
if(toDo.isSet(ADAPT) && markFlag.isSet(MESH_REFINED)) { if (toDo.isSet(ADAPT) && markFlag.isSet(MESH_REFINED))
flag = problem1->refineMesh(adaptInfo); flag = problem1->refineMesh(adaptInfo);
}
if(toDo.isSet(BUILD)) problem1->buildAfterCoarsen(adaptInfo, markFlag);
if(toDo.isSet(SOLVE)) problem1->solve(adaptInfo);
if(toDo.isSet(BUILD)) problem2->buildAfterCoarsen(adaptInfo, markFlag); if (toDo.isSet(BUILD)) problem1->buildAfterCoarsen(adaptInfo, markFlag);
if(toDo.isSet(SOLVE)) problem2->solve(adaptInfo); if (toDo.isSet(SOLVE)) problem1->solve(adaptInfo);
if(toDo.isSet(ESTIMATE)) problem1->estimate(adaptInfo); if (toDo.isSet(BUILD)) problem2->buildAfterCoarsen(adaptInfo, markFlag);
if (toDo.isSet(SOLVE)) problem2->solve(adaptInfo);
if (toDo.isSet(ESTIMATE)) problem1->estimate(adaptInfo);
return flag; return flag;
}; }
\end{lstlisting} \end{lstlisting}
The \verb+toDo+ flag is used by the adaptation loop to determine which parts of the iteration should be performed. The first iteration is always an iteration without mesh adaptation (see Figure \ref{f:stationary loop}). So we start our iteration by marking and adapting the mesh. The mesh and its adaptation is managed by the first problem. So we call \verb+markElements+ and \verb+refineMesh+ of \verb+problem1+. Note that no mesh coarsenings have to be performed in our example. Afterwards, \verb+problem1+ assembles its system of equations by \verb+buildAfterCoarsen+. Assemblage and mesh adaptation are nested operations in AMDiS (\verb+buildBeforeRefine+, \verb+refineMesh+, \verb+buildBeforeCoarsen+,\\\verb+coarsenMesh+,\verb+buildAfterCoarsen+). Here, we implement a simplified version. The \verb+toDo+ flag is used by the adaptation loop to determine which parts of the iteration should be performed. The first iteration is always an iteration without mesh adaptation (see Figure \ref{f:stationary loop}). So we start our iteration by marking and adapting the mesh. The mesh and its adaptation is managed by the first problem. So we call \verb+markElements+ and \verb+refineMesh+ of \verb+problem1+. Note that no mesh coarsenings have to be performed in our example. Afterwards, \verb+problem1+ assembles its system of equations by \verb+buildAfterCoarsen+. Assemblage and mesh adaptation are nested operations in AMDiS (\verb+buildBeforeRefine+, \verb+refineMesh+, \verb+buildBeforeCoarsen+,\\\verb+coarsenMesh+,\verb+buildAfterCoarsen+). Here, we implement a simplified version.
...@@ -111,16 +111,16 @@ Now, the access to the coupled problems is implemented and the member variables ...@@ -111,16 +111,16 @@ Now, the access to the coupled problems is implemented and the member variables
int getNumProblems() int getNumProblems()
{ {
return 2; return 2;
}; }
ProblemStatBase *getProblem(int number = 0) ProblemStatBase *getProblem(int number = 0)
{ {
FUNCNAME("CoupledIteration::getProblem()"); FUNCNAME("CoupledIteration::getProblem()");
if(number == 0) return problem1; if (number == 0) return problem1;
if(number == 1) return problem2; if (number == 1) return problem2;
ERROR_EXIT("invalid problem number\n"); ERROR_EXIT("invalid problem number\n");
return NULL; return NULL;
}; }
private: private:
ProblemStatBase *problem1; ProblemStatBase *problem1;
...@@ -136,15 +136,12 @@ The next class, \verb+Identity+, implements the identity $I(x)=x$ for \verb+doub ...@@ -136,15 +136,12 @@ The next class, \verb+Identity+, implements the identity $I(x)=x$ for \verb+doub
class Identity : public AbstractFunction<double, double> class Identity : public AbstractFunction<double, double>
{ {
public: public:
MEMORY_MANAGED(Identity); Identity(int degree) : AbstractFunction<double, double>(degree) {}
Identity(int degree) : AbstractFunction<double, double>(degree) {};
const double& operator()(const double& x) const { double operator()(const double& x) const
static double result; {
result = x; return x;
return result; }
};
}; };
\end{lstlisting} \end{lstlisting}
...@@ -162,7 +159,7 @@ int main(int argc, char* argv[]) ...@@ -162,7 +159,7 @@ int main(int argc, char* argv[])
problem1.initialize(INIT_ALL); problem1.initialize(INIT_ALL);
// ===== add boundary conditions for problem1 ===== // ===== add boundary conditions for problem1 =====
problem1.addDirichletBC(1, NEW G); problem1.addDirichletBC(1, new G);
\end{lstlisting} \end{lstlisting}
So far, we created and initialized \verb+problem1+ and its boundary conditions. So far, we created and initialized \verb+problem1+ and its boundary conditions.
...@@ -193,12 +190,12 @@ The operators for the first problem are defined like in Section \ref{s:ellipt co ...@@ -193,12 +190,12 @@ The operators for the first problem are defined like in Section \ref{s:ellipt co
// ===== create operators for problem2 ===== // ===== create operators for problem2 =====
Operator matrixOperator2(Operator::MATRIX_OPERATOR, Operator matrixOperator2(Operator::MATRIX_OPERATOR,
problem2.getFESpace()); problem2.getFESpace());
matrixOperator2.addZeroOrderTerm(NEW Simple_ZOT); matrixOperator2.addZeroOrderTerm(new Simple_ZOT);
problem2.addMatrixOperator(&matrixOperator2); problem2.addMatrixOperator(&matrixOperator2);
Operator rhsOperator2(Operator::VECTOR_OPERATOR, problem2.getFESpace()); Operator rhsOperator2(Operator::VECTOR_OPERATOR, problem2.getFESpace());
rhsOperator2.addZeroOrderTerm(NEW VecAtQP_ZOT(problem1.getSolution(), rhsOperator2.addZeroOrderTerm(new VecAtQP_ZOT(problem1.getSolution(),
NEW Identity(degree))); new Identity(degree)));
problem2.addVectorOperator(&rhsOperator2); problem2.addVectorOperator(&rhsOperator2);
\end{lstlisting} \end{lstlisting}
...@@ -208,11 +205,11 @@ Now, the adaptation loop is created: ...@@ -208,11 +205,11 @@ Now, the adaptation loop is created:
\begin{lstlisting}{} \begin{lstlisting}{}
// ===== create adaptation loop and iteration interface ===== // ===== create adaptation loop and iteration interface =====
AdaptInfo *adaptInfo = NEW AdaptInfo("couple->adapt", 1); AdaptInfo *adaptInfo = new AdaptInfo("couple->adapt", 1);
MyCoupledIteration coupledIteration(&problem1, &problem2); MyCoupledIteration coupledIteration(&problem1, &problem2);
AdaptStationary *adapt = NEW AdaptStationary("couple->adapt", AdaptStationary *adapt = new AdaptStationary("couple->adapt",
&coupledIteration, &coupledIteration,
adaptInfo); adaptInfo);
\end{lstlisting} \end{lstlisting}
......
...@@ -59,8 +59,6 @@ Now, the functions $f$ and $g$ will be defined by the classes \verb+F+ and \verb ...@@ -59,8 +59,6 @@ Now, the functions $f$ and $g$ will be defined by the classes \verb+F+ and \verb
class G : public AbstractFunction<double, WorldVector<double> > class G : public AbstractFunction<double, WorldVector<double> >
{ {
public: public:
MEMORY_MANAGED(G);
double operator()(const WorldVector<double>& x) const double operator()(const WorldVector<double>& x) const
{ {
return exp(-10.0 * (x * x)); return exp(-10.0 * (x * x));
...@@ -77,24 +75,16 @@ type \verb+double+. The actual mapping is defined by overloading the ...@@ -77,24 +75,16 @@ type \verb+double+. The actual mapping is defined by overloading the
\verb+operator()+. \verb+x*x+ stands for the scalar product of vector \verb+operator()+. \verb+x*x+ stands for the scalar product of vector
\verb+x+ with itself. \verb+x+ with itself.
Using the macro call \verb+MEMORY_MANAGED(G)+, the class will be
managed by the memory management of AMDiS. This memory management
provides memory monitoring to locate memory leaks and block memory
allocation to accelerate memory access. Objects of a memory managed
class can now be allocated through the memory manager by the macro
\verb+NEW+ and deallocated by the macro \verb+DELETE+.
The class \verb+F+ is defined in a similar way: The class \verb+F+ is defined in a similar way:
\begin{lstlisting}{} \begin{lstlisting}{}
class F : public AbstractFunction<double, WorldVector<double> > class F : public AbstractFunction<double, WorldVector<double> >
{ {
public: public:
MEMORY_MANAGED(F); F(int degree) : AbstractFunction<double, WorldVector<double> >(degree) {}
F(int degree) : AbstractFunction<double, WorldVector<double> >(degree) {};
double operator()(const WorldVector<double>& x) const { double operator()(const WorldVector<double>& x) const
{
int dow = Global::getGeo(WORLD); int dow = Global::getGeo(WORLD);
double r2 = (x * x); double r2 = (x * x);
double ux = exp(-10.0 * r2); double ux = exp(-10.0 * r2);
...@@ -136,10 +126,10 @@ The next steps are the creation of the adaptation loop and the corresponding \ve ...@@ -136,10 +126,10 @@ The next steps are the creation of the adaptation loop and the corresponding \ve
\begin{lstlisting}{} \begin{lstlisting}{}
// === create adapt info === // === create adapt info ===
AdaptInfo *adaptInfo = NEW AdaptInfo("ellipt->adapt", 1); AdaptInfo *adaptInfo = new AdaptInfo("ellipt->adapt", 1);
// === create adapt === // === create adapt ===
AdaptStationary *adapt = NEW AdaptStationary("ellipt->adapt", &ellipt, AdaptStationary *adapt = new AdaptStationary("ellipt->adapt", &ellipt,
adaptInfo); adaptInfo);
\end{lstlisting} \end{lstlisting}
...@@ -150,7 +140,7 @@ Now, we define boundary conditions: ...@@ -150,7 +140,7 @@ Now, we define boundary conditions:
\begin{lstlisting}{} \begin{lstlisting}{}
// ===== add boundary conditions ===== // ===== add boundary conditions =====
ellipt.addDirichletBC(1, NEW G); ellipt.addDirichletBC(1, new G);
\end{lstlisting} \end{lstlisting}
We have one Dirichlet boundary condition associated with identifier $1$. All nodes belonging to this boundary are set to the value of function \verb+G+ at the corresponding coordinates. In the macro file (see Section \ref{s:ellipt macro}) the Dirichlet boundary is marked with identifier $1$, too. So the nodes can be uniquely determined. We have one Dirichlet boundary condition associated with identifier $1$. All nodes belonging to this boundary are set to the value of function \verb+G+ at the corresponding coordinates. In the macro file (see Section \ref{s:ellipt macro}) the Dirichlet boundary is marked with identifier $1$, too. So the nodes can be uniquely determined.
...@@ -160,13 +150,13 @@ The operators now are defined as follows: ...@@ -160,13 +150,13 @@ The operators now are defined as follows:
\begin{lstlisting}{} \begin{lstlisting}{}
// ===== create matrix operator ===== // ===== create matrix operator =====
Operator matrixOperator(Operator::MATRIX_OPERATOR, ellipt.getFESpace()); Operator matrixOperator(Operator::MATRIX_OPERATOR, ellipt.getFESpace());
matrixOperator.addSecondOrderTerm(NEW Laplace_SOT); matrixOperator.addSecondOrderTerm(new Laplace_SOT);
ellipt.addMatrixOperator(&matrixOperator); ellipt.addMatrixOperator(&matrixOperator);
// ===== create rhs operator ===== // ===== create rhs operator =====
int degree = ellipt.getFESpace()->getBasisFcts()->getDegree(); int degree = ellipt.getFESpace()->getBasisFcts()->getDegree();
Operator rhsOperator(Operator::VECTOR_OPERATOR, ellipt.getFESpace()); Operator rhsOperator(Operator::VECTOR_OPERATOR, ellipt.getFESpace());
rhsOperator.addZeroOrderTerm(NEW CoordsAtQP_ZOT(NEW F(degree))); rhsOperator.addZeroOrderTerm(new CoordsAtQP_ZOT(new F(degree)));
ellipt.addVectorOperator(&rhsOperator); ellipt.addVectorOperator(&rhsOperator);
\end{lstlisting} \end{lstlisting}
......
...@@ -58,8 +58,6 @@ class G : public AbstractFunction<double, WorldVector<double> >, ...@@ -58,8 +58,6 @@ class G : public AbstractFunction<double, WorldVector<double> >,
public TimedObject public TimedObject
{ {
public: public:
MEMORY_MANAGED(G);
double operator()(const WorldVector<double>& x) const double operator()(const WorldVector<double>& x) const
{ {
return sin(M_PI * (*timePtr)) * exp(-10.0 *(x * x)); return sin(M_PI * (*timePtr)) * exp(-10.0 *(x * x));
...@@ -87,8 +85,6 @@ The first lines of class \verb+Heat+ are: ...@@ -87,8 +85,6 @@ The first lines of class \verb+Heat+ are:
class Heat : public ProblemInstatScal class Heat : public ProblemInstatScal
{ {
public: public:
MEMORY_MANAGED(Heat);
Heat(ProblemScal *heatSpace) Heat(ProblemScal *heatSpace)
: ProblemInstatScal("heat", heatSpace) : ProblemInstatScal("heat", heatSpace)
{ {
...@@ -96,7 +92,7 @@ public: ...@@ -96,7 +92,7 @@ public:
GET_PARAMETER(0, name + "->theta", "%f", &theta); GET_PARAMETER(0, name + "->theta", "%f", &theta);
TEST_EXIT(theta >= 0)("theta not set!\n"); TEST_EXIT(theta >= 0)("theta not set!\n");
theta1 = theta - 1; theta1 = theta - 1;
}; }
\end{lstlisting} \end{lstlisting}
The argument \verb+heatSpace+ is a pointer to the stationary problem which is solved each timestep. It is directly handed to the base class constructor of \verb+ProblemInstatScal+. In the body of the constructor, $\theta$ is read from the parameter file and stored in a member variable. The member variable \verb+theta1+ stores the value of $\theta - 1$. A pointer to this value is used later as factor in the $\theta$-scheme. The argument \verb+heatSpace+ is a pointer to the stationary problem which is solved each timestep. It is directly handed to the base class constructor of \verb+ProblemInstatScal+. In the body of the constructor, $\theta$ is read from the parameter file and stored in a member variable. The member variable \verb+theta1+ stores the value of $\theta - 1$. A pointer to this value is used later as factor in the $\theta$-scheme.
...@@ -104,18 +100,20 @@ The argument \verb+heatSpace+ is a pointer to the stationary problem which is so ...@@ -104,18 +100,20 @@ The argument \verb+heatSpace+ is a pointer to the stationary problem which is so
The next lines show the implementation of the time interface. The next lines show the implementation of the time interface.
\begin{lstlisting}{} \begin{lstlisting}{}
void setTime(AdaptInfo *adaptInfo) { void setTime(AdaptInfo *adaptInfo)
{
rhsTime = rhsTime =
adaptInfo->getTime()- adaptInfo->getTime()-
(1-theta)*adaptInfo->getTimestep(); (1-theta)*adaptInfo->getTimestep();
boundaryTime = adaptInfo->getTime(); boundaryTime = adaptInfo->getTime();
tau1 = 1.0 / adaptInfo->getTimestep(); tau1 = 1.0 / adaptInfo->getTimestep();
}; }
void closeTimestep(AdaptInfo *adaptInfo) { void closeTimestep(AdaptInfo *adaptInfo)
{
ProblemInstatScal::closeTimestep(adaptInfo); ProblemInstatScal::closeTimestep(adaptInfo);
WAIT; WAIT;
}; }
\end{lstlisting} \end{lstlisting}
The method \verb+setTime+ is called by the adaptation loop to inform the problem about the current time. The right hand side function $f$ will be evaluated at $t^{old}+\theta\tau = t^{new} - (1-\theta)\tau$, the Dirichlet boundary function $g$ at $t^{new}$. $t^{new}$ is the current time, $\tau$ is the current timestep, both set by the adaptation loop and stored in \verb+adaptInfo+. \verb+tau1+ stores the value of $\frac{1}{\tau}$, which is used later as factor for the zero order time discretization terms. The method \verb+setTime+ is called by the adaptation loop to inform the problem about the current time. The right hand side function $f$ will be evaluated at $t^{old}+\theta\tau = t^{new} - (1-\theta)\tau$, the Dirichlet boundary function $g$ at $t^{new}$. $t^{new}$ is the current time, $\tau$ is the current timestep, both set by the adaptation loop and stored in \verb+adaptInfo+. \verb+tau1+ stores the value of $\frac{1}{\tau}$, which is used later as factor for the zero order time discretization terms.
...@@ -128,7 +126,7 @@ Now, the implementation of the \verb+ProblemStatBase+ interface begins. As menti ...@@ -128,7 +126,7 @@ Now, the implementation of the \verb+ProblemStatBase+ interface begins. As menti
void solve(AdaptInfo *adaptInfo) void solve(AdaptInfo *adaptInfo)
{ {
problemStat->getSolution()->interpol(exactSolution); problemStat->getSolution()->interpol(exactSolution);
}; }
void estimate(AdaptInfo *adaptInfo) void estimate(AdaptInfo *adaptInfo)
{ {
...@@ -138,7 +136,7 @@ Now, the implementation of the \verb+ProblemStatBase+ interface begins. As menti ...@@ -138,7 +136,7 @@ Now, the implementation of the \verb+ProblemStatBase+ interface begins. As menti
0, &errMax, false); 0, &errMax, false);
adaptInfo->setEstSum(errSum, 0); adaptInfo->setEstSum(errSum, 0);
adaptInfo->setEstMax(errMax, 0); adaptInfo->setEstMax(errMax, 0);
}; }
\end{lstlisting} \end{lstlisting}
Here, only the solve and the estimate step are overloaded. For the other steps, there are empty default implementations in \verb+ProblemInstatScal+. Since the mesh is not adapted in the initial problem, the initial adaptation loop will stop after one iteration. In the solve step, the exact solution is interpolated on the macro mesh and stored in the solution vector of the stationary problem. In the estimate step, the L2 error is computed. The maximal element error and the sum over all element errors are stored in \verb+adaptInfo+. To make the exact solution known to the problem, we need a setting function: Here, only the solve and the estimate step are overloaded. For the other steps, there are empty default implementations in \verb+ProblemInstatScal+. Since the mesh is not adapted in the initial problem, the initial adaptation loop will stop after one iteration. In the solve step, the exact solution is interpolated on the macro mesh and stored in the solution vector of the stationary problem. In the estimate step, the L2 error is computed. The maximal element error and the sum over all element errors are stored in \verb+adaptInfo+. To make the exact solution known to the problem, we need a setting function:
...@@ -181,7 +179,7 @@ int main(int argc, char** argv) ...@@ -181,7 +179,7 @@ int main(int argc, char** argv)
Parameters::init(false, argv[1]); Parameters::init(false, argv[1]);
// ===== create and init stationary problem ===== // ===== create and init stationary problem =====
ProblemScal *heatSpace = NEW ProblemScal("heat->space"); ProblemScal *heatSpace = new ProblemScal("heat->space");
heatSpace->initialize(INIT_ALL); heatSpace->initialize(INIT_ALL);
// ===== create instationary problem ===== // ===== create instationary problem =====
...@@ -195,13 +193,13 @@ The next step is the creation of the needed \verb+AdaptInfo+ objects and of the ...@@ -195,13 +193,13 @@ The next step is the creation of the needed \verb+AdaptInfo+ objects and of the
\begin{lstlisting}{} \begin{lstlisting}{}
// create adapt info for heat // create adapt info for heat
AdaptInfo *adaptInfo = NEW AdaptInfo("heat->adapt"); AdaptInfo *adaptInfo = new AdaptInfo("heat->adapt");
// create initial adapt info // create initial adapt info
AdaptInfo *adaptInfoInitial = NEW AdaptInfo("heat->initial->adapt"); AdaptInfo *adaptInfoInitial = new AdaptInfo("heat->initial->adapt");
// create instationary adapt // create instationary adapt
AdaptInstationary *adaptInstat = NEW AdaptInstationary("heat->adapt", AdaptInstationary *adaptInstat = new AdaptInstationary("heat->adapt",
heatSpace, heatSpace,
adaptInfo, adaptInfo,
heat, heat,
...@@ -214,7 +212,7 @@ The definitions of functions $f$ and $g$ are: ...@@ -214,7 +212,7 @@ The definitions of functions $f$ and $g$ are:
\begin{lstlisting}{} \begin{lstlisting}{}
// ===== create boundary functions ===== // ===== create boundary functions =====
G *boundaryFct = NEW G; G *boundaryFct = new G;
boundaryFct->setTimePtr(heat->getBoundaryTimePtr()); boundaryFct->setTimePtr(heat->getBoundaryTimePtr());
heat->setExactSolution(boundaryFct); heat->setExactSolution(boundaryFct);
...@@ -222,7 +220,7 @@ The definitions of functions $f$ and $g$ are: ...@@ -222,7 +220,7 @@ The definitions of functions $f$ and $g$ are:
// ===== create rhs functions ===== // ===== create rhs functions =====
int degree = heatSpace->getFESpace()->getBasisFcts()->getDegree(); int degree = heatSpace->getFESpace()->getBasisFcts()->getDegree();
F *rhsFct = NEW F(degree); F *rhsFct = new F(degree);
rhsFct->setTimePtr(heat->getRHSTimePtr()); rhsFct->setTimePtr(heat->getRHSTimePtr());
\end{lstlisting} \end{lstlisting}
...@@ -236,7 +234,7 @@ Now, we define the operators: ...@@ -236,7 +234,7 @@ Now, we define the operators:
double zero = 0.0; double zero = 0.0;
// create laplace // create laplace
Operator *A = NEW Operator(Operator::MATRIX_OPERATOR | Operator *A = new Operator(Operator::MATRIX_OPERATOR |
Operator::VECTOR_OPERATOR, Operator::VECTOR_OPERATOR,
heatSpace->getFESpace()); heatSpace->getFESpace());
...@@ -255,11 +253,11 @@ Operator \verb+A+ represents $-\Delta u$. It is used as matrix operator on the l ...@@ -255,11 +253,11 @@ Operator \verb+A+ represents $-\Delta u$. It is used as matrix operator on the l
\begin{lstlisting}{} \begin{lstlisting}{}
// create zero order operator // create zero order operator
Operator *C = NEW Operator(Operator::MATRIX_OPERATOR | Operator *C = new Operator(Operator::MATRIX_OPERATOR |
Operator::VECTOR_OPERATOR, Operator::VECTOR_OPERATOR,
heatSpace->getFESpace()); heatSpace->getFESpace());
C->addZeroOrderTerm(NEW Simple_ZOT); C->addZeroOrderTerm(new Simple_ZOT);
C->setUhOld(heat->getOldSolution()); C->setUhOld(heat->getOldSolution());
...@@ -273,10 +271,10 @@ Finally, the operator for the right hand side function $f$ is added and the adap ...@@ -273,10 +271,10 @@ Finally, the operator for the right hand side function $f$ is added and the adap
\begin{lstlisting}{} \begin{lstlisting}{}
// create RHS operator // create RHS operator
Operator *F = NEW Operator(Operator::VECTOR_OPERATOR, Operator *F = new Operator(Operator::VECTOR_OPERATOR,
heatSpace->getFESpace()); heatSpace->getFESpace());
F->addZeroOrderTerm(NEW CoordsAtQP_ZOT(rhsFct)); F->addZeroOrderTerm(new CoordsAtQP_ZOT(rhsFct));
heatSpace->addVectorOperator(F); heatSpace->addVectorOperator(F);
......
...@@ -28,8 +28,6 @@ Only a few changes in the source code are necessary to apply Neumann boundary co ...@@ -28,8 +28,6 @@ Only a few changes in the source code are necessary to apply Neumann boundary co
class N : public AbstractFunction<double, WorldVector<double> > class N : public AbstractFunction<double, WorldVector<double> >
{ {
public: public:
MEMORY_MANAGED(N);
double operator()(const WorldVector<double>& x) const double operator()(const WorldVector<double>& x) const
{ {
return 1.0; return 1.0;
...@@ -43,8 +41,8 @@ In the main program we add the boundary conditions to our problem \verb+neumann+ ...@@ -43,8 +41,8 @@ In the main program we add the boundary conditions to our problem \verb+neumann+
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
... ...
neumann.addNeumannBC(1, NEW N); neumann.addNeumannBC(1, new N);
neumann.addDirichletBC(2, NEW G); neumann.addDirichletBC(2, new G);
... ...
} }
\end{lstlisting} \end{lstlisting}
......
...@@ -71,9 +71,8 @@ Now, we describe the code step by step. The function $g$ is defined like in the ...@@ -71,9 +71,8 @@ Now, we describe the code step by step. The function $g$ is defined like in the
class Zero : public AbstractFunction<double, WorldVector<double> > class Zero : public AbstractFunction<double, WorldVector<double> >
{ {
public: public:
MEMORY_MANAGED(Zero); double operator()(const WorldVector<double>& x) const
{
double operator()(const WorldVector<double>& x) const {
return 0.0; return 0.0;
} }
}; };
...@@ -81,19 +80,14 @@ public: ...@@ -81,19 +80,14 @@ public:
class F : public AbstractFunction<double, WorldVector<double> > class F : public AbstractFunction<double, WorldVector<double> >
{ {
public: public:
MEMORY_MANAGED(F); /// Constructor
/** \brief
* Constructor
*/
F(int degree) F(int degree)
: AbstractFunction<double, WorldVector<double> >(degree) : AbstractFunction<double, WorldVector<double> >(degree)
{}; {}
/** \brief /// Implementation of AbstractFunction::operator().
* Implementation of AbstractFunction::operator(). double operator()(const WorldVector<double>& x) const
*/ {
double operator()(const WorldVector<double>& x) const {
int dow = x.getSize(); int dow = x.getSize();
double r2 = x * x; double r2 = x * x;
double ux = exp(-10.0 * r2); double ux = exp(-10.0 * r2);
...@@ -109,14 +103,11 @@ The class \verb+X3+ implements the function $u^3(x)$ used within the Newton step ...@@ -109,14 +103,11 @@ The class \verb+X3+ implements the function $u^3(x)$ used within the Newton step
class X3 : public AbstractFunction<double, double> class X3 : public AbstractFunction<double, double>
{ {
public: public:
MEMORY_MANAGED(X3); X3() : AbstractFunction<double, double>(3) {}
X3() : AbstractFunction<double, double>(3) {}; /// Implementation of AbstractFunction::operator().
double operator()(const double& x) const
/** \brief {
* Implementation of AbstractFunction::operator().
*/
double operator()(const double& x) const {
return x * x * x; return x * x * x;
} }
}; };
...@@ -158,7 +149,7 @@ public: ...@@ -158,7 +149,7 @@ public:
&newtonMaxIter); &newtonMaxIter);
solution = problemNonlin->getSolution(); solution = problemNonlin->getSolution();
correction = newtonStep->getCorrection(); correction = newtonStep->getCorrection();
}; }
\end{lstlisting} \end{lstlisting}
In the constructor, pointers to the nonlinear problem and to the Newton-step object are stored to the class members \verb+problemNonlin+ and \verb+newtonStep+. Furthermore, the parameters \verb+newtonTolerance+ and \verb+newtonMaxIter+ are initialized, and pointers to the nonlinear solution and to the correction vector are stored. In the constructor, pointers to the nonlinear problem and to the Newton-step object are stored to the class members \verb+problemNonlin+ and \verb+newtonStep+. Furthermore, the parameters \verb+newtonTolerance+ and \verb+newtonMaxIter+ are initialized, and pointers to the nonlinear solution and to the correction vector are stored.
...@@ -178,13 +169,13 @@ The following methods define one iteration in the adaptation loop. ...@@ -178,13 +169,13 @@ The following methods define one iteration in the adaptation loop.
{ {
Flag flag = 0, markFlag = 0; Flag flag = 0, markFlag = 0;
if(toDo.isSet(MARK)) markFlag = problemNonlin->markElements(adaptInfo); if (toDo.isSet(MARK)) markFlag = problemNonlin->markElements(adaptInfo);
if(toDo.isSet(ADAPT) && markFlag.isSet(MESH_REFINED)) if (toDo.isSet(ADAPT) && markFlag.isSet(MESH_REFINED))
flag = problemNonlin->refineMesh(adaptInfo); flag = problemNonlin->refineMesh(adaptInfo);
if(toDo.isSet(ADAPT) && markFlag.isSet(MESH_COARSENED)) if (toDo.isSet(ADAPT) && markFlag.isSet(MESH_COARSENED))
flag |= problemNonlin->coarsenMesh(adaptInfo); flag |= problemNonlin->coarsenMesh(adaptInfo);
if(toDo.isSet(SOLVE)) { if (toDo.isSet(SOLVE)) {
newtonStep->initNewtonStep(adaptInfo); newtonStep->initNewtonStep(adaptInfo);
int newtonIteration = 0; int newtonIteration = 0;
double res = 0.0; double res = 0.0;
...@@ -196,14 +187,14 @@ The following methods define one iteration in the adaptation loop. ...@@ -196,14 +187,14 @@ The following methods define one iteration in the adaptation loop.