diff --git a/src/Algorithms/CavityAutophaser.cpp b/src/Algorithms/CavityAutophaser.cpp index 9fa6b29ecacc0e848295ab56a1fcd8a27e7dc419..4c791f71400bc77f3267baced2efad76627cac83 100644 --- a/src/Algorithms/CavityAutophaser.cpp +++ b/src/Algorithms/CavityAutophaser.cpp @@ -72,7 +72,7 @@ double CavityAutophaser::getPhaseAtMaxEnergy(const Vector_t &R, << std::left << std::setw(68) << std::setfill('*') << ss.str() << std::setfill(' ') << endl); if (!apVeto) { - double initialEnergy = Util::getEnergy(P, itsReference_m.getM()) * 1e-6; + double initialEnergy = Util::getKineticEnergy(P, itsReference_m.getM()) * 1e-6; double AstraPhase = 0.0; double designEnergy = element->getDesignEnergy(); @@ -191,7 +191,7 @@ double CavityAutophaser::guessCavityPhase(double t) { return orig_phi; } - Phimax = element->getAutoPhaseEstimate(getEnergyMeV(refP), + Phimax = element->getAutoPhaseEstimate(Util::getKineticEnergy(refP, itsReference_m.getM()) * 1e-6, t, itsReference_m.getQ(), itsReference_m.getM() * 1e-6); @@ -288,7 +288,7 @@ double CavityAutophaser::track(Vector_t /*R*/, out); rfc->setPhasem(initialPhase); - double finalKineticEnergy = Util::getEnergy(Vector_t(0.0, 0.0, pe.first), itsReference_m.getM() * 1e-6); + double finalKineticEnergy = Util::getKineticEnergy(Vector_t(0.0, 0.0, pe.first), itsReference_m.getM() * 1e-6); return finalKineticEnergy; } \ No newline at end of file diff --git a/src/Algorithms/CavityAutophaser.h b/src/Algorithms/CavityAutophaser.h index 29db048b24349a39a7e9b93b5518d18aafc5571a..a4e49c8da834b0c8cd8d8010aea35439c4315403 100644 --- a/src/Algorithms/CavityAutophaser.h +++ b/src/Algorithms/CavityAutophaser.h @@ -28,8 +28,6 @@ private: const double dt, const double phase, std::ofstream *out = NULL) const; - double getEnergyMeV(const Vector_t &P); - double getMomentum(double kineticEnergyMeV); const PartData &itsReference_m; std::shared_ptr<Component> itsCavity_m; @@ -39,14 +37,4 @@ private: }; -inline -double CavityAutophaser::getEnergyMeV(const Vector_t &P) { - return itsReference_m.getM() * 1e-6 * (sqrt(dot(P,P) + 1) - 1); -} - -inline -double CavityAutophaser::getMomentum(double kineticEnergyMeV) { - return sqrt(std::pow(kineticEnergyMeV / (itsReference_m.getM() * 1e-6) + 1, 2) - 1); -} - #endif \ No newline at end of file diff --git a/src/Algorithms/ParallelTTracker.cpp b/src/Algorithms/ParallelTTracker.cpp index f38da15e80bd5e36a201c9a9637a7aeaee16c12c..23e2a6c2fdfb97e3d3d8cec97a629ab3756b0452 100644 --- a/src/Algorithms/ParallelTTracker.cpp +++ b/src/Algorithms/ParallelTTracker.cpp @@ -1162,7 +1162,7 @@ void ParallelTTracker::findStartPosition(const BorisPusher &pusher) { selectDT(); if ((back_track && itsOpalBeamline_m.containsSource()) || - Util::getEnergy(itsBunch_m->RefPartP_m, itsBunch_m->getM()) < 1e-3) { + Util::getKineticEnergy(itsBunch_m->RefPartP_m, itsBunch_m->getM()) < 1e-3) { double gamma = 0.1 / itsBunch_m->getM() + 1.0; double beta = sqrt(1.0 - 1.0 / std::pow(gamma, 2)); itsBunch_m->RefPartP_m = itsBunch_m->toLabTrafo_m.rotateTo(beta * gamma * Vector_t(0, 0, 1)); diff --git a/src/Classic/AbsBeamline/RFCavity.cpp b/src/Classic/AbsBeamline/RFCavity.cpp index b8ebb79459043ae993e9c3b3b05712ad5183e541..33cecafa90dc8f8fee454843f7be5d0b6e1894e3 100644 --- a/src/Classic/AbsBeamline/RFCavity.cpp +++ b/src/Classic/AbsBeamline/RFCavity.cpp @@ -494,22 +494,22 @@ ElementBase::ElementType RFCavity::getType() const { double RFCavity::getAutoPhaseEstimateFallback(double E0, double t0, double q, double mass) { const double dt = 1e-13; - const double p0 = Util::getP(E0, mass); + const double p0 = Util::getBetaGamma(E0, mass); const double origPhase =getPhasem(); double dphi = Physics::pi / 18; double phi = 0.0; setPhasem(phi); - std::pair<double, double> ret = trackOnAxisParticle(E0 / mass, t0, dt, q, mass); + std::pair<double, double> ret = trackOnAxisParticle(p0, t0, dt, q, mass); double phimax = 0.0; - double Emax = Util::getEnergy(Vector_t(0.0, 0.0, ret.first), mass); + double Emax = Util::getKineticEnergy(Vector_t(0.0, 0.0, ret.first), mass); phi += dphi; for (unsigned int j = 0; j < 2; ++ j) { for (unsigned int i = 0; i < 36; ++ i, phi += dphi) { setPhasem(phi); ret = trackOnAxisParticle(p0, t0, dt, q, mass); - double Ekin = Util::getEnergy(Vector_t(0.0, 0.0, ret.first), mass); + double Ekin = Util::getKineticEnergy(Vector_t(0.0, 0.0, ret.first), mass); if (Ekin > Emax) { Emax = Ekin; phimax = phi; @@ -635,7 +635,7 @@ double RFCavity::getAutoPhaseEstimate(const double &E0, const double &t0, const } double cosine_part = 0.0, sine_part = 0.0; - double p0 = std::sqrt((E0 / mass + 1) * (E0 / mass + 1) - 1); + double p0 = Util::getBetaGamma(E0, mass); cosine_part += scale_m * std::cos(frequency_m * t0) * F[0]; sine_part += scale_m * std::sin(frequency_m * t0) * F[0]; @@ -675,11 +675,11 @@ std::pair<double, double> RFCavity::trackOnAxisParticle(const double &p0, const double zend = length_m + startField_m; Vector_t z(0.0, 0.0, zbegin); - double dz = 0.5 * p(2) / std::sqrt(1.0 + dot(p, p)) * cdt; + double dz = 0.5 * p(2) / Util::getGamma(p) * cdt; Vector_t Ef(0.0), Bf(0.0); if (out) *out << std::setw(18) << z[2] - << std::setw(18) << Util::getEnergy(p, mass) + << std::setw(18) << Util::getKineticEnergy(p, mass) << std::endl; while (z(2) + dz < zend && z(2) + dz > zbegin) { z /= cdt; @@ -700,7 +700,7 @@ std::pair<double, double> RFCavity::trackOnAxisParticle(const double &p0, t += dt; if (out) *out << std::setw(18) << z[2] - << std::setw(18) << Util::getEnergy(p, mass) + << std::setw(18) << Util::getKineticEnergy(p, mass) << std::endl; } 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/Classic/Utilities/Util.h b/src/Classic/Utilities/Util.h index edf7178517c527c010c2bfcfd183278465f0fd1a..42479de4b024055ced8e0e5cc28a80a702a933e2 100644 --- a/src/Classic/Utilities/Util.h +++ b/src/Classic/Utilities/Util.h @@ -6,6 +6,7 @@ #include <string> #include <cstring> +#include <limits> #include <sstream> #include <type_traits> #include <functional> @@ -28,16 +29,23 @@ namespace Util { } inline - double getEnergy(Vector_t p, double mass) { + double getKineticEnergy(Vector_t p, double mass) { return (getGamma(p) - 1.0) * mass; } inline - double getP(double E, double mass) { - double gamma = E / mass + 1; - return std::sqrt(std::pow(gamma, 2.0) - 1.0); + double getBetaGamma(double Ekin, double mass) { + double value = std::sqrt(std::pow(Ekin / mass + 1.0, 2) - 1.0); + if (value < std::numeric_limits<double>::epsilon()) + value = std::sqrt(2 * Ekin / mass); + return value; } + inline + double convertMomentumeVToBetaGamma(double p, double mass) { + return p / mass; + } + inline std::string getTimeString(double time, unsigned int precision = 3) { std::string timeUnit(" [ps]"); @@ -162,7 +170,7 @@ namespace Util { } Vector_t getTaitBryantAngles(Quaternion rotation, const std::string &elementName = ""); - + std::string toUpper(const std::string &str); std::string combineFilePath(std::initializer_list<std::string>); diff --git a/src/Distribution/Distribution.cpp b/src/Distribution/Distribution.cpp index eddb76da941932e356999563f1aaa32b001ce506..744df64db31d2ac6f4f04aeedaea6926d611cce6 100644 --- a/src/Distribution/Distribution.cpp +++ b/src/Distribution/Distribution.cpp @@ -17,7 +17,6 @@ #include <string> #include <vector> #include <numeric> -#include <limits> // IPPL #include "DataSource/DataConnect.h" @@ -875,14 +874,6 @@ void Distribution::chooseInputMomentumUnits(InputMomentumUnitsT::InputMomentumUn } -double Distribution::converteVToBetaGamma(double valueIneV, double massIneV) { - double value = std::copysign(std::sqrt(std::pow(std::abs(valueIneV) / massIneV + 1.0, 2) - 1.0), valueIneV); - if (std::abs(value) < std::numeric_limits<double>::epsilon()) - value = std::copysign(std::sqrt(2 * std::abs(valueIneV) / massIneV), valueIneV); - - return value; -} - void Distribution::createDistributionBinomial(size_t numberOfParticles, double massIneV) { setDistParametersBinomial(massIneV); @@ -1069,9 +1060,9 @@ void Distribution::createDistributionFromFile(size_t /*numberOfParticles*/, doub saveProcessor = 0; if (inputMoUnits_m == InputMomentumUnitsT::EV) { - P(0) = converteVToBetaGamma(P(0), massIneV); - P(1) = converteVToBetaGamma(P(1), massIneV); - P(2) = converteVToBetaGamma(P(2), massIneV); + P(0) = Util::convertMomentumeVToBetaGamma(P(0), massIneV); + P(1) = Util::convertMomentumeVToBetaGamma(P(1), massIneV); + P(2) = Util::convertMomentumeVToBetaGamma(P(2), massIneV); } pmean_m += P; @@ -1422,7 +1413,7 @@ void Distribution::createOpalT(PartBunchBase<double, 3> *beam, // This is PC from BEAM double deltaP = Attributes::getReal(itsAttr[Attrib::Distribution::OFFSETP]); if (inputMoUnits_m == InputMomentumUnitsT::EV) { - deltaP = converteVToBetaGamma(deltaP, beam->getM()); + deltaP = Util::convertMomentumeVToBetaGamma(deltaP, beam->getM()); } avrgpz_m = beam->getP()/beam->getM() + deltaP; @@ -3650,9 +3641,9 @@ void Distribution::setSigmaP_m(double massIneV) { // Check what input units we are using for momentum. if (inputMoUnits_m == InputMomentumUnitsT::EV) { - sigmaP_m[0] = converteVToBetaGamma(sigmaP_m[0], massIneV); - sigmaP_m[1] = converteVToBetaGamma(sigmaP_m[1], massIneV); - sigmaP_m[2] = converteVToBetaGamma(sigmaP_m[2], massIneV); + sigmaP_m[0] = Util::convertMomentumeVToBetaGamma(sigmaP_m[0], massIneV); + sigmaP_m[1] = Util::convertMomentumeVToBetaGamma(sigmaP_m[1], massIneV); + sigmaP_m[2] = Util::convertMomentumeVToBetaGamma(sigmaP_m[2], massIneV); } } @@ -3985,14 +3976,14 @@ void Distribution::setupEmissionModel(PartBunchBase<double, 3> *beam) { void Distribution::setupEmissionModelAstra(PartBunchBase<double, 3> *beam) { double wThermal = std::abs(Attributes::getReal(itsAttr[Attrib::Distribution::EKIN])); - pTotThermal_m = converteVToBetaGamma(wThermal, beam->getM()); + pTotThermal_m = Util::getBetaGamma(wThermal, beam->getM()); pmean_m = Vector_t(0.0, 0.0, 0.5 * pTotThermal_m); } void Distribution::setupEmissionModelNone(PartBunchBase<double, 3> *beam) { double wThermal = std::abs(Attributes::getReal(itsAttr[Attrib::Distribution::EKIN])); - pTotThermal_m = converteVToBetaGamma(wThermal, beam->getM()); + pTotThermal_m = Util::getBetaGamma(wThermal, beam->getM()); double avgPz = std::accumulate(pzDist_m.begin(), pzDist_m.end(), 0.0); size_t numParticles = pzDist_m.size(); reduce(avgPz, avgPz, OpAddAssign()); @@ -4146,9 +4137,9 @@ void Distribution::shiftDistCoordinates(double massIneV) { // Check input momentum units. if (inputMoUnits_m == InputMomentumUnitsT::EV) { - deltaPx = converteVToBetaGamma(deltaPx, massIneV); - deltaPy = converteVToBetaGamma(deltaPy, massIneV); - deltaPz = converteVToBetaGamma(deltaPz, massIneV); + deltaPx = Util::convertMomentumeVToBetaGamma(deltaPx, massIneV); + deltaPy = Util::convertMomentumeVToBetaGamma(deltaPy, massIneV); + deltaPz = Util::convertMomentumeVToBetaGamma(deltaPz, massIneV); } size_t endIdx = startIdx + particlesPerDist_m[i]; @@ -4429,8 +4420,8 @@ void Distribution::adjustPhaseSpace(double massIneV) { double deltaPy = Attributes::getReal(itsAttr[Attrib::Distribution::OFFSETPY]); // Check input momentum units. if (inputMoUnits_m == InputMomentumUnitsT::EV) { - deltaPx = converteVToBetaGamma(deltaPx, massIneV); - deltaPy = converteVToBetaGamma(deltaPy, massIneV); + deltaPx = Util::convertMomentumeVToBetaGamma(deltaPx, massIneV); + deltaPy = Util::convertMomentumeVToBetaGamma(deltaPy, massIneV); } double avrg[6]; diff --git a/src/Distribution/Distribution.h b/src/Distribution/Distribution.h index 15e728fa666d756889d65ad9ddfa49ef0f5a030e..31817e3c968886ab2d141f20d0e3c6876441a383 100644 --- a/src/Distribution/Distribution.h +++ b/src/Distribution/Distribution.h @@ -292,7 +292,6 @@ private: void checkIfEmitted(); void checkParticleNumber(size_t &numberOfParticles); void chooseInputMomentumUnits(InputMomentumUnitsT::InputMomentumUnitsT inputMoUnits); - double converteVToBetaGamma(double valueIneV, double massIneV); size_t getNumberOfParticlesInFile(std::ifstream &inputFile); class BinomialBehaviorSplitter { diff --git a/src/Elements/OpalElement.cpp b/src/Elements/OpalElement.cpp index 63bf8b771bf9200523104f97bbb7684f2ca46d29..684fc18f62354414ef97a6bbe5bb05471f603e96 100644 --- a/src/Elements/OpalElement.cpp +++ b/src/Elements/OpalElement.cpp @@ -568,7 +568,8 @@ void OpalElement::update() { rotation = rotTheta * (rotPhi * rotPsi); } else { if (itsAttr[ORIENTATION]) { - throw OpalException("Line::parse","Parameter orientation is array of 3 values (theta, phi, psi);\n" + + throw OpalException("OpalElement::update", + "Parameter orientation is array of 3 values (theta, phi, psi);\n" + std::to_string(dir.size()) + " values provided"); } } @@ -577,7 +578,8 @@ void OpalElement::update() { origin = Vector_t(ori[0], ori[1], ori[2]); } else { if (itsAttr[ORIGIN]) { - throw OpalException("Line::parse","Parameter origin is array of 3 values (x, y, z);\n" + + throw OpalException("OpalElement::update", + "Parameter origin is array of 3 values (x, y, z);\n" + std::to_string(ori.size()) + " values provided"); } } diff --git a/src/Elements/OpalRBend.cpp b/src/Elements/OpalRBend.cpp index dec75dc88fd2a27239cc8538a2487d68a35b513b..0f1b9e0be8c28d849f5a493ee21c4a8839024680 100644 --- a/src/Elements/OpalRBend.cpp +++ b/src/Elements/OpalRBend.cpp @@ -24,7 +24,6 @@ #include "Structure/OpalWake.h" #include "Structure/ParticleMatterInteraction.h" #include "Utilities/OpalException.h" -#include <cmath> OpalRBend::OpalRBend(): OpalBend("RBEND", @@ -47,10 +46,8 @@ OpalRBend::OpalRBend(const std::string &name, OpalRBend *parent): OpalRBend::~OpalRBend() { - if(owk_m) - delete owk_m; - if(parmatint_m) - delete parmatint_m; + delete owk_m; + delete parmatint_m; } @@ -131,7 +128,7 @@ void OpalRBend::update() { double k0s = itsAttr[K0S] ? Attributes::getReal(itsAttr[K0S]) : 0.0; //JMJ 4/10/2000: above line replaced // length ? angle / length : angle; - // to avoid closed orbit created by RBEND with defalt K0. + // to avoid closed orbit created by RBEND with default K0. field.setNormalComponent(1, factor * k0); field.setSkewComponent(1, factor * Attributes::getReal(itsAttr[K0S])); field.setNormalComponent(2, factor * Attributes::getReal(itsAttr[K1])); @@ -177,8 +174,11 @@ void OpalRBend::update() { } // Energy in eV. - if(itsAttr[DESIGNENERGY]) { + if(itsAttr[DESIGNENERGY] && Attributes::getReal(itsAttr[DESIGNENERGY]) != 0.0) { bend->setDesignEnergy(Attributes::getReal(itsAttr[DESIGNENERGY]), false); + } else if (bend->getName() != "RBEND") { + throw OpalException("OpalRBend::update", + "RBend requires non-zero DESIGNENERGY"); } bend->setFullGap(Attributes::getReal(itsAttr[GAP])); diff --git a/src/Elements/OpalRBend3D.cpp b/src/Elements/OpalRBend3D.cpp index f64500bfddc8945e4520fc85fbce6fe40bdd9ad1..e1175d63fcd64bce123bf92242e2bd0dfbb925b3 100644 --- a/src/Elements/OpalRBend3D.cpp +++ b/src/Elements/OpalRBend3D.cpp @@ -72,10 +72,8 @@ OpalRBend3D::OpalRBend3D(const std::string &name, OpalRBend3D *parent): } OpalRBend3D::~OpalRBend3D() { - if(owk_m) - delete owk_m; - if(parmatint_m) - delete parmatint_m; + delete owk_m; + delete parmatint_m; } OpalRBend3D *OpalRBend3D::clone(const std::string &name) { @@ -130,8 +128,11 @@ void OpalRBend3D::update() { bend->setEntranceAngle(e1); // Energy in eV. - if(itsAttr[DESIGNENERGY]) { + if(itsAttr[DESIGNENERGY] && Attributes::getReal(itsAttr[DESIGNENERGY]) != 0.0) { bend->setDesignEnergy(Attributes::getReal(itsAttr[DESIGNENERGY]), false); + } else if (bend->getName() != "RBEND3D") { + throw OpalException("OpalRBend3D::update", + "RBend3D requires non-zero DESIGNENERGY"); } bend->setFullGap(Attributes::getReal(itsAttr[GAP])); diff --git a/src/Elements/OpalSBend.cpp b/src/Elements/OpalSBend.cpp index 785c1bf3d17951b734bc898323be340f58d297e2..2ec776a807aa5568bbd0e2005e294229f88bbb4a 100644 --- a/src/Elements/OpalSBend.cpp +++ b/src/Elements/OpalSBend.cpp @@ -24,7 +24,6 @@ #include "Structure/OpalWake.h" #include "Structure/ParticleMatterInteraction.h" #include "Utilities/OpalException.h" -#include <cmath> OpalSBend::OpalSBend(): OpalBend("SBEND", @@ -47,10 +46,8 @@ OpalSBend::OpalSBend(const std::string &name, OpalSBend *parent): OpalSBend::~OpalSBend() { - if(owk_m) - delete owk_m; - if(parmatint_m) - delete parmatint_m; + delete owk_m; + delete parmatint_m; } @@ -131,7 +128,7 @@ void OpalSBend::update() { double k0s = itsAttr[K0S] ? Attributes::getReal(itsAttr[K0S]) : 0.0; //JMJ 4/10/2000: above line replaced // length ? angle / length : angle; - // to avoid closed orbit created by SBEND with defalt K0. + // to avoid closed orbit created by SBEND with default K0. field.setNormalComponent(1, factor * k0); field.setSkewComponent(1, factor * Attributes::getReal(itsAttr[K0S])); field.setNormalComponent(2, factor * Attributes::getReal(itsAttr[K1])); @@ -163,11 +160,11 @@ void OpalSBend::update() { if(itsAttr[GREATERTHANPI]) throw OpalException("OpalSBend::update", - "GREATERTHANPI not supportet any more"); + "GREATERTHANPI not supported anymore"); if(itsAttr[ROTATION]) throw OpalException("OpalSBend::update", - "ROTATION not supportet any more; use PSI instead"); + "ROTATION not supported anymore; use PSI instead"); if(itsAttr[FMAPFN]) bend->setFieldMapFN(Attributes::getString(itsAttr[FMAPFN])); @@ -183,15 +180,18 @@ void OpalSBend::update() { bend->setExitAngle(e2); // Units are eV. - if(itsAttr[DESIGNENERGY]) { + if(itsAttr[DESIGNENERGY] && Attributes::getReal(itsAttr[DESIGNENERGY]) != 0.0) { bend->setDesignEnergy(Attributes::getReal(itsAttr[DESIGNENERGY]), false); + } else if (bend->getName() != "SBEND") { + throw OpalException("OpalSBend::update", + "SBend requires non-zero DESIGNENERGY"); } bend->setFullGap(Attributes::getReal(itsAttr[GAP])); if(itsAttr[APERT]) - throw OpalException("OpalRBend::fillRegisteredAttributes", - "APERTURE in RBEND not supported; use GAP and HAPERT instead"); + throw OpalException("OpalSBend::update", + "APERTURE in SBEND not supported; use GAP and HAPERT instead"); if(itsAttr[HAPERT]) { double hapert = Attributes::getReal(itsAttr[HAPERT]); 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*/) { diff --git a/tests/classic_src/Solvers/GreenWakeFunctionTest.cpp b/tests/classic_src/Solvers/GreenWakeFunctionTest.cpp index e6b4a98ddd711a46cac0ae49fd5612973f4bba94..b839e4d8009c6adc1e2a0670f7400b738bfe66c8 100644 --- a/tests/classic_src/Solvers/GreenWakeFunctionTest.cpp +++ b/tests/classic_src/Solvers/GreenWakeFunctionTest.cpp @@ -25,10 +25,10 @@ TEST(GreenWakeFunctionTest, TestApply) bool const_length = true; std::string fname = ""; - std::vector<double> finalWakeValues = {1.61757e+10, 2.78525e+19}; - std::vector<double> finalEnergyValues = {-0.00125303, -2.15739e+06}; + std::vector<double> finalWakeValues = { 1.61757e+10, 2.78525e+19}; + std::vector<double> finalEnergyValues = {-2.446072e-5, -42118.09}; std::vector<double> relativeErrorWake = {1e+6, 1e+15}; - std::vector<double> relativeErrorEnergy = {1e-7, 1e+2}; + std::vector<double> relativeErrorEnergy = {1e-9, 1}; for (int acmode : acmodes) { GreenWakeFunction gwf("opal", nullptr, filters, nbin, Z0, radius, sigma, acmode, tau, 0, const_length, fname); @@ -37,7 +37,7 @@ TEST(GreenWakeFunctionTest, TestApply) // determine K and charge double charge = 0.8e-9; // nC double K = 0.20536314319923724e-9; //K normalizes nC data in lambda.h? - gwf.NBin_m = 294; + gwf.NBin_m = 10; std::cout << "# Z0 = " << gwf.Z0_m << std::endl << "# radius = " << gwf.radius_m << std::endl