diff --git a/src/Classic/Algorithms/PartBunch.cpp b/src/Classic/Algorithms/PartBunch.cpp index b475a680dd1b5f7604acef6ec212cf60b14f0d23..2be8fe9af747162e8cb6e4722b4b1cb65c3e7aa8 100644 --- a/src/Classic/Algorithms/PartBunch.cpp +++ b/src/Classic/Algorithms/PartBunch.cpp @@ -123,8 +123,7 @@ void PartBunch::computeSelfFields(int binNumber) { if(fs_m->hasValidSolver()) { /// Mesh the whole domain - if(fs_m->getFieldSolverType() == "SAAMG") - resizeMesh(); + resizeMesh(); /// Scatter charge onto space charge grid. this->Q *= this->dt; @@ -328,12 +327,14 @@ void PartBunch::computeSelfFields(int binNumber) { } void PartBunch::resizeMesh() { + if (fs_m->getFieldSolverType() != "SAAMG") { + return; + } + double xmin = fs_m->solver_m->getXRangeMin(); double xmax = fs_m->solver_m->getXRangeMax(); double ymin = fs_m->solver_m->getYRangeMin(); double ymax = fs_m->solver_m->getYRangeMax(); - double zmin = fs_m->solver_m->getZRangeMin(); - double zmax = fs_m->solver_m->getZRangeMax(); if(xmin > rmin_m[0] || xmax < rmax_m[0] || ymin > rmin_m[1] || ymax < rmax_m[1]) { @@ -354,14 +355,14 @@ void PartBunch::resizeMesh() { boundp(); get_bounds(rmin_m, rmax_m); } - Vector_t mymin = Vector_t(xmin, ymin , zmin); - Vector_t mymax = Vector_t(xmax, ymax , zmax); - for (int i = 0; i < 3; i++) - hr_m[i] = (mymax[i] - mymin[i])/nr_m[i]; + Vector_t origin = Vector_t(0.0, 0.0, 0.0); + + // update the mesh origin and mesh spacing hr_m + fs_m->solver_m->resizeMesh(origin, hr_m, rmin_m, rmax_m, dh_m); getMesh().set_meshSpacing(&(hr_m[0])); - getMesh().set_origin(mymin); + getMesh().set_origin(origin); rho_m.initialize(getMesh(), getFieldLayout(), @@ -384,8 +385,7 @@ void PartBunch::computeSelfFields() { if(fs_m->hasValidSolver()) { //mesh the whole domain - if(fs_m->getFieldSolverType() == "SAAMG") - resizeMesh(); + resizeMesh(); //scatter charges onto grid this->Q *= this->dt; @@ -510,8 +510,7 @@ void PartBunch::computeSelfFields_cycl(double gamma) { if(fs_m->hasValidSolver()) { /// mesh the whole domain - if(fs_m->getFieldSolverType() == "SAAMG") - resizeMesh(); + resizeMesh(); /// scatter particles charge onto grid. this->Q.scatter(this->rho_m, this->R, IntrplCIC_t()); @@ -639,8 +638,7 @@ void PartBunch::computeSelfFields_cycl(int bin) { if(fs_m->hasValidSolver()) { /// mesh the whole domain - if(fs_m->getFieldSolverType() == "SAAMG") - resizeMesh(); + resizeMesh(); /// scatter particles charge onto grid. this->Q.scatter(this->rho_m, this->R, IntrplCIC_t()); diff --git a/src/Classic/Algorithms/PartBunchBase.h b/src/Classic/Algorithms/PartBunchBase.h index 76807acfa037f60c17faccd72b4f51a3a7b43870..47b865bd6587ccaacf28de35295d892cb421313a 100644 --- a/src/Classic/Algorithms/PartBunchBase.h +++ b/src/Classic/Algorithms/PartBunchBase.h @@ -411,6 +411,8 @@ public: // virtual void setFieldLayout(FieldLayout_t* fLayout) = 0; virtual FieldLayout_t &getFieldLayout() = 0; + virtual void resizeMesh() { }; + /* * Wrapped member functions of IpplParticleBase */ diff --git a/src/Solvers/EllipticDomain.cpp b/src/Solvers/EllipticDomain.cpp index 28b6e8f2780ca407ad43de1898c5edfac73781a6..d3365cd53028bd7542eceaadb4ad370342b7e714 100644 --- a/src/Solvers/EllipticDomain.cpp +++ b/src/Solvers/EllipticDomain.cpp @@ -1,6 +1,8 @@ // // Class EllipticDomain -// :FIXME: add brief description +// This class provides an elliptic beam pipe. The mesh adapts to the bunch size +// in the longitudinal direction. At the intersection of the mesh with the +// beam pipe, three stencil interpolation methods are available. // // Copyright (c) 2008, Yves Ineichen, ETH Zürich, // 2013 - 2015, Tülin Kaman, Paul Scherrer Institut, Villigen PSI, Switzerland @@ -38,52 +40,36 @@ EllipticDomain::EllipticDomain(Vector_t nr, Vector_t hr) { setHr(hr); } -EllipticDomain::EllipticDomain(double semimajor, double semiminor, Vector_t nr, Vector_t hr, std::string interpl) { - SemiMajor = semimajor; - SemiMinor = semiminor; +EllipticDomain::EllipticDomain(double semimajor, double semiminor, Vector_t nr, + Vector_t hr, std::string interpl) + : semiMajor_m(semimajor) + , semiMinor_m(semiminor) +{ setNr(nr); setHr(hr); - if(interpl == "CONSTANT") - interpolationMethod = CONSTANT; - else if(interpl == "LINEAR") - interpolationMethod = LINEAR; - else if(interpl == "QUADRATIC") - interpolationMethod = QUADRATIC; + if (interpl == "CONSTANT") + interpolationMethod_m = CONSTANT; + else if (interpl == "LINEAR") + interpolationMethod_m = LINEAR; + else if (interpl == "QUADRATIC") + interpolationMethod_m = QUADRATIC; } -EllipticDomain::EllipticDomain(BoundaryGeometry *bgeom, Vector_t nr, Vector_t hr, std::string interpl) { - SemiMajor = bgeom->getA(); - SemiMinor = bgeom->getB(); +EllipticDomain::EllipticDomain(BoundaryGeometry *bgeom, Vector_t nr, Vector_t hr, + std::string interpl) + : EllipticDomain(bgeom->getA(), bgeom->getB(), nr, hr, interpl) +{ setMinMaxZ(bgeom->getS(), bgeom->getLength()); - setNr(nr); - setHr(hr); - - if(interpl == "CONSTANT") - interpolationMethod = CONSTANT; - else if(interpl == "LINEAR") - interpolationMethod = LINEAR; - else if(interpl == "QUADRATIC") - interpolationMethod = QUADRATIC; } -EllipticDomain::EllipticDomain(BoundaryGeometry *bgeom, Vector_t nr, std::string interpl) { - SemiMajor = bgeom->getA(); - SemiMinor = bgeom->getB(); - setMinMaxZ(bgeom->getS(), bgeom->getLength()); - Vector_t hr_m; - hr_m[0] = (getXRangeMax()-getXRangeMin())/nr[0]; - hr_m[1] = (getYRangeMax()-getYRangeMin())/nr[1]; - hr_m[2] = (getZRangeMax()-getZRangeMin())/nr[2]; - setHr(hr_m); - - if(interpl == "CONSTANT") - interpolationMethod = CONSTANT; - else if(interpl == "LINEAR") - interpolationMethod = LINEAR; - else if(interpl == "QUADRATIC") - interpolationMethod = QUADRATIC; -} +EllipticDomain::EllipticDomain(BoundaryGeometry *bgeom, Vector_t nr, std::string interpl) + : EllipticDomain(bgeom, nr, + Vector_t(2.0 * bgeom->getA() / nr[0], + 2.0 * bgeom->getB() / nr[1], + (bgeom->getLength() - bgeom->getS()) / nr[2]), + interpl) +{ } EllipticDomain::~EllipticDomain() { //nothing so far @@ -93,164 +79,115 @@ EllipticDomain::~EllipticDomain() { // for this geometry we only have to calculate the intersection on // one x-y-plane // for the moment we center the ellipse around the center of the grid -void EllipticDomain::compute(Vector_t hr){ - //there is nothing to be done if the mesh spacings have not changed - if(hr[0] == getHr()[0] && hr[1] == getHr()[1] && hr[2] == getHr()[2]) { +void EllipticDomain::compute(Vector_t hr, NDIndex<3> localId){ + // there is nothing to be done if the mesh spacings in x and y have not changed + if (hr[0] == getHr()[0] && + hr[1] == getHr()[1]) + { hasGeometryChanged_m = false; return; } + setHr(hr); hasGeometryChanged_m = true; //reset number of points inside domain nxy_m = 0; // clear previous coordinate maps - IdxMap.clear(); - CoordMap.clear(); + idxMap_m.clear(); + coordMap_m.clear(); //clear previous intersection points - IntersectYDir.clear(); - IntersectXDir.clear(); + intersectYDir_m.clear(); + intersectXDir_m.clear(); // build a index and coordinate map int idx = 0; int x, y; - for(x = 0; x < nr[0]; x++) { - for(y = 0; y < nr[1]; y++) { - if(isInside(x, y, 1)) { - IdxMap[toCoordIdx(x, y)] = idx; - CoordMap[idx++] = toCoordIdx(x, y); + /* we need to scan the full x-y-plane on all cores + * in order to figure out the number of valid + * grid points per plane --> otherwise we might + * get not unique global indices in the Tpetra::CrsMatrix + */ + for (x = 0; x < nr[0]; ++x) { + for (y = 0; y < nr[1]; ++y) { + if (isInside(x, y, 1)) { + idxMap_m[toCoordIdx(x, y)] = idx; + coordMap_m[idx++] = toCoordIdx(x, y); nxy_m++; } - } } - switch(interpolationMethod) { + switch (interpolationMethod_m) { case CONSTANT: break; case LINEAR: case QUADRATIC: - double smajsq = SemiMajor * SemiMajor; - double sminsq = SemiMinor * SemiMinor; + double smajsq = semiMajor_m * semiMajor_m; + double sminsq = semiMinor_m * semiMinor_m; double yd = 0.0; double xd = 0.0; double pos = 0.0; - double mx = (nr[0] - 1) * hr[0] / 2.0; - double my = (nr[1] - 1) * hr[1] / 2.0; - //calculate intersection with the ellipse - for(x = 0; x < nr[0]; x++) { - pos = x * hr[0] - mx; - if (pos <= -SemiMajor || pos >= SemiMajor) + // calculate intersection with the ellipse + for (x = localId[0].first(); x <= localId[0].last(); x++) { + pos = - semiMajor_m + hr[0] * (x + 0.5); + if (std::abs(pos) >= semiMajor_m) { - IntersectYDir.insert(std::pair<int, double>(x, 0)); - IntersectYDir.insert(std::pair<int, double>(x, 0)); - }else{ - yd = std::abs(sqrt(sminsq - sminsq * pos * pos / smajsq)); // + 0.5*nr[1]*hr[1]); - IntersectYDir.insert(std::pair<int, double>(x, yd)); - IntersectYDir.insert(std::pair<int, double>(x, -yd)); + intersectYDir_m.insert(std::pair<int, double>(x, 0)); + intersectYDir_m.insert(std::pair<int, double>(x, 0)); + } else { + yd = std::abs(std::sqrt(sminsq - sminsq * pos * pos / smajsq)); + intersectYDir_m.insert(std::pair<int, double>(x, yd)); + intersectYDir_m.insert(std::pair<int, double>(x, -yd)); } } - for(y = 0; y < nr[1]; y++) { - pos = y * hr[1] - my; - if (pos <= -SemiMinor || pos >= SemiMinor) + for (y = localId[0].first(); y < localId[1].last(); y++) { + pos = - semiMinor_m + hr[1] * (y + 0.5); + if (std::abs(pos) >= semiMinor_m) { - IntersectXDir.insert(std::pair<int, double>(y, 0)); - IntersectXDir.insert(std::pair<int, double>(y, 0)); - }else{ - xd = std::abs(sqrt(smajsq - smajsq * pos * pos / sminsq)); // + 0.5*nr[0]*hr[0]); - IntersectXDir.insert(std::pair<int, double>(y, xd)); - IntersectXDir.insert(std::pair<int, double>(y, -xd)); + intersectXDir_m.insert(std::pair<int, double>(y, 0)); + intersectXDir_m.insert(std::pair<int, double>(y, 0)); + } else { + xd = std::abs(std::sqrt(smajsq - smajsq * pos * pos / sminsq)); + intersectXDir_m.insert(std::pair<int, double>(y, xd)); + intersectXDir_m.insert(std::pair<int, double>(y, -xd)); } } } } -void EllipticDomain::compute(Vector_t hr, NDIndex<3> localId){ - //there is nothing to be done if the mesh spacings have not changed - if(hr[0] == getHr()[0] && hr[1] == getHr()[1] && hr[2] == getHr()[2]) { - hasGeometryChanged_m = false; - return; - } - setHr(hr); - hasGeometryChanged_m = true; - //reset number of points inside domain - nxy_m = 0; - - // clear previous coordinate maps - IdxMap.clear(); - CoordMap.clear(); - //clear previous intersection points - IntersectYDir.clear(); - IntersectXDir.clear(); - - // build a index and coordinate map - int idx = 0; - int x, y; - - for(x = localId[0].first(); x<= localId[0].last(); x++) { - for(y = localId[1].first(); y <= localId[1].last(); y++) { - if(isInside(x, y, 1)) { - IdxMap[toCoordIdx(x, y)] = idx; - CoordMap[idx++] = toCoordIdx(x, y); - nxy_m++; - } - } - } - - switch(interpolationMethod) { - case CONSTANT: - break; - case LINEAR: - case QUADRATIC: +void EllipticDomain::resizeMesh(Vector_t& origin, Vector_t& hr, const Vector_t& rmin, + const Vector_t& rmax, double dh) +{ + Vector_t mymax = Vector_t(0.0, 0.0, 0.0); - double smajsq = SemiMajor * SemiMajor; - double sminsq = SemiMinor * SemiMinor; - double yd = 0.0; - double xd = 0.0; - double pos = 0.0; - double mx = (nr[0] - 1) * hr[0] / 2.0; - double my = (nr[1] - 1) * hr[1] / 2.0; + // apply bounding box increment dh, i.e., "BBOXINCR" input argument + double zsize = rmax[2] - rmin[2]; - //calculate intersection with the ellipse - for(x = localId[0].first(); x <= localId[0].last(); x++) { - pos = x * hr[0] - mx; - if (pos <= -SemiMajor || pos >= SemiMajor) - { - IntersectYDir.insert(std::pair<int, double>(x, 0)); - IntersectYDir.insert(std::pair<int, double>(x, 0)); - }else{ - yd = std::abs(sqrt(sminsq - sminsq * pos * pos / smajsq)); // + 0.5*nr[1]*hr[1]); - IntersectYDir.insert(std::pair<int, double>(x, yd)); - IntersectYDir.insert(std::pair<int, double>(x, -yd)); - } + setMinMaxZ(rmin[2] - zsize * (1.0 + dh), + rmax[2] + zsize * (1.0 + dh)); - } + origin = Vector_t(-semiMajor_m, -semiMinor_m, getMinZ()); + mymax = Vector_t( semiMajor_m, semiMinor_m, getMaxZ()); - for(y = localId[0].first(); y < localId[1].last(); y++) { - pos = y * hr[1] - my; - if (pos <= -SemiMinor || pos >= SemiMinor) - { - IntersectXDir.insert(std::pair<int, double>(y, 0)); - IntersectXDir.insert(std::pair<int, double>(y, 0)); - }else{ - xd = std::abs(sqrt(smajsq - smajsq * pos * pos / sminsq)); // + 0.5*nr[0]*hr[0]); - IntersectXDir.insert(std::pair<int, double>(y, xd)); - IntersectXDir.insert(std::pair<int, double>(y, -xd)); - } - } - } + for (int i = 0; i < 3; ++i) + hr[i] = (mymax[i] - origin[i]) / nr[i]; } -void EllipticDomain::getBoundaryStencil(int x, int y, int z, double &W, double &E, double &S, double &N, double &F, double &B, double &C, double &scaleFactor) { +void EllipticDomain::getBoundaryStencil(int x, int y, int z, double &W, + double &E, double &S, double &N, + double &F, double &B, double &C, + double &scaleFactor) +{ scaleFactor = 1.0; - // determine which interpolation method we use for points near the boundary - switch(interpolationMethod) { + // determine which interpolation method we use for points near the boundary + switch (interpolationMethod_m) { case CONSTANT: constantInterpolation(x, y, z, W, E, S, N, F, B, C, scaleFactor); break; @@ -266,9 +203,10 @@ void EllipticDomain::getBoundaryStencil(int x, int y, int z, double &W, double & assert(C > 0); } -void EllipticDomain::getBoundaryStencil(int idx, double &W, double &E, double &S, double &N, double &F, double &B, double &C, double &scaleFactor) { - - +void EllipticDomain::getBoundaryStencil(int idx, double &W, double &E, + double &S, double &N, double &F, + double &B, double &C, double &scaleFactor) +{ int x = 0, y = 0, z = 0; getCoord(idx, x, y, z); getBoundaryStencil(x, y, z, W, E, S, N, F, B, C, scaleFactor); @@ -283,113 +221,99 @@ void EllipticDomain::getNeighbours(int idx, int &W, int &E, int &S, int &N, int } -void EllipticDomain::getNeighbours(int x, int y, int z, int &W, int &E, int &S, int &N, int &F, int &B) { - - if(x > 0) +void EllipticDomain::getNeighbours(int x, int y, int z, int &W, int &E, + int &S, int &N, int &F, int &B) +{ + if (x > 0) W = getIdx(x - 1, y, z); else W = -1; - if(x < nr[0] - 1) + + if (x < nr[0] - 1) E = getIdx(x + 1, y, z); else E = -1; - if(y < nr[1] - 1) + if (y < nr[1] - 1) N = getIdx(x, y + 1, z); else N = -1; - if(y > 0) + + if (y > 0) S = getIdx(x, y - 1, z); else S = -1; - if(z > 0) + if (z > 0) F = getIdx(x, y, z - 1); else F = -1; - if(z < nr[2] - 1) + + if (z < nr[2] - 1) B = getIdx(x, y, z + 1); else B = -1; } -void EllipticDomain::constantInterpolation(int x, int y, int z, double &WV, double &EV, double &SV, double &NV, double &FV, double &BV, double &CV, double &scaleFactor) { - +void EllipticDomain::constantInterpolation(int x, int y, int z, double &WV, + double &EV, double &SV, double &NV, + double &FV, double &BV, double &CV, + double &scaleFactor) +{ scaleFactor = 1.0; - WV = -1/(hr[0]*hr[0]); - EV = -1/(hr[0]*hr[0]); - NV = -1/(hr[1]*hr[1]); - SV = -1/(hr[1]*hr[1]); - FV = -1/(hr[2]*hr[2]); - BV = -1/(hr[2]*hr[2]); - CV = 2/(hr[0]*hr[0]) + 2/(hr[1]*hr[1]) + 2/(hr[2]*hr[2]); + WV = -1.0 / (hr[0] * hr[0]); + EV = -1.0 / (hr[0] * hr[0]); + NV = -1.0 / (hr[1] * hr[1]); + SV = -1.0 / (hr[1] * hr[1]); + FV = -1.0 / (hr[2] * hr[2]); + BV = -1.0 / (hr[2] * hr[2]); + + CV = 2.0 / (hr[0] * hr[0]) + + 2.0 / (hr[1] * hr[1]) + + 2.0 / (hr[2] * hr[2]); // we are a right boundary point - if(!isInside(x + 1, y, z)) - EV= 0.0; + if (!isInside(x + 1, y, z)) + EV = 0.0; // we are a left boundary point - if(!isInside(x - 1, y, z)) + if (!isInside(x - 1, y, z)) WV = 0.0; // we are a upper boundary point - if(!isInside(x, y + 1, z)) + if (!isInside(x, y + 1, z)) NV = 0.0; // we are a lower boundary point - if(!isInside(x, y - 1, z)) + if (!isInside(x, y - 1, z)) SV = 0.0; - if(z == 1 || z == nr[2] - 2) { - - // case where we are on the Robin BC in Z-direction - // where we distinguish two cases - // IFF: this values should not matter because they - // never make it into the discretization matrix - if(z == 1) - FV = 0.0; - else - BV = 0.0; - - // add contribution of Robin discretization to center point - // d the distance between the center of the bunch and the boundary - //double cx = (x-(nr[0]-1)/2)*hr[0]; - //double cy = (y-(nr[1]-1)/2)*hr[1]; - //double cz = hr[2]*(nr[2]-1); - //double d = sqrt(cx*cx+cy*cy+cz*cz); - double d = hr[2] * (nr[2] - 1) / 2; - CV += 2 / (d * hr[2]); - //C += 2/((hr[2]*(nr[2]-1)/2.0) * hr[2]); - - // scale all stencil-points in z-plane with 0.5 (Robin discretization) - WV /= 2.0; - EV /= 2.0; - NV /= 2.0; - SV /= 2.0; - CV /= 2.0; - scaleFactor *= 0.5; - } - + // handle boundary condition in z direction + robinBoundaryStencil(z, FV, BV, CV); } -void EllipticDomain::linearInterpolation(int x, int y, int z, double &W, double &E, double &S, double &N, double &F, double &B, double &C, double &scaleFactor) { - +void EllipticDomain::linearInterpolation(int x, int y, int z, double &W, + double &E, double &S, double &N, + double &F, double &B, double &C, + double &scaleFactor) +{ scaleFactor = 1.0; - double cx = x * hr[0] - (nr[0] - 1) * hr[0] / 2.0; - double cy = y * hr[1] - (nr[1] - 1) * hr[1] / 2.0; + double cx = - semiMajor_m + hr[0] * (x + 0.5); + double cy = - semiMinor_m + hr[1] * (y + 0.5); double dx = 0.0; - std::multimap<int, double>::iterator it = IntersectXDir.find(y); - if(cx < 0) + std::multimap<int, double>::iterator it = intersectXDir_m.find(y); + + if (cx < 0) ++it; dx = it->second; double dy = 0.0; - it = IntersectYDir.find(x); - if(cy < 0) + it = intersectYDir_m.find(x); + if (cy < 0) ++it; dy = it->second; @@ -400,73 +324,55 @@ void EllipticDomain::linearInterpolation(int x, int y, int z, double &W, double double ds = hr[1]; C = 0.0; - //we are a right boundary point - if(!isInside(x + 1, y, z)) { - C += 1 / ((dx - cx) * de); + // we are a right boundary point + if (!isInside(x + 1, y, z)) { + C += 1.0 / ((dx - cx) * de); E = 0.0; } else { - C += 1 / (de * de); - E = -1 / (de * de); + C += 1.0 / (de * de); + E = -1.0 / (de * de); } - //we are a left boundary point - if(!isInside(x - 1, y, z)) { - C += 1 / ((std::abs(dx) - std::abs(cx)) * dw); + // we are a left boundary point + if (!isInside(x - 1, y, z)) { + C += 1.0 / ((std::abs(dx) - std::abs(cx)) * dw); W = 0.0; } else { - C += 1 / (dw * dw); - W = -1 / (dw * dw); + C += 1.0 / (dw * dw); + W = -1.0 / (dw * dw); } - //we are a upper boundary point - if(!isInside(x, y + 1, z)) { - C += 1 / ((dy - cy) * dn); + // we are a upper boundary point + if (!isInside(x, y + 1, z)) { + C += 1.0 / ((dy - cy) * dn); N = 0.0; } else { - C += 1 / (dn * dn); - N = -1 / (dn * dn); + C += 1.0 / (dn * dn); + N = -1.0 / (dn * dn); } - //we are a lower boundary point - if(!isInside(x, y - 1, z)) { - C += 1 / ((std::abs(dy) - std::abs(cy)) * ds); + // we are a lower boundary point + if (!isInside(x, y - 1, z)) { + C += 1.0 / ((std::abs(dy) - std::abs(cy)) * ds); S = 0.0; } else { - C += 1 / (ds * ds); - S = -1 / (ds * ds); + C += 1.0 / (ds * ds); + S = -1.0 / (ds * ds); } - F = -1 / (hr[2] * hr[2]); - B = -1 / (hr[2] * hr[2]); - C += 2 / (hr[2] * hr[2]); - // handle boundary condition in z direction -/* - if(z == 0 || z == nr[2] - 1) { - - // case where we are on the NEUMAN BC in Z-direction - // where we distinguish two cases - if(z == 0) - F = 0.0; - else - B = 0.0; - - //hr[2]*(nr2[2]-1)/2 = radius - double d = hr[2] * (nr[2] - 1) / 2; - C += 2 / (d * hr[2]); - - W /= 2.0; - E /= 2.0; - N /= 2.0; - S /= 2.0; - C /= 2.0; - scaleFactor *= 0.5; - - } -*/ + F = -1.0 / (hr[2] * hr[2]); + B = -1.0 / (hr[2] * hr[2]); + C += 2.0 / (hr[2] * hr[2]); + robinBoundaryStencil(z, F, B, C); } -void EllipticDomain::quadraticInterpolation(int x, int y, int z, double &W, double &E, double &S, double &N, double &F, double &B, double &C, double &scaleFactor) { +void EllipticDomain::quadraticInterpolation(int x, int y, int z, + double &W, double &E, double &S, + double &N, double &F, double &B, double &C, + double &scaleFactor) +{ + scaleFactor = 1.0; double cx = (x - (nr[0] - 1) / 2.0) * hr[0]; double cy = (y - (nr[1] - 1) / 2.0) * hr[1]; @@ -474,14 +380,14 @@ void EllipticDomain::quadraticInterpolation(int x, int y, int z, double &W, doub // since every vector for elliptic domains has ALWAYS size 2 we // can catch all cases manually double dx = 0.0; - std::multimap<int, double>::iterator it = IntersectXDir.find(y); - if(cx < 0) + std::multimap<int, double>::iterator it = intersectXDir_m.find(y); + if (cx < 0) ++it; dx = it->second; double dy = 0.0; - it = IntersectYDir.find(x); - if(cy < 0) + it = intersectYDir_m.find(x); + if (cy < 0) ++it; dy = it->second; @@ -489,197 +395,80 @@ void EllipticDomain::quadraticInterpolation(int x, int y, int z, double &W, doub double de = hr[0]; double dn = hr[1]; double ds = hr[1]; - W = 1.0; - E = 1.0; - N = 1.0; - S = 1.0; - F = 1.0; - B = 1.0; + + W = 0.0; + E = 0.0; + S = 0.0; + N = 0.0; C = 0.0; - //TODO: = cx+hr[0] > dx && cx > 0 - //if((x-nr[0]/2.0+1)*hr[0] > dx && cx > 0) { - ////we are a right boundary point - ////if(!isInside(x+1,y,z)) { - //de = dx-cx; - //} - - //if((x-nr[0]/2.0-1)*hr[0] < dx && cx < 0) { - ////we are a left boundary point - ////if(!isInside(x-1,y,z)) { - //dw = std::abs(dx)-std::abs(cx); - //} - - //if((y-nr[1]/2.0+1)*hr[1] > dy && cy > 0) { - ////we are a upper boundary point - ////if(!isInside(x,y+1,z)) { - //dn = dy-cy; - //} - - //if((y-nr[1]/2.0-1)*hr[1] < dy && cy < 0) { - ////we are a lower boundary point - ////if(!isInside(x,y-1,z)) { - //ds = std::abs(dy)-std::abs(cy); - //} - - //TODO: = cx+hr[0] > dx && cx > 0 - //if((x-nr[0]/2.0+1)*hr[0] > dx && cx > 0) { - //we are a right boundary point - if(!isInside(x + 1, y, z)) { - de = dx - cx; + // we are a right boundary point + if (!isInside(x + 1, y, z)) { + double s = dx - cx; + C -= 2.0 * (s - 1.0) / (s * de); E = 0.0; + W += (s - 1.0) / ((s + 1.0) * de); + } else { + C += 1.0 / (de * de); + E = -1.0 / (de * de); } - //if((x-nr[0]/2.0-1)*hr[0] < dx && cx < 0) { - //we are a left boundary point - if(!isInside(x - 1, y, z)) { - dw = std::abs(dx) - std::abs(cx); + // we are a left boundary point + if (!isInside(x - 1, y, z)) { + double s = std::abs(dx) - std::abs(cx); + C -= 2.0 * (s - 1.0) / (s * de); W = 0.0; + E += (s - 1.0) / ((s + 1.0) * de); + } else { + C += 1.0 / (dw * dw); + W = -1.0 / (dw * dw); } - //if((y-nr[1]/2.0+1)*hr[1] > dy && cy > 0) { - //we are a upper boundary point - if(!isInside(x, y + 1, z)) { - dn = dy - cy; + // we are a upper boundary point + if (!isInside(x, y + 1, z)) { + double s = dy - cy; + C -= 2.0 * (s - 1.0) / (s * dn); N = 0.0; + S += (s - 1.0) / ((s + 1.0) * dn); + } else { + C += 1.0 / (dn * dn); + N = -1.0 / (dn * dn); } - //if((y-nr[1]/2.0-1)*hr[1] < dy && cy < 0) { - //we are a lower boundary point - if(!isInside(x, y - 1, z)) { - ds = std::abs(dy) - std::abs(cy); + // we are a lower boundary point + if (!isInside(x, y - 1, z)) { + double s = std::abs(dy) - std::abs(cy); + C -= 2.0 * (s - 1.0) / (s * dn); S = 0.0; + N += (s - 1.0) / ((s + 1.0) * dn); + } else { + C += 1.0 / (ds * ds); + S = -1.0 / (ds * ds); } - //2/dw*(dw_de) - W *= -1.0 / (dw * (dw + de)); - E *= -1.0 / (de * (dw + de)); - N *= -1.0 / (dn * (dn + ds)); - S *= -1.0 / (ds * (dn + ds)); - F = -1 / (hr[2] * (hr[2] + hr[2])); - B = -1 / (hr[2] * (hr[2] + hr[2])); - - //TODO: problem when de,dw,dn,ds == 0 - //is NOT a regular BOUND PT - C += 1 / de * 1 / dw; - C += 1 / dn * 1 / ds; - C += 1 / hr[2] * 1 / hr[2]; - scaleFactor = 0.5; - - - //for regular gridpoints no problem with symmetry, just boundary - //z direction is right - //implement isLastInside(dir) - //we have LOCAL x,y coordinates! - - /* - if(dw != 0 && !wIsB) - W = -1/dw * (dn+ds) * 2*hr[2]; - else - W = 0; - if(de != 0 && !eIsB) - E = -1/de * (dn+ds) * 2*hr[2]; - else - E = 0; - if(dn != 0 && !nIsB) - N = -1/dn * (dw+de) * 2*hr[2]; - else - N = 0; - if(ds != 0 && !sIsB) - S = -1/ds * (dw+de) * 2*hr[2]; - else - S = 0; - F = -(dw+de)*(dn+ds)/hr[2]; - B = -(dw+de)*(dn+ds)/hr[2]; - */ - - //if(dw != 0) - //W = -2*hr[2]*(dn+ds)/dw; - //else - //W = 0; - //if(de != 0) - //E = -2*hr[2]*(dn+ds)/de; - //else - //E = 0; - //if(dn != 0) - //N = -2*hr[2]*(dw+de)/dn; - //else - //N = 0; - //if(ds != 0) - //S = -2*hr[2]*(dw+de)/ds; - //else - //S = 0; - //F = -(dw+de)*(dn+ds)/hr[2]; - //B = -(dw+de)*(dn+ds)/hr[2]; - - //// RHS scaleFactor for current 3D index - //// Factor 0.5 results from the SW/quadratic extrapolation - //scaleFactor = 0.5*(dw+de)*(dn+ds)*(2*hr[2]); - - // catch the case where a point lies on the boundary - //FIXME: do this more elegant! - //double m1 = dw*de; - //double m2 = dn*ds; - //if(de == 0) - //m1 = dw; - //if(dw == 0) - //m1 = de; - //if(dn == 0) - //m2 = ds; - //if(ds == 0) - //m2 = dn; - ////XXX: dn+ds || dw+de can be 0 - ////C = 2*(dn+ds)*(dw+de)/hr[2]; - //C = 2/hr[2]; - //if(dw != 0 || de != 0) - //C *= (dw+de); - //if(dn != 0 || ds != 0) - //C *= (dn+ds); - //if(dw != 0 || de != 0) - //C += (2*hr[2])*(dn+ds)*(dw+de)/m1; - //if(dn != 0 || ds != 0) - //C += (2*hr[2])*(dw+de)*(dn+ds)/m2; - - //handle Neumann case - //if(z == 0 || z == nr[2]-1) { - - //if(z == 0) - //F = 0.0; - //else - //B = 0.0; - - ////neumann stuff - //W = W/2.0; - //E = E/2.0; - //N = N/2.0; - //S = S/2.0; - //C /= 2.0; - - //scaleFactor /= 2.0; - //} - // handle boundary condition in z direction - if(z == 0 || z == nr[2] - 1) { + F = -1.0 / (hr[2] * hr[2]); + B = -1.0 / (hr[2] * hr[2]); + C += 2.0 / (hr[2] * hr[2]); + robinBoundaryStencil(z, F, B, C); +} + +void EllipticDomain::robinBoundaryStencil(int z, double &F, double &B, double &C) { + if (z == 0 || z == nr[2] - 1) { - // case where we are on the NEUMAN BC in Z-direction + // case where we are on the Robin BC in Z-direction // where we distinguish two cases - if(z == 0) + // IFF: this values should not matter because they + // never make it into the discretization matrix + if (z == 0) F = 0.0; else B = 0.0; - //C += 2/((hr[2]*(nr[2]-1)/2.0) * hr[2]); - //hr[2]*(nr2[2]-1)/2 = radius - double d = hr[2] * (nr[2] - 1) / 2; - C += 2 / (d * hr[2]); - - W /= 2.0; - E /= 2.0; - N /= 2.0; - S /= 2.0; - C /= 2.0; - scaleFactor /= 2.0; - + // add contribution of Robin discretization to center point + // d the distance between the center of the bunch and the boundary + double d = 0.5 * hr[2] * (nr[2] - 1); + C += 2.0 / (d * hr[2]); } } diff --git a/src/Solvers/EllipticDomain.h b/src/Solvers/EllipticDomain.h index 691e82cffb148c0180103eef7fd127c843681fb2..e5478b5ae1fe0cdd90739b84cffa1c9232a5449b 100644 --- a/src/Solvers/EllipticDomain.h +++ b/src/Solvers/EllipticDomain.h @@ -1,6 +1,8 @@ // // Class EllipticDomain -// :FIXME: add brief description +// This class provides an elliptic beam pipe. The mesh adapts to the bunch size +// in the longitudinal direction. At the intersection of the mesh with the +// beam pipe, three stencil interpolation methods are available. // // Copyright (c) 2008, Yves Ineichen, ETH Zürich, // 2013 - 2015, Tülin Kaman, Paul Scherrer Institut, Villigen PSI, Switzerland @@ -32,100 +34,127 @@ #include <cmath> #include "IrregularDomain.h" #include "Structure/BoundaryGeometry.h" +#include "Utilities/OpalException.h" class EllipticDomain : public IrregularDomain { public: EllipticDomain(Vector_t nr, Vector_t hr); - EllipticDomain(double semimajor, double semiminor, Vector_t nr, Vector_t hr, std::string interpl); - EllipticDomain(BoundaryGeometry *bgeom, Vector_t nr, Vector_t hr, std::string interpl); + + EllipticDomain(double semimajor, double semiminor, Vector_t nr, + Vector_t hr, std::string interpl); + + EllipticDomain(BoundaryGeometry *bgeom, Vector_t nr, + Vector_t hr, std::string interpl); + EllipticDomain(BoundaryGeometry *bgeom, Vector_t nr, std::string interpl); ~EllipticDomain(); /// returns discretization at (x,y,z) - void getBoundaryStencil(int x, int y, int z, double &W, double &E, double &S, double &N, double &F, double &B, double &C, double &scaleFactor); + void getBoundaryStencil(int x, int y, int z, + double &W, double &E, double &S, + double &N, double &F, double &B, + double &C, double &scaleFactor); + /// returns discretization at 3D index - void getBoundaryStencil(int idx, double &W, double &E, double &S, double &N, double &F, double &B, double &C, double &scaleFactor); + void getBoundaryStencil(int idx, double &W, double &E, + double &S, double &N, double &F, + double &B, double &C, double &scaleFactor); + /// returns index of neighbours at (x,y,z) - void getNeighbours(int x, int y, int z, int &W, int &E, int &S, int &N, int &F, int &B); + void getNeighbours(int x, int y, int z, int &W, int &E, + int &S, int &N, int &F, int &B); + /// returns index of neighbours at 3D index void getNeighbours(int idx, int &W, int &E, int &S, int &N, int &F, int &B); + /// returns type of boundary condition std::string getType() {return "Elliptic";} + /// queries if a given (x,y,z) coordinate lies inside the domain inline bool isInside(int x, int y, int z) { - double xx = (x - (nr[0] - 1) / 2.0) * hr[0]; - double yy = (y - (nr[1] - 1) / 2.0) * hr[1]; - return ((xx * xx / (SemiMajor * SemiMajor) + yy * yy / (SemiMinor * SemiMinor) < 1) && z != 0 && z != nr[2] - 1); + double xx = - semiMajor_m + hr[0] * (x + 0.5); + double yy = - semiMinor_m + hr[1] * (y + 0.5); + + bool isInsideEllipse = (xx * xx / (semiMajor_m * semiMajor_m) + + yy * yy / (semiMinor_m * semiMinor_m) < 1); + + return (isInsideEllipse && z > 0 && z < nr[2] - 1); } int getNumXY(int /*z*/) { return nxy_m; } - /// set semi-minor - void setSemiMinor(double sm) {SemiMinor = sm;} - /// set semi-major - void setSemiMajor(double sm) {SemiMajor = sm;} - /// calculates intersection - void compute(Vector_t hr); + + /// calculates intersection + void compute(Vector_t /*hr*/) { + throw OpalException("EllipticDomain::compute()", "This function is not available."); + } + void compute(Vector_t hr, NDIndex<3> localId); - double getXRangeMin() { return -SemiMajor; } - double getXRangeMax() { return SemiMajor; } - double getYRangeMin() { return -SemiMinor; } - double getYRangeMax() { return SemiMinor; } + double getXRangeMin() { return -semiMajor_m; } + double getXRangeMax() { return semiMajor_m; } + double getYRangeMin() { return -semiMinor_m; } + double getYRangeMax() { return semiMinor_m; } double getZRangeMin() { return zMin_m; } double getZRangeMax() { return zMax_m; } + bool hasGeometryChanged() { return hasGeometryChanged_m; } - //TODO: ? - int getStartIdx() {return 0;} - bool hasGeometryChanged() { return hasGeometryChanged_m; } + void resizeMesh(Vector_t& origin, Vector_t& hr, const Vector_t& rmin, + const Vector_t& rmax, double dh); private: /// Map from a single coordinate (x or y) to a list of intersection values with /// boundary. - typedef std::multimap<int, double> EllipticPointList; + typedef std::multimap<int, double> EllipticPointList_t; /// all intersection points with grid lines in X direction - EllipticPointList IntersectXDir; + EllipticPointList_t intersectXDir_m; /// all intersection points with grid lines in Y direction - EllipticPointList IntersectYDir; + EllipticPointList_t intersectYDir_m; /// mapping (x,y,z) -> idx - std::map<int, int> IdxMap; + std::map<int, int> idxMap_m; /// mapping idx -> (x,y,z) - std::map<int, int> CoordMap; + std::map<int, int> coordMap_m; /// semi-major of the ellipse - double SemiMajor; + double semiMajor_m; + /// semi-minor of the ellipse - double SemiMinor; + double semiMinor_m; + /// number of nodes in the xy plane (for this case: independent of the z coordinate) int nxy_m; + /// interpolation type - int interpolationMethod; + int interpolationMethod_m; + /// flag indicating if geometry has changed for the current time-step bool hasGeometryChanged_m; /// conversion from (x,y) to index in xy plane inline int toCoordIdx(int x, int y) { return y * nr[0] + x; } + /// conversion from (x,y,z) to index on the 3D grid inline int getIdx(int x, int y, int z) { - if(isInside(x, y, z) && x >= 0 && y >= 0 && z >= 0) - return IdxMap[toCoordIdx(x, y)] + (z - 1) * nxy_m; + if (isInside(x, y, z)) + return idxMap_m[toCoordIdx(x, y)] + (z - 1) * nxy_m; else return -1; } + /// conversion from a 3D index to (x,y,z) inline void getCoord(int idx, int &x, int &y, int &z) { int ixy = idx % nxy_m; - int xy = CoordMap[ixy]; + int xy = coordMap_m[ixy]; int inr = (int)nr[0]; x = xy % inr; y = (xy - x) / nr[0]; @@ -133,10 +162,23 @@ private: } /// different interpolation methods for boundary points - void constantInterpolation(int x, int y, int z, double &W, double &E, double &S, double &N, double &F, double &B, double &C, double &scaleFactor); - void linearInterpolation(int x, int y, int z, double &W, double &E, double &S, double &N, double &F, double &B, double &C, double &scaleFactor); - void quadraticInterpolation(int x, int y, int z, double &W, double &E, double &S, double &N, double &F, double &B, double &C, double &scaleFactor); - + void constantInterpolation(int x, int y, int z, + double &W, double &E, double &S, + double &N, double &F, double &B, + double &C, double &scaleFactor); + + void linearInterpolation(int x, int y, int z, double &W, + double &E, double &S, double &N, + double &F, double &B, double &C, + double &scaleFactor); + + void quadraticInterpolation(int x, int y, int z, double &W, + double &E, double &S, double &N, + double &F, double &B, double &C, + double &scaleFactor); + + /// function to handle the open boundary condition in longitudinal direction + void robinBoundaryStencil(int z, double &F, double &B, double &C); }; #endif //#ifdef ELLIPTICAL_DOMAIN_H diff --git a/src/Solvers/IrregularDomain.h b/src/Solvers/IrregularDomain.h index 4569f663d9cfbd9a3bdb78ce6875b5b69a438fd0..eb00435e1772f8dca9f019ebc0848650c29e0047 100644 --- a/src/Solvers/IrregularDomain.h +++ b/src/Solvers/IrregularDomain.h @@ -129,6 +129,22 @@ public: virtual bool hasGeometryChanged() = 0; virtual ~IrregularDomain() {}; + virtual void resizeMesh(Vector_t& origin, Vector_t& hr, + const Vector_t& /*rmin*/, const Vector_t& /*rmax*/, double /*dh*/) { + double xmin = getXRangeMin(); + double xmax = getXRangeMax(); + double ymin = getYRangeMin(); + double ymax = getYRangeMax(); + double zmin = getZRangeMin(); + double zmax = getZRangeMax(); + + origin = Vector_t(xmin, ymin , zmin); + Vector_t mymax = Vector_t(xmax, ymax , zmax); + + for (int i = 0; i < 3; i++) + hr[i] = (mymax[i] - origin[i]) / nr[i]; + }; + protected: // a irregular domain is always defined on a grid diff --git a/src/Solvers/MGPoissonSolver.cpp b/src/Solvers/MGPoissonSolver.cpp index 57836bfd6ea0634b7c4b8ebb34c2525aefff80b8..ddcf129c7ebe3b38e3ae1374d1de41320d266817 100644 --- a/src/Solvers/MGPoissonSolver.cpp +++ b/src/Solvers/MGPoissonSolver.cpp @@ -353,8 +353,10 @@ void MGPoissonSolver::computePotential(Field_t &rho, Vector_t hr) { for (int idz = localId[2].first(); idz <= localId[2].last(); idz++) { for (int idy = localId[1].first(); idy <= localId[1].last(); idy++) { for (int idx = localId[0].first(); idx <= localId[0].last(); idx++) { + NDIndex<3> l(Index(idx, idx), Index(idy, idy), Index(idz, idz)); if (bp_m->isInside(idx, idy, idz)) - RHS->getDataNonConst()[id++] = 4*M_PI*rho[idx][idy][idz].get()/scaleFactor; + RHS->replaceGlobalValue(bp_m->getIdx(idx, idy, idz), + 4.0 * M_PI * rho.localElement(l) / scaleFactor); } } } @@ -508,6 +510,7 @@ void MGPoissonSolver::IPPLToMap3D(NDIndex<3> localId) { } } } + int indexbase = 0; map_p = Teuchos::rcp(new TpetraMap_t(Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid(), &MyGlobalElements[0], NumMyElements, indexbase, comm_mp)); diff --git a/src/Solvers/MGPoissonSolver.h b/src/Solvers/MGPoissonSolver.h index 44bf05aca7449937087cb2a7c415721e9972b1fe..c2e1de9a9fe87dea819218f1b629574b29cd4234 100644 --- a/src/Solvers/MGPoissonSolver.h +++ b/src/Solvers/MGPoissonSolver.h @@ -125,8 +125,16 @@ public: void extrapolateLHS(); + void resizeMesh(Vector_t& origin, Vector_t& hr, const Vector_t& rmin, + const Vector_t& rmax, double dh) + { + bp_m->resizeMesh(origin, hr, rmin, rmax, dh); + } + Inform &print(Inform &os) const; + + private: bool isMatrixfilled_m; @@ -171,6 +179,7 @@ private: /// Map holding the processor distribution of data Teuchos::RCP<TpetraMap_t> map_p; + /// communicator used by Trilinos Teuchos::RCP<const Comm_t> comm_mp; diff --git a/src/Solvers/PoissonSolver.h b/src/Solvers/PoissonSolver.h index e2dd5a350b3ec2c1f8a9c2f65e07f8c9592891d6..84aa754cee851194d88d2da0b47501c89b172ed4 100644 --- a/src/Solvers/PoissonSolver.h +++ b/src/Solvers/PoissonSolver.h @@ -58,6 +58,11 @@ public: virtual void test(PartBunchBase<double, 3> *bunch) = 0 ; virtual ~PoissonSolver(){}; + virtual void resizeMesh(Vector_t& /*origin*/, Vector_t& /*hr*/, + const Vector_t& /*rmin*/, const Vector_t& /*rmax*/, + double /*dh*/) + { }; + }; inline Inform &operator<<(Inform &os, const PoissonSolver &/*fs*/) {