Skip to content
Snippets Groups Projects
Commit 756d9638 authored by Thomas Witkowski's avatar Thomas Witkowski
Browse files

Tutorial adapted to new AMDiS

parent 72340bdf
No related branches found
No related tags found
No related merge requests found
......@@ -46,7 +46,7 @@ public:
ProblemStatBase *prob2)
: problem1(prob1),
problem2(prob2)
{};
{}
\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.
......@@ -60,14 +60,14 @@ Now, we implement the needed interface methods:
MSG("\n");
MSG("begin of iteration %d\n", adaptInfo->getSpaceIteration()+1);
MSG("=============================\n");
};
}
void endIteration(AdaptInfo *adaptInfo) {
FUNCNAME("StandardProblemIteration::endIteration()");
MSG("\n");
MSG("end of iteration %d\n", adaptInfo->getSpaceIteration()+1);
MSG("=============================\n");
};
}
\end{lstlisting}
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:
Flag oneIteration(AdaptInfo *adaptInfo, Flag toDo = FULL_ITERATION)
{
Flag flag, markFlag;
if(toDo.isSet(MARK)) markFlag = problem1->markElements(adaptInfo);
if(toDo.isSet(ADAPT) && markFlag.isSet(MESH_REFINED)) {
if (toDo.isSet(MARK)) markFlag = problem1->markElements(adaptInfo);
if (toDo.isSet(ADAPT) && markFlag.isSet(MESH_REFINED))
flag = problem1->refineMesh(adaptInfo);
}
if(toDo.isSet(BUILD)) problem1->buildAfterCoarsen(adaptInfo, markFlag);
if(toDo.isSet(SOLVE)) problem1->solve(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(SOLVE)) problem2->solve(adaptInfo);
if (toDo.isSet(BUILD)) problem2->buildAfterCoarsen(adaptInfo, markFlag);
if (toDo.isSet(SOLVE)) problem2->solve(adaptInfo);
if(toDo.isSet(ESTIMATE)) problem1->estimate(adaptInfo);
if (toDo.isSet(ESTIMATE)) problem1->estimate(adaptInfo);
return flag;
};
}
\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.
......@@ -111,16 +111,16 @@ Now, the access to the coupled problems is implemented and the member variables
int getNumProblems()
{
return 2;
};
}
ProblemStatBase *getProblem(int number = 0)
{
FUNCNAME("CoupledIteration::getProblem()");
if(number == 0) return problem1;
if(number == 1) return problem2;
if (number == 0) return problem1;
if (number == 1) return problem2;
ERROR_EXIT("invalid problem number\n");
return NULL;
};
}
private:
ProblemStatBase *problem1;
......@@ -136,15 +136,12 @@ The next class, \verb+Identity+, implements the identity $I(x)=x$ for \verb+doub
class Identity : public AbstractFunction<double, double>
{
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 {
static double result;
result = x;
return result;
};
double operator()(const double& x) const
{
return x;
}
};
\end{lstlisting}
......@@ -162,7 +159,7 @@ int main(int argc, char* argv[])
problem1.initialize(INIT_ALL);
// ===== add boundary conditions for problem1 =====
problem1.addDirichletBC(1, NEW G);
problem1.addDirichletBC(1, new G);
\end{lstlisting}
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
// ===== create operators for problem2 =====
Operator matrixOperator2(Operator::MATRIX_OPERATOR,
problem2.getFESpace());
matrixOperator2.addZeroOrderTerm(NEW Simple_ZOT);
matrixOperator2.addZeroOrderTerm(new Simple_ZOT);
problem2.addMatrixOperator(&matrixOperator2);
Operator rhsOperator2(Operator::VECTOR_OPERATOR, problem2.getFESpace());
rhsOperator2.addZeroOrderTerm(NEW VecAtQP_ZOT(problem1.getSolution(),
NEW Identity(degree)));
rhsOperator2.addZeroOrderTerm(new VecAtQP_ZOT(problem1.getSolution(),
new Identity(degree)));
problem2.addVectorOperator(&rhsOperator2);
\end{lstlisting}
......@@ -208,11 +205,11 @@ Now, the adaptation loop is created:
\begin{lstlisting}{}
// ===== create adaptation loop and iteration interface =====
AdaptInfo *adaptInfo = NEW AdaptInfo("couple->adapt", 1);
AdaptInfo *adaptInfo = new AdaptInfo("couple->adapt", 1);
MyCoupledIteration coupledIteration(&problem1, &problem2);
AdaptStationary *adapt = NEW AdaptStationary("couple->adapt",
AdaptStationary *adapt = new AdaptStationary("couple->adapt",
&coupledIteration,
adaptInfo);
\end{lstlisting}
......
......@@ -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> >
{
public:
MEMORY_MANAGED(G);
double operator()(const WorldVector<double>& x) const
{
return exp(-10.0 * (x * x));
......@@ -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+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:
\begin{lstlisting}{}
class F : public AbstractFunction<double, WorldVector<double> >
{
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);
double r2 = (x * x);
double ux = exp(-10.0 * r2);
......@@ -136,10 +126,10 @@ The next steps are the creation of the adaptation loop and the corresponding \ve
\begin{lstlisting}{}
// === create adapt info ===
AdaptInfo *adaptInfo = NEW AdaptInfo("ellipt->adapt", 1);
AdaptInfo *adaptInfo = new AdaptInfo("ellipt->adapt", 1);
// === create adapt ===
AdaptStationary *adapt = NEW AdaptStationary("ellipt->adapt", &ellipt,
AdaptStationary *adapt = new AdaptStationary("ellipt->adapt", &ellipt,
adaptInfo);
\end{lstlisting}
......@@ -150,7 +140,7 @@ Now, we define boundary conditions:
\begin{lstlisting}{}
// ===== add boundary conditions =====
ellipt.addDirichletBC(1, NEW G);
ellipt.addDirichletBC(1, new G);
\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.
......@@ -160,13 +150,13 @@ The operators now are defined as follows:
\begin{lstlisting}{}
// ===== create matrix operator =====
Operator matrixOperator(Operator::MATRIX_OPERATOR, ellipt.getFESpace());
matrixOperator.addSecondOrderTerm(NEW Laplace_SOT);
matrixOperator.addSecondOrderTerm(new Laplace_SOT);
ellipt.addMatrixOperator(&matrixOperator);
// ===== create rhs operator =====
int degree = ellipt.getFESpace()->getBasisFcts()->getDegree();
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);
\end{lstlisting}
......
......@@ -58,8 +58,6 @@ class G : public AbstractFunction<double, WorldVector<double> >,
public TimedObject
{
public:
MEMORY_MANAGED(G);
double operator()(const WorldVector<double>& x) const
{
return sin(M_PI * (*timePtr)) * exp(-10.0 *(x * x));
......@@ -87,8 +85,6 @@ The first lines of class \verb+Heat+ are:
class Heat : public ProblemInstatScal
{
public:
MEMORY_MANAGED(Heat);
Heat(ProblemScal *heatSpace)
: ProblemInstatScal("heat", heatSpace)
{
......@@ -96,7 +92,7 @@ public:
GET_PARAMETER(0, name + "->theta", "%f", &theta);
TEST_EXIT(theta >= 0)("theta not set!\n");
theta1 = theta - 1;
};
}
\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.
......@@ -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.
\begin{lstlisting}{}
void setTime(AdaptInfo *adaptInfo) {
void setTime(AdaptInfo *adaptInfo)
{
rhsTime =
adaptInfo->getTime()-
(1-theta)*adaptInfo->getTimestep();
boundaryTime = adaptInfo->getTime();
tau1 = 1.0 / adaptInfo->getTimestep();
};
}
void closeTimestep(AdaptInfo *adaptInfo) {
void closeTimestep(AdaptInfo *adaptInfo)
{
ProblemInstatScal::closeTimestep(adaptInfo);
WAIT;
};
}
\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.
......@@ -128,7 +126,7 @@ Now, the implementation of the \verb+ProblemStatBase+ interface begins. As menti
void solve(AdaptInfo *adaptInfo)
{
problemStat->getSolution()->interpol(exactSolution);
};
}
void estimate(AdaptInfo *adaptInfo)
{
......@@ -138,7 +136,7 @@ Now, the implementation of the \verb+ProblemStatBase+ interface begins. As menti
0, &errMax, false);
adaptInfo->setEstSum(errSum, 0);
adaptInfo->setEstMax(errMax, 0);
};
}
\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:
......@@ -181,7 +179,7 @@ int main(int argc, char** argv)
Parameters::init(false, argv[1]);
// ===== create and init stationary problem =====
ProblemScal *heatSpace = NEW ProblemScal("heat->space");
ProblemScal *heatSpace = new ProblemScal("heat->space");
heatSpace->initialize(INIT_ALL);
// ===== create instationary problem =====
......@@ -195,13 +193,13 @@ The next step is the creation of the needed \verb+AdaptInfo+ objects and of the
\begin{lstlisting}{}
// create adapt info for heat
AdaptInfo *adaptInfo = NEW AdaptInfo("heat->adapt");
AdaptInfo *adaptInfo = new AdaptInfo("heat->adapt");
// create initial adapt info
AdaptInfo *adaptInfoInitial = NEW AdaptInfo("heat->initial->adapt");
AdaptInfo *adaptInfoInitial = new AdaptInfo("heat->initial->adapt");
// create instationary adapt
AdaptInstationary *adaptInstat = NEW AdaptInstationary("heat->adapt",
AdaptInstationary *adaptInstat = new AdaptInstationary("heat->adapt",
heatSpace,
adaptInfo,
heat,
......@@ -214,7 +212,7 @@ The definitions of functions $f$ and $g$ are:
\begin{lstlisting}{}
// ===== create boundary functions =====
G *boundaryFct = NEW G;
G *boundaryFct = new G;
boundaryFct->setTimePtr(heat->getBoundaryTimePtr());
heat->setExactSolution(boundaryFct);
......@@ -222,7 +220,7 @@ The definitions of functions $f$ and $g$ are:
// ===== create rhs functions =====
int degree = heatSpace->getFESpace()->getBasisFcts()->getDegree();
F *rhsFct = NEW F(degree);
F *rhsFct = new F(degree);
rhsFct->setTimePtr(heat->getRHSTimePtr());
\end{lstlisting}
......@@ -236,7 +234,7 @@ Now, we define the operators:
double zero = 0.0;
// create laplace
Operator *A = NEW Operator(Operator::MATRIX_OPERATOR |
Operator *A = new Operator(Operator::MATRIX_OPERATOR |
Operator::VECTOR_OPERATOR,
heatSpace->getFESpace());
......@@ -255,11 +253,11 @@ Operator \verb+A+ represents $-\Delta u$. It is used as matrix operator on the l
\begin{lstlisting}{}
// create zero order operator
Operator *C = NEW Operator(Operator::MATRIX_OPERATOR |
Operator *C = new Operator(Operator::MATRIX_OPERATOR |
Operator::VECTOR_OPERATOR,
heatSpace->getFESpace());
C->addZeroOrderTerm(NEW Simple_ZOT);
C->addZeroOrderTerm(new Simple_ZOT);
C->setUhOld(heat->getOldSolution());
......@@ -273,10 +271,10 @@ Finally, the operator for the right hand side function $f$ is added and the adap
\begin{lstlisting}{}
// create RHS operator
Operator *F = NEW Operator(Operator::VECTOR_OPERATOR,
Operator *F = new Operator(Operator::VECTOR_OPERATOR,
heatSpace->getFESpace());
F->addZeroOrderTerm(NEW CoordsAtQP_ZOT(rhsFct));
F->addZeroOrderTerm(new CoordsAtQP_ZOT(rhsFct));
heatSpace->addVectorOperator(F);
......
......@@ -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> >
{
public:
MEMORY_MANAGED(N);
double operator()(const WorldVector<double>& x) const
{
return 1.0;
......@@ -43,8 +41,8 @@ In the main program we add the boundary conditions to our problem \verb+neumann+
int main(int argc, char* argv[])
{
...
neumann.addNeumannBC(1, NEW N);
neumann.addDirichletBC(2, NEW G);
neumann.addNeumannBC(1, new N);
neumann.addDirichletBC(2, new G);
...
}
\end{lstlisting}
......
......@@ -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> >
{
public:
MEMORY_MANAGED(Zero);
double operator()(const WorldVector<double>& x) const {
double operator()(const WorldVector<double>& x) const
{
return 0.0;
}
};
......@@ -81,19 +80,14 @@ public:
class F : public AbstractFunction<double, WorldVector<double> >
{
public:
MEMORY_MANAGED(F);
/** \brief
* Constructor
*/
/// Constructor
F(int degree)
: AbstractFunction<double, WorldVector<double> >(degree)
{};
{}
/** \brief
* Implementation of AbstractFunction::operator().
*/
double operator()(const WorldVector<double>& x) const {
/// Implementation of AbstractFunction::operator().
double operator()(const WorldVector<double>& x) const
{
int dow = x.getSize();
double r2 = x * x;
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
class X3 : public AbstractFunction<double, double>
{
public:
MEMORY_MANAGED(X3);
X3() : AbstractFunction<double, double>(3) {}
X3() : AbstractFunction<double, double>(3) {};
/** \brief
* Implementation of AbstractFunction::operator().
*/
double operator()(const double& x) const {
/// Implementation of AbstractFunction::operator().
double operator()(const double& x) const
{
return x * x * x;
}
};
......@@ -158,7 +149,7 @@ public:
&newtonMaxIter);
solution = problemNonlin->getSolution();
correction = newtonStep->getCorrection();
};
}
\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.
......@@ -178,13 +169,13 @@ The following methods define one iteration in the adaptation loop.
{
Flag flag = 0, markFlag = 0;
if(toDo.isSet(MARK)) markFlag = problemNonlin->markElements(adaptInfo);
if(toDo.isSet(ADAPT) && markFlag.isSet(MESH_REFINED))
if (toDo.isSet(MARK)) markFlag = problemNonlin->markElements(adaptInfo);
if (toDo.isSet(ADAPT) && markFlag.isSet(MESH_REFINED))
flag = problemNonlin->refineMesh(adaptInfo);
if(toDo.isSet(ADAPT) && markFlag.isSet(MESH_COARSENED))
if (toDo.isSet(ADAPT) && markFlag.isSet(MESH_COARSENED))
flag |= problemNonlin->coarsenMesh(adaptInfo);
if(toDo.isSet(SOLVE)) {
if (toDo.isSet(SOLVE)) {
newtonStep->initNewtonStep(adaptInfo);
int newtonIteration = 0;
double res = 0.0;
......@@ -196,14 +187,14 @@ The following methods define one iteration in the adaptation loop.
*solution -= *correction;
MSG("newton iteration %d: residual %f (tol: %f)\n",
newtonIteration, res, newtonTolerance);
} while((res > newtonTolerance) && (newtonIteration < newtonMaxIter));
} while ((res > newtonTolerance) && (newtonIteration < newtonMaxIter));
newtonStep->exitNewtonStep(adaptInfo);
}
if(toDo.isSet(ESTIMATE)) problemNonlin->estimate(adaptInfo);
if (toDo.isSet(ESTIMATE)) problemNonlin->estimate(adaptInfo);
return flag;
};
}
void endIteration(AdaptInfo *adaptInfo)
{
......@@ -224,10 +215,10 @@ Finally, the methods \verb+getNumProblems+ and \verb+getProblem+ are implemented
ProblemStatBase *getProblem(int number = 0)
{
FUNCNAME("NewtonMethod::getProblem()");
if(number == 0) return problemNonlin;
if (number == 0) return problemNonlin;
ERROR_EXIT("invalid problem number\n");
return NULL;
};
}
private:
ProblemScal *problemNonlin;
......@@ -248,7 +239,7 @@ class Nonlin : public ProblemScal,
public:
Nonlin(const char *name)
: ProblemScal(name)
{};
{}
\end{lstlisting}
In the constructor, the base class constructor of \verb+ProblemScal+ is called and the name is given to it.
......@@ -261,16 +252,16 @@ In the initialization, the base class intialization is called, the correction ve
Flag adoptFlag = INIT_NOTHING)
{
ProblemScal::initialize(initFlag, adoptProblem, adoptFlag);
correction = NEW DOFVector<double>(this->getFESpace(), "old solution");
correction = new DOFVector<double>(this->getFESpace(), "old solution");
correction->set(0.0);
dirichletZero = NEW DirichletBC(1, &zero, feSpace_);
dirichletG = NEW DirichletBC(1, &g, feSpace_);
dirichletZero = new DirichletBC(1, &zero, feSpace_);
dirichletG = new DirichletBC(1, &g, feSpace_);
solution_->getBoundaryManager()->addBoundaryCondition(dirichletG);
systemMatrix_->getBoundaryManager()->
solution->getBoundaryManager()->addBoundaryCondition(dirichletG);
systemMatrix->getBoundaryManager()->
addBoundaryCondition(dirichletZero);
rhs_->getBoundaryManager()->addBoundaryCondition(dirichletZero);
rhs->getBoundaryManager()->addBoundaryCondition(dirichletZero);
correction->getBoundaryManager()->addBoundaryCondition(dirichletZero);
};
\end{lstlisting}
......@@ -282,54 +273,60 @@ In the destructor, the allocated memory is freed.
\begin{lstlisting}{}
~Nonlin()
{
DELETE correction;
DELETE dirichletZero;
DELETE dirichletG;
};
delete correction;
delete dirichletZero;
delete dirichletG;
}
\end{lstlisting}
Now, we implement the Newton step functionality. First, in \verb+initNewtonStep+, we fill the solution vector with boundary values. This will not be done automatically because we let the \verb+solution_+ pointer point to \verb+correction+. The address of \verb+solution_+ is stored in \verb+tmp+. After the Newton method is finished, the \verb+solution_+ pointer is reset to its original value in \verb+exitNewtonStep+.
\begin{lstlisting}{}
void initNewtonStep(AdaptInfo *adaptInfo) {
solution_->getBoundaryManager()->initVector(solution_);
void initNewtonStep(AdaptInfo *adaptInfo)
{
solution->getBoundaryManager()->initVector(solution);
TraverseStack stack;
ElInfo *elInfo = stack.traverseFirst(mesh_, -1,
Mesh::CALL_LEAF_EL |
Mesh::FILL_COORDS |
Mesh::FILL_BOUND);
while(elInfo) {
solution_->getBoundaryManager()->fillBoundaryConditions(elInfo,
solution_);
while (elInfo) {
solution->getBoundaryManager()->fillBoundaryConditions(elInfo, solution);
elInfo = stack.traverseNext(elInfo);
}
solution_->getBoundaryManager()->exitVector(solution_);
solution->getBoundaryManager()->exitVector(solution);
tmp = solution_;
solution_ = correction;
};
tmp = solution;
solution = correction;
}
void exitNewtonStep(AdaptInfo *adaptInfo) {
solution_ = tmp;
};
void exitNewtonStep(AdaptInfo *adaptInfo)
{
solution = tmp;
}
\end{lstlisting}
The implementation of \verb+assembleNewtonStep+ and \verb+solveNewtonStep+ just delegates the calls to the base class implementations in \verb+ProblemScal+.
\begin{lstlisting}{}
void assembleNewtonStep(AdaptInfo *adaptInfo, Flag flag) {
void assembleNewtonStep(AdaptInfo *adaptInfo, Flag flag)
{
ProblemScal::buildAfterCoarsen(adaptInfo, flag);
};
}
void solveNewtonStep(AdaptInfo *adaptInfo) {
void solveNewtonStep(AdaptInfo *adaptInfo)
{
ProblemScal::solve(adaptInfo);
};
}
\end{lstlisting}
Finally, the \verb+getCorrection+ method is implemented and private class members are defined.
\begin{lstlisting}{}
DOFVector<double> *getCorrection() { return correction; };
DOFVector<double> *getCorrection()
{
return correction;
}
private:
DOFVector<double> *correction;
......@@ -355,11 +352,11 @@ int main(int argc, char* argv[])
Nonlin nonlin("nonlin");
nonlin.initialize(INIT_ALL);
AdaptInfo *adaptInfo = NEW AdaptInfo("nonlin->adapt", 1);
AdaptInfo *adaptInfo = new AdaptInfo("nonlin->adapt", 1);
NewtonMethod newtonMethod("nonlin->newton", &nonlin, &nonlin);
AdaptStationary *adapt = NEW AdaptStationary("nonlin->adapt",
AdaptStationary *adapt = new AdaptStationary("nonlin->adapt",
&newtonMethod,
adaptInfo);
\end{lstlisting}
......@@ -381,32 +378,32 @@ We have to add operators representing the Newton step equation $-\Delta d + 4u_n
double zero = 0.0;
double minusOne = -1.0;
Operator *nonlinOperator0 = NEW Operator(Operator::MATRIX_OPERATOR |
Operator *nonlinOperator0 = new Operator(Operator::MATRIX_OPERATOR |
Operator::VECTOR_OPERATOR,
nonlin.getFESpace());
nonlinOperator0->setUhOld(nonlin.getSolution());
nonlinOperator0->addZeroOrderTerm(NEW VecAtQP_ZOT(nonlin.getSolution(),
NEW X3));
nonlinOperator0->addZeroOrderTerm(new VecAtQP_ZOT(nonlin.getSolution(),
new X3));
nonlin.addMatrixOperator(nonlinOperator0, &four, &one);
nonlin.addVectorOperator(nonlinOperator0, &one, &zero);
Operator *nonlinOperator2 = NEW Operator(Operator::MATRIX_OPERATOR |
Operator *nonlinOperator2 = new Operator(Operator::MATRIX_OPERATOR |
Operator::VECTOR_OPERATOR,
nonlin.getFESpace());
nonlinOperator2->setUhOld(nonlin.getSolution());
nonlinOperator2->addSecondOrderTerm(NEW Laplace_SOT);
nonlinOperator2->addSecondOrderTerm(new Laplace_SOT);
nonlin.addMatrixOperator(nonlinOperator2, &one, &one);
nonlin.addVectorOperator(nonlinOperator2, &one, &zero);
int degree = nonlin.getFESpace()->getBasisFcts()->getDegree();
Operator* rhsFunctionOperator = NEW Operator(Operator::VECTOR_OPERATOR,
Operator* rhsFunctionOperator = new Operator(Operator::VECTOR_OPERATOR,
nonlin.getFESpace());
rhsFunctionOperator->addZeroOrderTerm(NEW CoordsAtQP_ZOT(NEW F(degree)));
rhsFunctionOperator->addZeroOrderTerm(new CoordsAtQP_ZOT(new F(degree)));
nonlin.addVectorOperator(rhsFunctionOperator, &minusOne, &one);
\end{lstlisting}
......
......@@ -99,18 +99,14 @@ class G : public AbstractFunction<double, WorldVector<double> >,
public TimedObject
{
public:
MEMORY_MANAGED(G);
/** \brief
* Implementation of AbstractFunction::operator().
*/
/// Implementation of AbstractFunction::operator().
double operator()(const WorldVector<double>& argX) const
{
WorldVector<double> x = argX;
int dim = x.getSize();
for (int i = 0; i < dim; i++) {
for (int i = 0; i < dim; i++)
x[i] -= *timePtr;
}
return sin(M_PI * (*timePtr)) * exp(-10.0 * (x * x));
}
};
......@@ -119,19 +115,15 @@ class F : public AbstractFunction<double, WorldVector<double> >,
public TimedObject
{
public:
MEMORY_MANAGED(F);
F(int degree) : AbstractFunction<double, WorldVector<double> >(degree) {}
F(int degree) : AbstractFunction<double, WorldVector<double> >(degree) {};
/** \brief
* Implementation of AbstractFunction::operator().
*/
double operator()(const WorldVector<double>& argX) const {
/// Implementation of AbstractFunction::operator().
double operator()(const WorldVector<double>& argX) const
{
WorldVector<double> x = argX;
int dim = x.getSize();
for (int i = 0; i < dim; i++) {
for (int i = 0; i < dim; i++)
x[i] -= *timePtr;
}
double r2 = (x * x);
double ux = sin(M_PI * (*timePtr)) * exp(-10.0 * r2);
......@@ -155,7 +147,7 @@ int main(int argc, char** argv)
vectors);
AdaptInstationary *adaptInstat =
NEW AdaptInstationary("heat->adapt",
new AdaptInstationary("heat->adapt",
&parallelheat,
adaptInfo,
&parallelheat,
......
......@@ -65,20 +65,22 @@ The right hand side function $f$ has to follow the rotation of the torus.
class F : public AbstractFunction<double, WorldVector<double> >
{
public:
MEMORY_MANAGED(F);
F(int degree)
: AbstractFunction<double, WorldVector<double> >(degree),
rotation(0.0)
{};
double operator()(const WorldVector<double>& x) const {
double operator()(const WorldVector<double>& x) const
{
WorldVector<double> myX = x;
YRotation::rotate(myX, -rotation);
return = -2.0 * myX[0];
}
void rotate(double r) { rotation += r; };
void rotate(double r)
{
rotation += r;
}
private:
double rotation;
......@@ -102,10 +104,10 @@ public:
radius2_(radius2)
{};
virtual ~TorusProject() {};
void project(WorldVector<double> &x) {
virtual ~TorusProject() {}
void project(WorldVector<double> &x)
{
WorldVector<double> xPlane = x;
xPlane[2] = 0.0;
......@@ -147,10 +149,7 @@ int main(int argc, char* argv[])
double r2 = (1.5 - 1.0/std::sqrt(2.0)) / 2.0;
double r1 = 1.0/std::sqrt(2.0) + r2;
NEW TorusProject(1,
VOLUME_PROJECTION,
r1,
r2);
new TorusProject(1, VOLUME_PROJECTION, r1, r2);
...
......@@ -165,7 +164,6 @@ Before we let the torus rotate, some variables are defined. We set the rotation
\begin{lstlisting}{}
double rotation = M_PI/3.0;
int i, j;
int dim = torus.getMesh()->getDim();
int dow = Global::getGeo(WORLD);
......@@ -175,14 +173,12 @@ Before we let the torus rotate, some variables are defined. We set the rotation
const FiniteElemSpace *feSpace = torus.getFESpace();
const BasisFunction *basFcts = feSpace->getBasisFcts();
int numBasFcts = basFcts->getNumber();
DegreeOfFreedom *localIndices = GET_MEMORY(DegreeOfFreedom, numBasFcts);
DegreeOfFreedom *localIndices = new double[numBasFcts];
DOFAdmin *admin = feSpace->getAdmin();
WorldVector<DOFVector<double>*> parametricCoords;
for(i = 0; i < dow; i++) {
parametricCoords[i] = NEW DOFVector<double>(feSpace,
"parametric coords");
}
for (int i = 0; i < dow; i++)
parametricCoords[i] = new DOFVector<double>(feSpace, "parametric coords");
\end{lstlisting}
In the next step, we store the rotated vertex coordinates of the mesh in \verb+parametricCoords+,a vector of DOF vectors, where the first vector stores the first component of each vertex coordinate, and so on. In the STL map \verb+visited+, we store which vertices have already been visited, to avoid multiple rotations of the same point.
......@@ -193,16 +189,16 @@ In the next step, we store the rotated vertex coordinates of the mesh in \verb+p
ElInfo *elInfo = stack.traverseFirst(torus.getMesh(), -1,
Mesh::CALL_LEAF_EL |
Mesh::FILL_COORDS);
while(elInfo) {
while (elInfo) {
basFcts->getLocalIndices(elInfo->getElement(), admin, localIndices);
for(i = 0; i < dim + 1; i++) {
for (int i = 0; i < dim + 1; i++) {
dof = localIndices[i];
x = elInfo->getCoord(i);
YRotation::rotate(x, rotation);
if(!visited[dof]) {
for(j = 0; j < dow; j++) {
if (!visited[dof]) {
for (int j = 0; j < dow; j++)
(*(parametricCoords[j]))[dof] = x[j];
}
visited[dof] = true;
}
}
......@@ -224,10 +220,10 @@ We rotate the right hand side function, reset \verb+adaptInfo+ and start the ada
adaptInfo->reset();
adapt->adapt();
DataCollector *dc = NEW DataCollector(feSpace, torus.getSolution());
DataCollector *dc = new DataCollector(feSpace, torus.getSolution());
MacroWriter::writeMacro(dc, "output/rotation1.mesh");
ValueWriter::writeValues(dc, "output/rotation1.dat");
DELETE dc;
delete dc;
\end{lstlisting}
We perform another rotation. All we have to do is to modify the coordinates in \verb+parametricCoords+ and to inform $f$ about the rotation.
......@@ -236,16 +232,16 @@ We perform another rotation. All we have to do is to modify the coordinates in \
visited.clear();
elInfo = stack.traverseFirst(torus.getMesh(), -1,
Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS);
while(elInfo) {
while (elInfo) {
basFcts->getLocalIndices(elInfo->getElement(), admin, localIndices);
for(i = 0; i < dim + 1; i++) {
for (int i = 0; i < dim + 1; i++) {
dof = localIndices[i];
x = elInfo->getCoord(i);
YRotation::rotate(x, rotation);
if(!visited[dof]) {
for(j = 0; j < dow; j++) {
if (!visited[dof]) {
for (int j = 0; j < dow; j++)
(*(parametricCoords[j]))[dof] = x[j];
}
visited[dof] = true;
}
}
......@@ -256,10 +252,10 @@ We perform another rotation. All we have to do is to modify the coordinates in \
adaptInfo->reset();
adapt->adapt();
dc = NEW DataCollector(feSpace, torus.getSolution());
dc = new DataCollector(feSpace, torus.getSolution());
MacroWriter::writeMacro(dc, "output/rotation1.mesh");
ValueWriter::writeValues(dc, "output/rotation1.dat");
DELETE dc;
delete dc;
\end{lstlisting}
The solution is written to \verb+rotation2.mesh+ and \verb+rotation2.dat+.
......@@ -267,9 +263,9 @@ The solution is written to \verb+rotation2.mesh+ and \verb+rotation2.dat+.
Finally, we free some memory and finish the main program.
\begin{lstlisting}{}
for(i = 0; i < dow; i++)
DELETE parametricCoords[i];
FREE_MEMORY(localIndices, DegreeOfFreedom, numBasFcts);
for (int i = 0; i < dow; i++)
delete parametricCoords[i];
delete [] localIndices;
}
\end{lstlisting}
......
......@@ -74,15 +74,16 @@ public:
: Projection(id, type),
center_(center),
radius_(radius)
{};
{}
void project(WorldVector<double> &x) {
void project(WorldVector<double> &x)
{
x -= center_;
double norm = sqrt(x*x);
TEST_EXIT(norm != 0.0)("can't project vector x\n");
x *= radius_/norm;
x += center_;
};
}
protected:
WorldVector<double> center_;
......@@ -98,9 +99,7 @@ If we compute on the surface, we redefine the function $f$.
class F : public AbstractFunction<double, WorldVector<double> >
{
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
{
......@@ -115,7 +114,7 @@ In the main program, we create an instance of \verb+BallProject+ with ID $1$, ce
// ===== create projection =====
WorldVector<double> ballCenter;
ballCenter.set(0.0);
NEW BallProject(1,
new BallProject(1,
BOUNDARY_PROJECTION,
ballCenter,
1.0);
......@@ -127,7 +126,7 @@ If we solve on the two dimensional surface of the sphere, the projection type is
// ===== create projection =====
WorldVector<double> ballCenter;
ballCenter.set(0.0);
NEW BallProject(1,
new BallProject(1,
VOLUME_PROJECTION,
ballCenter,
1.0);
......
No preview for this file type
......@@ -44,11 +44,11 @@ The \verb+AdaptInfo+ constructor is called with the number of problem components
\begin{lstlisting}{}
// === create adapt info ===
AdaptInfo *adaptInfo = NEW AdaptInfo("vecellipt->adapt",
AdaptInfo *adaptInfo = new AdaptInfo("vecellipt->adapt",
vecellipt.getNumComponents());
// === create adapt ===
AdaptStationary *adapt = NEW AdaptStationary("vecellipt->adapt",
AdaptStationary *adapt = new AdaptStationary("vecellipt->adapt",
&vecellipt,
adaptInfo);
......@@ -61,10 +61,12 @@ The Dirichlet boundary condition for the first equation is defined by
\begin{lstlisting}{}
// ===== add boundary conditions =====
vecellipt.addDirichletBC(1, 0, NEW G);
vecellipt.addDirichletBC(1, 0, 0, new G);
\end{lstlisting}
The first argument is the condition identifier, as in the scalar case. The second argument is the component, the boundary condition belongs to.
The first argument is the condition identifier, as in the scalar
case. The second and third argument define the the component, the
boundary condition belongs to.
The operator definitions for the first equation are:
......@@ -73,7 +75,7 @@ The operator definitions for the first equation are:
Operator matrixOperator00(Operator::MATRIX_OPERATOR,
vecellipt.getFESpace(0),
vecellipt.getFESpace(0));
matrixOperator00.addSecondOrderTerm(NEW Laplace_SOT);
matrixOperator00.addSecondOrderTerm(new Laplace_SOT);
vecellipt.addMatrixOperator(&matrixOperator00, 0, 0);
Operator rhsOperator0(Operator::VECTOR_OPERATOR,
......@@ -81,7 +83,7 @@ The operator definitions for the first equation are:
int degree = vecellipt.getFESpace(0)->getBasisFcts()->getDegree();
rhsOperator0.addZeroOrderTerm(NEW CoordsAtQP_ZOT(NEW F(degree)));
rhsOperator0.addZeroOrderTerm(new CoordsAtQP_ZOT(new F(degree)));
vecellipt.addVectorOperator(&rhsOperator0, 0);
\end{lstlisting}
......@@ -100,11 +102,11 @@ Now, the operators for the second equation are defined:
vecellipt.getFESpace(1),
vecellipt.getFESpace(1));
matrixOperator10.addZeroOrderTerm(NEW Simple_ZOT);
matrixOperator10.addZeroOrderTerm(new Simple_ZOT);
vecellipt.addMatrixOperator(&matrixOperator10, 1, 0);
matrixOperator11.addZeroOrderTerm(NEW Simple_ZOT(-1.0));
matrixOperator11.addZeroOrderTerm(new Simple_ZOT(-1.0));
vecellipt.addMatrixOperator(&matrixOperator11, 1, 1);
\end{lstlisting}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment