diff --git a/AMDiS/src/Estimator.cc b/AMDiS/src/Estimator.cc index 0354e8add638dd3213b48beebd760ea4a062316b..a6c2542b36a5c4f273a4353ae3baf99dd8df5582 100755 --- a/AMDiS/src/Estimator.cc +++ b/AMDiS/src/Estimator.cc @@ -100,6 +100,7 @@ namespace AMDiS { TraverseStack stack; ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + while(elInfo) { estimateElement(elInfo); elInfo = stack.traverseNext(elInfo); diff --git a/AMDiS/src/Operator.hh b/AMDiS/src/Operator.hh new file mode 100644 index 0000000000000000000000000000000000000000..7e9c5b1143e1cda9f7b1baefcf87b86d0f0949b3 --- /dev/null +++ b/AMDiS/src/Operator.hh @@ -0,0 +1,49 @@ +namespace AMDiS { + + template <typename T> + void Operator::addSecondOrderTerm(T *term) + { + secondOrder[0].push_back(term); + term->operat = this; + + for (int i = 1; i < omp_get_max_threads(); i++) { + T *newTerm = NEW T(static_cast<const T>(*term)); + secondOrder[i].push_back(newTerm); + } + } + + template <typename T> + void Operator::addFirstOrderTerm(T *term, + FirstOrderType type) + { + if (type == GRD_PSI) { + firstOrderGrdPsi[0].push_back(term); + } else { + firstOrderGrdPhi[0].push_back(term); + } + term->operat = this; + + for (int i = 1; i < omp_get_max_threads(); i++) { + T *newTerm = NEW T(static_cast<const T>(*term)); + if (type == GRD_PSI) { + firstOrderGrdPsi[i].push_back(newTerm); + } else { + firstOrderGrdPhi[i].push_back(newTerm); + } + } + } + + template <typename T> + void Operator::addZeroOrderTerm(T *term) + { + zeroOrder[0].push_back(term); + term->operat = this; + + for (int i = 1; i < omp_get_max_threads(); i++) { + T *newTerm = NEW T(static_cast<const T>(*term)); + zeroOrder[i].push_back(newTerm); + } + } + + +} diff --git a/AMDiS/src/PardisoSolver.cc b/AMDiS/src/PardisoSolver.cc index f53ef71cb8e7c5eb34a326ca1fc64ec6f7756e51..907294ef3b2d72489fe97643c5081d5cce4b94f7 100644 --- a/AMDiS/src/PardisoSolver.cc +++ b/AMDiS/src/PardisoSolver.cc @@ -125,8 +125,8 @@ namespace AMDiS { iparm[7] = 2; // Max numbers of iterative refinement steps iparm[9] = 13; // Perturb the pivot elements with 1e-13 iparm[10] = 1; // Use nonsymmetric permutation and scaling MPS - iparm[17] = -1; // Output: Number of nonzeros in the factor LU - iparm[18] = -1; // Output: Mflops for LU factorization + iparm[17] = 0; // Output: Number of nonzeros in the factor LU + iparm[18] = 0; // Output: Mflops for LU factorization // Maximum number of numerical factorizations MKL_INT maxfct = 1; @@ -135,7 +135,7 @@ namespace AMDiS { MKL_INT mnum = 1; // Print statistical information in file - MKL_INT msglvl = 1; + MKL_INT msglvl = 0; // Error flag MKL_INT error = 0; diff --git a/AMDiS/src/ResidualEstimator.cc b/AMDiS/src/ResidualEstimator.cc new file mode 100644 index 0000000000000000000000000000000000000000..202762640d663a7e1cb92a976bdc32e080145f06 --- /dev/null +++ b/AMDiS/src/ResidualEstimator.cc @@ -0,0 +1,543 @@ +#include "ResidualEstimator.h" +#include "Operator.h" +#include "DOFMatrix.h" +#include "DOFVector.h" +#include "Assembler.h" +#include "Traverse.h" +#include "Parameters.h" + +namespace AMDiS { + + ResidualEstimator::ResidualEstimator(::std::string name, int r) + : Estimator(name, r), + C0(1.0), + C1(1.0), + C2(1.0), + C3(1.0) + { + GET_PARAMETER(0, name + "->C0", "%f", &C0); + GET_PARAMETER(0, name + "->C1", "%f", &C1); + GET_PARAMETER(0, name + "->C2", "%f", &C2); + GET_PARAMETER(0, name + "->C3", "%f", &C3); + + C0 = C0 > 1.e-25 ? sqr(C0) : 0.0; + C1 = C1 > 1.e-25 ? sqr(C1) : 0.0; + C2 = C2 > 1.e-25 ? sqr(C2) : 0.0; + C3 = C3 > 1.e-25 ? sqr(C3) : 0.0; + } + + void ResidualEstimator::init(double ts) + { + FUNCNAME("ResidualEstimator::init()"); + + timestep = ts; + + mesh = uh[row == -1 ? 0 : row]->getFESpace()->getMesh(); + + numSystems = static_cast<int>(uh.size()); + TEST_EXIT_DBG(numSystems > 0)("no system set\n"); + + dim = mesh->getDim(); + basFcts = GET_MEMORY(const BasisFunction*, numSystems); + quadFast = GET_MEMORY(FastQuadrature*, numSystems); + + degree = 0; + for (int system = 0; system < numSystems; system++) { + basFcts[system] = uh[system]->getFESpace()->getBasisFcts(); + degree = ::std::max(degree, basFcts[system]->getDegree()); + } + + degree *= 2; + + quad = Quadrature::provideQuadrature(dim, degree); + numPoints = quad->getNumPoints(); + + Flag flag = INIT_PHI | INIT_GRD_PHI; + if (degree > 2) { + flag |= INIT_D2_PHI; + } + + for (int system = 0; system < numSystems; system++) { + quadFast[system] = FastQuadrature::provideFastQuadrature(basFcts[system], + *quad, + flag); + } + + uhEl = GET_MEMORY(double*, numSystems); + uhOldEl = timestep ? GET_MEMORY(double*, numSystems) : NULL; + + for (int system = 0; system < numSystems; system++) { + uhEl[system] = GET_MEMORY(double, basFcts[system]->getNumber()); + if (timestep) + uhOldEl[system] = GET_MEMORY(double, basFcts[system]->getNumber()); + } + + uhQP = timestep ? GET_MEMORY(double, numPoints) : NULL; + uhOldQP = timestep ? GET_MEMORY(double, numPoints) : NULL; + + riq = GET_MEMORY(double, numPoints); + + TraverseStack stack; + ElInfo *elInfo = NULL; + + // clear error indicators and mark elements for jumpRes + elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL); + while (elInfo) { + elInfo->getElement()->setEstimation(0.0, row); + elInfo->getElement()->setMark(1); + elInfo = stack.traverseNext(elInfo); + } + + est_sum = 0.0; + est_max = 0.0; + est_t_sum = 0.0; + est_t_max = 0.0; + + traverseFlag = + Mesh::FILL_NEIGH | + Mesh::FILL_COORDS | + Mesh::FILL_OPP_COORDS | + Mesh::FILL_BOUND | + Mesh::FILL_GRD_LAMBDA | + Mesh::FILL_DET | + Mesh::CALL_LEAF_EL; + } + + void ResidualEstimator::exit(bool output) + { + FUNCNAME("ResidualEstimator::exit()"); + + est_sum = sqrt(est_sum); + est_t_sum = sqrt(est_t_sum); + + for (int system = 0; system < numSystems; system++) { + FREE_MEMORY(uhEl[system], double, basFcts[system]->getNumber()); + if (timestep) + FREE_MEMORY(uhOldEl[system], double, basFcts[system]->getNumber()); + } + + FREE_MEMORY(uhEl, double*, numSystems); + if (timestep) + FREE_MEMORY(uhOldEl, double*, numSystems); + + if (timestep) { + FREE_MEMORY(uhQP, double, numPoints); + FREE_MEMORY(uhOldQP, double, numPoints); + } + + if (output) { + MSG("estimate = %.8e\n", est_sum); + if (C3) { + MSG("time estimate = %.8e\n", est_t_sum); + } + } + + FREE_MEMORY(riq, double, numPoints); + FREE_MEMORY(basFcts, const BasisFunction*, numSystems); + FREE_MEMORY(quadFast, FastQuadrature*, numSystems); + } + + void ResidualEstimator::estimateElement(ElInfo *elInfo) + { + FUNCNAME("ResidualEstimator::estimateElement()"); + + double est_el = 0.0; + double val = 0.0; + Element *el, *neigh; + int iq; + + TEST_EXIT_DBG(numSystems > 0)("no system set\n"); + + ::std::vector<Operator*>::iterator it; + + WorldVector<double> *grdUh_qp = NULL; + WorldMatrix<double> *D2uhqp = NULL; + + el = elInfo->getElement(); + + double det = elInfo->getDet(); + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + + est_el = el->getEstimation(row); + + double h2 = h2_from_det(det, dim); + + for (iq = 0; iq < numPoints; iq++) { + riq[iq] = 0.0; + } + + for (int system = 0; system < numSystems; system++) { + + if (matrix[system] == NULL) + continue; + + // init assemblers + ::std::vector<Operator*>::iterator it; + + for (it = const_cast<DOFMatrix*>(matrix[system])->getOperatorsBegin(); + it != const_cast<DOFMatrix*>(matrix[system])->getOperatorsEnd(); + ++it) { + (*it)->getAssembler(omp_get_thread_num())->initElement(elInfo, quad); + } + + for (it = const_cast<DOFVector<double>*>(fh[system])->getOperatorsBegin(); + it != const_cast<DOFVector<double>*>(fh[system])->getOperatorsEnd(); + ++it) { + (*it)->getAssembler(omp_get_thread_num())->initElement(elInfo, quad); + } + + if (timestep) { + TEST_EXIT_DBG(uhOld[system])("no uhOld\n"); + uhOld[system]->getLocalVector(el, uhOldEl[system]); + + // ===== time and element residuals + if (C0 || C3) { + uh[system]->getVecAtQPs(elInfo, NULL, quadFast[system], uhQP); + uhOld[system]->getVecAtQPs(elInfo, NULL, quadFast[system], uhOldQP); + + if (C3 && uhOldQP && system == ::std::max(row, 0)) { + for (val = iq = 0; iq < numPoints; iq++) { + double tiq = (uhQP[iq] - uhOldQP[iq]); + val += quad->getWeight(iq) * tiq * tiq; + } + double v = C3 * det * val; + est_t_sum += v; + est_t_max = max(est_t_max, v); + } + } + } + + + if (C0) { + for (it = const_cast<DOFMatrix*>(matrix[system])->getOperatorsBegin(); + it != const_cast<DOFMatrix*>(matrix[system])->getOperatorsEnd(); + ++it) { + if ((*it)->zeroOrderTerms() && !uhQP) { + uhQP = GET_MEMORY(double, numPoints); + uh[system]->getVecAtQPs(elInfo, NULL, quadFast[system], uhQP); + } + if ((*it)->firstOrderTermsGrdPsi() || (*it)->firstOrderTermsGrdPhi() + && !grdUh_qp) { + grdUh_qp = new WorldVector<double>[numPoints]; + uh[system]->getGrdAtQPs(elInfo, NULL, quadFast[system], grdUh_qp); + } + if ((*it)->secondOrderTerms() && !D2uhqp) { + if (degree > 2) { + D2uhqp = new WorldMatrix<double>[numPoints]; + uh[system]->getD2AtQPs(elInfo, NULL, quadFast[system], D2uhqp); + } + } + } + + r(elInfo, + numPoints, + uhQP, + grdUh_qp, + D2uhqp, + uhOldQP, + NULL, // grdUhOldQP + NULL, // D2UhOldQP + matrix[system], + fh[system], + quad, + riq); + } + } + + // add integral over r square + for (val = iq = 0; iq < numPoints; iq++) { + val += quad->getWeight(iq) * riq[iq] * riq[iq]; + } + + if (timestep != 0.0 || norm == NO_NORM || norm == L2_NORM) + val = C0 * h2 * h2 * det * val; + else + val = C0 * h2 * det * val; + + est_el += val; + + // ===== jump residuals + if (C1 && (dim > 1)) { + int neighbours = Global::getGeo(NEIGH, dim); + int face; + Quadrature *surfaceQuad = Quadrature::provideQuadrature(dim - 1, degree); + int numPointsSurface = surfaceQuad->getNumPoints(); + Vector<WorldVector<double> > jump(numPointsSurface); + + + for (face = 0; face < neighbours; face++) { + neigh = const_cast<Element*>(elInfo->getNeighbour(face)); + if (neigh && neigh->getMark()) { + ElInfo *neighInfo = mesh->createNewElInfo(); + WorldVector<int> faceIndEl, faceIndNeigh; + int oppV = elInfo->getOppVertex(face); + DimVec<WorldVector<double> > LambdaNeigh(dim, NO_INIT); + double detNeigh; + DimVec<double> lambda(dim, NO_INIT); + + el->sortFaceIndices(face, &faceIndEl); + neigh->sortFaceIndices(oppV, &faceIndNeigh); + + neighInfo->setElement(const_cast<Element*>(neigh)); + neighInfo->setFillFlag(Mesh::FILL_COORDS); + + int dow = Global::getGeo(WORLD); + + int j, i1, i2; + + for (int i = 0; i < dow; i++) + neighInfo->getCoord(oppV)[i] = elInfo->getOppCoord(face)[i]; + + // periodic leaf data ? + ElementData *ldp = el->getElementData()->getElementData(PERIODIC); + + bool periodicCoords = false; + + if (ldp) { + ::std::list<LeafDataPeriodic::PeriodicInfo>::iterator it; + + for (it = dynamic_cast<LeafDataPeriodic*>(ldp)->getInfoList().begin(); + it != dynamic_cast<LeafDataPeriodic*>(ldp)->getInfoList().end(); + ++it) { + if (it->elementSide == face) { + for (int i = 0; i < dim; i++) { + i1 = faceIndEl[i]; + i2 = faceIndNeigh[i]; + + for (j = 0; j < dim; j++) { + if (i1 == el->getVertexOfPosition(INDEX_OF_DIM(dim - 1, + dim), + face, + j)) { + break; + } + } + + TEST_EXIT_DBG(j != dim)("vertex i1 not on face ???\n"); + + neighInfo->getCoord(i2) = (*(it->periodicCoords))[j]; + } + periodicCoords = true; + break; + } + } + } + + if (!periodicCoords) { + for (int i = 0; i < dim; i++) { + i1 = faceIndEl[i]; + i2 = faceIndNeigh[i]; + for (j = 0; j < dow; j++) + neighInfo->getCoord(i2)[j] = elInfo->getCoord(i1)[j]; + } + } + + Parametric *parametric = mesh->getParametric(); + if (parametric) { + neighInfo = parametric->addParametricInfo(neighInfo); + } + + detNeigh = abs(neighInfo->calcGrdLambda(LambdaNeigh)); + + Vector<WorldVector<double> > grdUhEl(numPointsSurface); + Vector<WorldVector<double> > grdUhNeigh(numPointsSurface); + + for (iq = 0; iq < numPointsSurface; iq++) { + jump[iq].set(0.0); + } + + + for (int system = 0; system < numSystems; system++) { + if (matrix[system] == NULL) + continue; + + uh[system]->getLocalVector(el, uhEl[system]); + + double* uhNeigh; + uhNeigh = new double[basFcts[system]->getNumber()]; + uh[system]->getLocalVector(neigh, uhNeigh); + + + for (iq = 0; iq < numPointsSurface; iq++) { + lambda[face] = 0.0; + for (int i = 0; i < dim; i++) { + lambda[faceIndEl[i]] = surfaceQuad->getLambda(iq, i); + } + + basFcts[system]->evalGrdUh(lambda, + Lambda, + uhEl[system], + &grdUhEl[iq]); + + lambda[oppV] = 0.0; + for (int i = 0; i < dim; i++) { + lambda[faceIndNeigh[i]] = surfaceQuad->getLambda(iq, i); + } + + basFcts[system]->evalGrdUh(lambda, + LambdaNeigh, + uhNeigh, + &grdUhNeigh[iq]); + + grdUhEl[iq] -= grdUhNeigh[iq]; + } + + delete [] uhNeigh; + + ::std::vector<double*>::iterator fac; + + for (it = const_cast<DOFMatrix*>(matrix[system])->getOperatorsBegin(), + fac = const_cast<DOFMatrix*>(matrix[system])->getOperatorEstFactorBegin(); + it != const_cast<DOFMatrix*>(matrix[system])->getOperatorsEnd(); + ++it, ++fac) { + Vector<WorldVector<double> > localJump(numPointsSurface); + for (iq = 0; iq < numPointsSurface; iq++) { + localJump[iq].set(0.0); + } + + (*it)->weakEvalSecondOrder(numPointsSurface, + grdUhEl.getValArray(), + localJump.getValArray()); + double factor = *fac ? **fac : 1.0; + if (factor != 1.0) { + for (int i = 0; i < numPointsSurface; i++) { + localJump[i] *= factor; + } + } + + for (int i = 0; i < numPointsSurface; i++) { + jump[i] += localJump[i]; + } + } + } + + + for (val = iq = 0; iq < numPointsSurface; iq++) { + val += surfaceQuad->getWeight(iq) * (jump[iq] * jump[iq]); + } + + double d = 0.5 * (det + detNeigh); + + if (norm == NO_NORM || norm == L2_NORM) + val *= C1 * h2_from_det(d, dim) * d; + else + val *= C1 * d; + + if (parametric) { + neighInfo = parametric->removeParametricInfo(neighInfo); + } + + DELETE neighInfo; + + neigh->setEstimation(neigh->getEstimation(row) + val, row); + + est_el += val; + + } + } + + val = fh[::std::max(row, 0)]-> + getBoundaryManager()-> + boundResidual(elInfo, matrix[::std::max(row, 0)], uh[::std::max(row, 0)]); + if (norm == NO_NORM || norm == L2_NORM) + val *= C1 * h2; + else + val *= C1; + + est_el += val; + } + + + el->setEstimation(est_el, row); + + est_sum += est_el; + est_max = max(est_max, est_el); + + elInfo->getElement()->setMark(0); + } + + void r(const ElInfo *elInfo, + int numPoints, + const double *uhIq, + const WorldVector<double> *grdUhIq, + const WorldMatrix<double> *D2UhIq, + const double *uhOldIq, + const WorldVector<double> *grdUhOldIq, + const WorldMatrix<double> *D2UhOldIq, + DOFMatrix *A, + DOFVector<double> *fh, + Quadrature *quad, + double *result) + { + ::std::vector<Operator*>::iterator it; + ::std::vector<double*>::iterator fac; + double factor; + + // lhs + for (it = const_cast<DOFMatrix*>(A)->getOperatorsBegin(), + fac = const_cast<DOFMatrix*>(A)->getOperatorEstFactorBegin(); + it != const_cast<DOFMatrix*>(A)->getOperatorsEnd(); + ++it, ++fac) { + + factor = *fac ? **fac : 1.0; + if (factor) { + if (D2UhIq) { + (*it)->evalSecondOrder(numPoints, uhIq, grdUhIq, D2UhIq, result, -factor); + } + + if (grdUhIq) { + (*it)->evalFirstOrderGrdPsi(numPoints, uhIq, grdUhIq, D2UhIq, result, factor); + (*it)->evalFirstOrderGrdPhi(numPoints, uhIq, grdUhIq, D2UhIq, result, factor); + } + + if (uhIq) { + (*it)->evalZeroOrder(numPoints, uhIq, grdUhIq, D2UhIq, result, factor); + } + } + } + + // rhs + for (it = const_cast<DOFVector<double>*>(fh)->getOperatorsBegin(), + fac = const_cast<DOFVector<double>*>(fh)->getOperatorEstFactorBegin(); + it != const_cast<DOFVector<double>*>(fh)->getOperatorsEnd(); + ++it, ++fac) { + + factor = *fac ? **fac : 1.0; + if (factor) { + if ((*it)->getUhOld()) { + if (D2UhOldIq) { + (*it)->evalSecondOrder(numPoints, + uhOldIq, grdUhOldIq, D2UhOldIq, + result, factor); + } + if (grdUhOldIq) { + (*it)->evalFirstOrderGrdPsi(numPoints, + uhOldIq, grdUhOldIq, D2UhOldIq, + result, -factor); + (*it)->evalFirstOrderGrdPhi(numPoints, + uhOldIq, grdUhOldIq, D2UhOldIq, + result, -factor); + } + if (uhOldIq) { + (*it)->evalZeroOrder(numPoints, + uhOldIq, grdUhOldIq, D2UhOldIq, + result, -factor); + } + } else { + double *fx = GET_MEMORY(double, numPoints); + for (int iq = 0; iq < numPoints; iq++) { + fx[iq] = 0.0; + } + (*it)->getC(elInfo, numPoints, fx); + + for (int iq = 0; iq < numPoints; iq++) { + result[iq] -= factor * fx[iq]; + } + FREE_MEMORY(fx, double, numPoints); + } + } + } + } + + +} diff --git a/AMDiS/src/ResidualEstimator.h b/AMDiS/src/ResidualEstimator.h new file mode 100644 index 0000000000000000000000000000000000000000..d07db3880a593b96634719a514efa50fa75c121a --- /dev/null +++ b/AMDiS/src/ResidualEstimator.h @@ -0,0 +1,154 @@ +// ============================================================================ +// == == +// == AMDiS - Adaptive multidimensional simulations == +// == == +// ============================================================================ +// == == +// == crystal growth group == +// == == +// == Stiftung caesar == +// == Ludwig-Erhard-Allee 2 == +// == 53175 Bonn == +// == germany == +// == == +// ============================================================================ +// == == +// == http://www.caesar.de/cg/AMDiS == +// == == +// ============================================================================ + +/** \file ResidualEstimator.h */ + +/** \defgroup Estimator Estimator module + * @{ <img src="estimator.png"> @} + */ + +#ifndef AMDIS_RESIDUALESTIMATOR_H +#define AMDIS_RESIDUALESTIMATOR_H + +#include "Estimator.h" +#include "FixVec.h" + +namespace AMDiS { + + /** \brief + * Returns residual square at quadrature point. Not Member of + * Estimator to avoid multiple instantiation. + */ + void r(const ElInfo *elInfo, + int numPoints, + const double *uhIq, + const WorldVector<double> *grdUhIq, + const WorldMatrix<double> *D2UhIq, + const double *uhOldIq, + const WorldVector<double> *grdUhOldIq, + const WorldMatrix<double> *D2UhOldIq, + DOFMatrix *A, + DOFVector<double> *fh, + Quadrature *quad, + double *result); + + /** \brief + * Returns pow(det,2.0/dim). Not Member of + * Estimator to avoid multiple instantiation. + */ + inline double h2_from_det(double det, int dim) { + return pow(det, 2.0 / dim); + }; + + // ============================================================================ + // ===== class ResidualEstimator ============================================== + // ============================================================================ + + /** + * \ingroup Estimator + * + * \brief + * Estimator for scalar problems. + */ + class ResidualEstimator : public Estimator + { + public: + MEMORY_MANAGED(ResidualEstimator); + + /** \brief + * Creator class used in the OEMSolverMap. + */ + class Creator : public EstimatorCreator + { + public: + MEMORY_MANAGED(Creator); + + Creator() : EstimatorCreator() {}; + + virtual ~Creator() {}; + + /** \brief + * Returns a new ODirSolver object. + */ + Estimator* create() { + return NEW ResidualEstimator(name, row); + }; + }; + + + /** \brief + * Constructor. + */ + ResidualEstimator(::std::string name, int r); + + virtual void init(double timestep); + + virtual void estimateElement(ElInfo *elInfo); + + virtual void exit(bool output = true); + + protected: + /** \brief + * Constant in front of element residual + */ + double C0; + + /** \brief + * Constant in front of edge/face residual + */ + double C1; + + /** \brief + * Constant in front of coarsening term + */ + double C2; + + /** \brief + * Constant in front of the time + */ + double C3; + + + int numSystems; + + int numPoints; + + int dim; + + int degree; + + Quadrature *quad; + + FastQuadrature **quadFast; + + const BasisFunction **basFcts; + + double **uhEl; + + double **uhOldEl; + + double *uhQP; + + double *uhOldQP; + + double *riq; + }; +} + +#endif // AMDIS_RESIDUALESTIMATOR_H diff --git a/AMDiS/src/ResidualParallelEstimator.cc b/AMDiS/src/ResidualParallelEstimator.cc new file mode 100644 index 0000000000000000000000000000000000000000..809608916a5680cb8690468575ef680b210f62f6 --- /dev/null +++ b/AMDiS/src/ResidualParallelEstimator.cc @@ -0,0 +1,108 @@ +#include "ResidualParallelEstimator.h" +#include "ResidualEstimator.h" +#include "TraverseParallel.h" +#include "Parameters.h" +#include "OpenMP.h" + +namespace AMDiS { + ResidualParallelEstimator::ResidualParallelEstimator(::std::string name, int r) + : Estimator(name, r), + C3(1.0) + { + GET_PARAMETER(0, name + "->C3", "%f", &C3); + C3 = C3 > 1.e-25 ? sqr(C3) : 0.0; + + seqEstimators_.resize(omp_get_max_threads()); + + for (int i = 0; i < omp_get_max_threads(); i++) { + seqEstimators_[i] = NEW ResidualEstimator(name, r); + } + } + + ResidualParallelEstimator::~ResidualParallelEstimator() + { + for (int i = 0; i < static_cast<int>(seqEstimators_.size()); i++) { + DELETE seqEstimators_[i]; + } + } + + void ResidualParallelEstimator::addSystem(DOFMatrix *matrix_, + DOFVector<double> *uh_, + DOFVector<double> *fh_, + DOFVector<double> *uhOld_) + { + Estimator::addSystem(matrix_, uh_, fh_, uhOld_); + + for (int i = 0; i < static_cast<int>(seqEstimators_.size()); i++) { + seqEstimators_[i]->addSystem(matrix_, uh_, fh_, uhOld_); + } + } + + void ResidualParallelEstimator::addUhOldToSystem(int system, + DOFVector<double> *uhOld_) + { + Estimator::addUhOldToSystem(system, uhOld_); + + for (int i = 0; i < static_cast<int>(seqEstimators_.size()); i++) { + seqEstimators_[i]->addUhOldToSystem(system, uhOld_); + } + } + + double ResidualParallelEstimator::estimate(double ts) + { + mesh = uh[row == -1 ? 0 : row]->getFESpace()->getMesh(); + + for (int i = 0; i < static_cast<int>(seqEstimators_.size()); i++) { + seqEstimators_[i]->init(ts); + } + + TraverseParallelStack stack; + +#pragma omp parallel + { + ResidualEstimator *estimator = seqEstimators_[omp_get_thread_num()]; + + traverseFlag = + Mesh::FILL_NEIGH | + Mesh::FILL_COORDS | + Mesh::FILL_OPP_COORDS | + Mesh::FILL_BOUND | + Mesh::FILL_GRD_LAMBDA | + Mesh::FILL_DET | + Mesh::CALL_LEAF_EL; + + ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + + while (elInfo) { + estimator->estimateElement(elInfo); + elInfo = stack.traverseNext(elInfo); + } + } + + est_sum = 0.0; + est_max = 0.0; + est_t_sum = 0.0; + est_t_max = 0.0; + + for (int i = 0; i < static_cast<int>(seqEstimators_.size()); i++) { + seqEstimators_[i]->exit(false); + est_sum += pow(seqEstimators_[i]->getErrorSum(), 2); + est_max = max(est_max, seqEstimators_[i]->getErrorMax()); + est_t_sum += pow(seqEstimators_[i]->getTimeEst(), 2); + est_t_max = max(est_t_max, seqEstimators_[i]->getTimeEstMax()); + } + + est_sum = sqrt(est_sum); + est_t_sum = sqrt(est_t_sum); + + MSG("estimate = %.8e\n", est_sum); + if (C3) { + MSG("time estimate = %.8e\n", est_t_sum); + } + + return est_sum; + } + + +} + diff --git a/AMDiS/src/ResidualParallelEstimator.h b/AMDiS/src/ResidualParallelEstimator.h new file mode 100644 index 0000000000000000000000000000000000000000..d68173ba8dbeb65195023b5c9fd45b22c2822012 --- /dev/null +++ b/AMDiS/src/ResidualParallelEstimator.h @@ -0,0 +1,109 @@ +// ============================================================================ +// == == +// == AMDiS - Adaptive multidimensional simulations == +// == == +// ============================================================================ +// == == +// == crystal growth group == +// == == +// == Stiftung caesar == +// == Ludwig-Erhard-Allee 2 == +// == 53175 Bonn == +// == germany == +// == == +// ============================================================================ +// == == +// == http://www.caesar.de/cg/AMDiS == +// == == +// ============================================================================ + +/** \file ResidualParallelEstimator.h */ + +/** \defgroup Estimator Estimator module + * @{ <img src="estimator.png"> @} + */ + +#ifndef AMDIS_RESIDUALPARALLELESTIMATOR_H +#define AMDIS_RESIDUALPARALLELESTIMATOR_H + +#include "ResidualEstimator.h" +#include <vector> + +namespace AMDiS { + + // ============================================================================ + // ===== class ResidualParallelEstimator ====================================== + // ============================================================================ + + /** + * \ingroup Estimator + * + * \brief + * Parallel Residual Estimator for scalar problems. + */ + class ResidualParallelEstimator : public Estimator + { + public: + MEMORY_MANAGED(ResidualParallelEstimator); + + /** \brief + * Creator class used in the OEMSolverMap. + */ + class Creator : public EstimatorCreator + { + public: + MEMORY_MANAGED(Creator); + + Creator() : EstimatorCreator() {}; + + virtual ~Creator() {}; + + /** \brief + * Returns a new ODirSolver object. + */ + Estimator* create() { + return NEW ResidualParallelEstimator(name, row); + }; + }; + + /** \brief + * Constructor. + */ + ResidualParallelEstimator(::std::string name, int r); + + /** \brief + * Destructor. + */ + ~ResidualParallelEstimator(); + + /** \brief + * + */ + virtual void addSystem(DOFMatrix *matrix_, + DOFVector<double> *uh_, + DOFVector<double> *fh_, + DOFVector<double> *uhOld_ = NULL); + + /** \brief + * + */ + virtual void addUhOldToSystem(int system, DOFVector<double> *uhOld_); + + /** \brief + * + */ + virtual double estimate(double timestep); + + private: + ::std::vector<ResidualEstimator*> seqEstimators_; + + + /** \brief + * Constant in fromt of the time + */ + double C3; + }; + +} + +#endif // AMDIS_RESIDUALPARALLELESTIMATOR_H diff --git a/AMDiS/src/Traverse.cc b/AMDiS/src/Traverse.cc index 51786ff9e5fff95022d9ea2674069a1b11b87969..a5c7e3505caada3f7f00aa35dbcafe486875d1cc 100644 --- a/AMDiS/src/Traverse.cc +++ b/AMDiS/src/Traverse.cc @@ -340,7 +340,7 @@ namespace AMDiS { el = elinfo_stack[stack_used]->getElement(); if ((el == NULL) || (el->getFirstChild() == NULL)) { - return(elinfo_stack[stack_used]); + return (elinfo_stack[stack_used]); } } else { el = elinfo_stack[stack_used]->getElement(); diff --git a/AMDiS/src/TraverseParallel.cc b/AMDiS/src/TraverseParallel.cc new file mode 100644 index 0000000000000000000000000000000000000000..d6b99c7a4b85913d969efa1362950cda6903546d --- /dev/null +++ b/AMDiS/src/TraverseParallel.cc @@ -0,0 +1,49 @@ +#include "TraverseParallel.h" +#include "OpenMP.h" +#include "Mesh.h" + +#ifdef _OPENMP + +namespace AMDiS { + + TraverseParallelStack::TraverseParallelStack(int nThreads) + { + if (nThreads == 0) { + nThreads_ = omp_get_max_threads(); + } else { + nThreads_ = nThreads; + } + + stacks_.resize(nThreads_); + int i = 0; + for (::std::vector<TraverseStack*>::iterator it = stacks_.begin(); + it != stacks_.end(); + ++it) { + + (*it) = NEW TraverseStack(); + + (*it)->setMyThreadId(i++); + (*it)->setMaxThreads(nThreads_); + } + } + + TraverseParallelStack::~TraverseParallelStack() + { + for (::std::vector<TraverseStack*>::iterator it = stacks_.begin(); + it != stacks_.end(); + ++it) { + + DELETE (*it); + } + } + + ElInfo* TraverseParallelStack::traverseFirst(Mesh *mesh, int level, Flag fill_flag) + { + TEST_EXIT(fill_flag.isSet(Mesh::CALL_LEAF_EL))("not yet implemented"); + TEST_EXIT(stacks_[omp_get_thread_num()])("something wrong with parallel stack traverse"); + + return stacks_[omp_get_thread_num()]->traverseFirst(mesh, level, fill_flag); + } +} + +#endif // _OPENMP diff --git a/AMDiS/src/TraverseParallel.h b/AMDiS/src/TraverseParallel.h new file mode 100644 index 0000000000000000000000000000000000000000..83f5072b1945228375a4431978b7c7c8f98d4c3e --- /dev/null +++ b/AMDiS/src/TraverseParallel.h @@ -0,0 +1,69 @@ +// ============================================================================ +// == == +// == AMDiS - Adaptive multidimensional simulations == +// == == +// ============================================================================ +// == == +// == crystal growth group == +// == == +// == Stiftung caesar == +// == Ludwig-Erhard-Allee 2 == +// == 53175 Bonn == +// == germany == +// == == +// ============================================================================ +// == == +// == http://www.caesar.de/cg/AMDiS == +// == == +// ============================================================================ + +/** \file TraverseParallel.h */ + +#ifndef AMDIS_TRAVERSEPARALLEL_H +#define AMDIS_TRAVERSEPARALLEL_H + +#ifdef _OPENMP + +#include "OpenMP.h" +#include "Traverse.h" +#include <vector> + +namespace AMDiS { + + // =========================================================================== + // ===== class TraverseParallelStack ========================================= + // =========================================================================== + + /** \ingroup Traverse + * \brief + */ + class TraverseParallelStack + { + public: + MEMORY_MANAGED(TraverseParallelStack); + + TraverseParallelStack(int nThreads = 0); + + ~TraverseParallelStack(); + + ElInfo* traverseFirst(Mesh *mesh, int level, Flag fill_flag); + + inline ElInfo* traverseNext(ElInfo* elinfo_old) { + return stacks_[omp_get_thread_num()]->traverseNext(elinfo_old); + } + + private: + /** \brief + * Number of threads using the stack in parallel. + */ + int nThreads_; + + ::std::vector<TraverseStack*> stacks_; + }; + +} + +#endif // _OPENMP + +#endif // AMDIS_TRAVERSEPARALLEL_H +