diff --git a/src/PartBunch/CMakeLists.txt b/src/PartBunch/CMakeLists.txt index 9c9ec923fecb2316911022e4bb5e5113617f7322..6b3d5af74e7714d92957765575b3476781265581 100644 --- a/src/PartBunch/CMakeLists.txt +++ b/src/PartBunch/CMakeLists.txt @@ -1,5 +1,6 @@ set (_SRCS PartBunch.cpp + FieldSolver.cpp ) include_directories ( diff --git a/src/PartBunch/FieldSolver.cpp b/src/PartBunch/FieldSolver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ac359971108d4fe78f7ff14f4f208ddcf8d8a52b --- /dev/null +++ b/src/PartBunch/FieldSolver.cpp @@ -0,0 +1,145 @@ +#include "PartBunch/FieldSolver.hpp" + +template <> +void FieldSolver<double,3>::initOpenSolver() { + // if constexpr (Dim == 3) { + ippl::ParameterList sp; + sp.add("output_type", OpenSolver_t<double, 3>::GRAD); + sp.add("use_heffte_defaults", false); + sp.add("use_pencils", true); + sp.add("use_reorder", false); + sp.add("use_gpu_aware", true); + sp.add("comm", ippl::p2p_pl); + sp.add("r2c_direction", 0); + sp.add("algorithm", OpenSolver_t<double, 3>::HOCKNEY); + initSolverWithParams<OpenSolver_t<double, 3>>(sp); + // } else { + //throw std::runtime_error("Unsupported dimensionality for OPEN solver"); + //} +} + +template <> +void FieldSolver<double,3>::initSolver() { + Inform m; + if (this->getStype() == "FFT") { + initFFTSolver(); + } else if (this->getStype() == "CG") { + initCGSolver(); + } else if (this->getStype() == "P3M") { + initP3MSolver(); + } else if (this->getStype() == "FFTOPEN") { + initFFTSolver(); + } else if (this->getStype() == "NONE") { + initNullSolver(); + } + else { + m << "No solver matches the argument: " << this->getStype() << endl; + } +} + +template <> +void FieldSolver<double,3>::setPotentialBCs() { + // CG requires explicit periodic boundary conditions while the periodic Poisson solver + // simply assumes them + if (this->getStype() == "CG") { + typedef ippl::BConds<Field<double, 3>, 3> bc_type; + bc_type allPeriodic; + for (unsigned int i = 0; i < 2 * 3; ++i) { + allPeriodic[i] = std::make_shared<ippl::PeriodicFace<Field<double, 3>>>(i); + } + phi_m->setFieldBC(allPeriodic); + } + } + +template<> +void FieldSolver<double,3>::runSolver() { + Inform m("runSolver "); + constexpr int Dim = 3; + + m << "solver type= " << this->getStype() << endl; + + if (this->getStype() == "CG") { + CGSolver_t<double, 3>& solver = std::get<CGSolver_t<double, 3>>(this->getSolver()); + solver.solve(); + + if (ippl::Comm->rank() == 0) { + std::stringstream fname; + fname << "data/CG_"; + fname << ippl::Comm->size(); + fname << ".csv"; + + Inform log(NULL, fname.str().c_str(), Inform::APPEND); + int iterations = solver.getIterationCount(); + // Assume the dummy solve is the first call + if (iterations == 0) { + log << "residue,iterations" << endl; + } + // Don't print the dummy solve + if (iterations > 0) { + log << solver.getResidue() << "," << iterations << endl; + } + } + ippl::Comm->barrier(); + } else if (this->getStype() == "FFT") { + if constexpr (Dim == 2 || Dim == 3) { + std::get<FFTSolver_t<double, 3>>(this->getSolver()).solve(); + } + } else if (this->getStype() == "P3M") { + if constexpr (Dim == 3) { + std::get<P3MSolver_t<double, 3>>(this->getSolver()).solve(); + } + } else if (this->getStype() == "FFTOPEN") { + if constexpr (Dim == 3) { + m << " about to open.solve " << endl; + std::get<FFTSolver_t<double, 3>>(this->getSolver()).solve(); + m << " done open.solve " << endl; + } + } else { + throw std::runtime_error("Unknown solver type"); + } + + m << " done xx.solve() " << endl; +} + +/* +template<> +void FieldSolver<double,3>::initNullSolver() { + // if constexpr (Dim == 2 || Dim == 3) { + //ippl::ParameterList sp; + throw std::runtime_error("Not implemented Null solver"); + // } else { + //throw std::runtime_error("Unsupported dimensionality for Null solver"); + //} +} +*/ + +/* +template <> +void FieldSolver<double,3>::initCGSolver() { + ippl::ParameterList sp; + sp.add("output_type", CGSolver_t<double, 3>::GRAD); + // Increase tolerance in the 1D case + sp.add("tolerance", 1e-10); + + initSolverWithParams<CGSolver_t<double, 3>>(sp); +} + +template<> +void FieldSolver<double,3>::initP3MSolver() { + // if constexpr (Dim == 3) { + ippl::ParameterList sp; + sp.add("output_type", P3MSolver_t<double, 3>::GRAD); + sp.add("use_heffte_defaults", false); + sp.add("use_pencils", true); + sp.add("use_reorder", false); + sp.add("use_gpu_aware", true); + sp.add("comm", ippl::p2p_pl); + sp.add("r2c_direction", 0); + + initSolverWithParams<P3MSolver_t<double, 3>>(sp); + // } else { + // throw std::runtime_error("Unsupported dimensionality for P3M solver"); + // } +} + +*/ \ No newline at end of file diff --git a/src/PartBunch/FieldSolver.hpp b/src/PartBunch/FieldSolver.hpp index 2ff8dfa4b3d123adc460568a686db569085ccb71..7573fc2f296a188707bd9ec90d9ebe62ee364dc9 100644 --- a/src/PartBunch/FieldSolver.hpp +++ b/src/PartBunch/FieldSolver.hpp @@ -70,77 +70,14 @@ public: phi_m = phi; } - void initSolver() override { - Inform m("solver "); - if (this->getStype() == "FFT") { - initFFTSolver(); - } else if (this->getStype() == "CG") { - initCGSolver(); - } else if (this->getStype() == "P3M") { - initP3MSolver(); - } else if (this->getStype() == "OPEN") { - initOpenSolver(); - } else if (this->getStype() == "NONE") { - initNullSolver(); - } - else { - m << "No solver matches the argument: " << this->getStype() << endl; - } - } + void initOpenSolver(); - void setPotentialBCs() { - // CG requires explicit periodic boundary conditions while the periodic Poisson solver - // simply assumes them - if (this->getStype() == "CG") { - typedef ippl::BConds<Field<T, Dim>, Dim> bc_type; - bc_type allPeriodic; - for (unsigned int i = 0; i < 2 * Dim; ++i) { - allPeriodic[i] = std::make_shared<ippl::PeriodicFace<Field<T, Dim>>>(i); - } - phi_m->setFieldBC(allPeriodic); - } - } + void initSolver() override ; - void runSolver() override { - if (this->getStype() == "CG") { - CGSolver_t<T, Dim>& solver = std::get<CGSolver_t<T, Dim>>(this->getSolver()); - solver.solve(); - - if (ippl::Comm->rank() == 0) { - std::stringstream fname; - fname << "data/CG_"; - fname << ippl::Comm->size(); - fname << ".csv"; - - Inform log(NULL, fname.str().c_str(), Inform::APPEND); - int iterations = solver.getIterationCount(); - // Assume the dummy solve is the first call - if (iterations == 0) { - log << "residue,iterations" << endl; - } - // Don't print the dummy solve - if (iterations > 0) { - log << solver.getResidue() << "," << iterations << endl; - } - } - ippl::Comm->barrier(); - } else if (this->getStype() == "FFT") { - if constexpr (Dim == 2 || Dim == 3) { - std::get<FFTSolver_t<T, Dim>>(this->getSolver()).solve(); - } - } else if (this->getStype() == "P3M") { - if constexpr (Dim == 3) { - std::get<P3MSolver_t<T, Dim>>(this->getSolver()).solve(); - } - } else if (this->getStype() == "OPEN") { - if constexpr (Dim == 3) { - std::get<OpenSolver_t<T, Dim>>(this->getSolver()).solve(); - } - } else { - throw std::runtime_error("Unknown solver type"); - } - } + void setPotentialBCs(); + void runSolver() override; + template <typename Solver> void initSolverWithParams(const ippl::ParameterList& sp) { this->getSolver().template emplace<Solver>(); @@ -162,74 +99,23 @@ public: } } - void initNullSolver() { - if constexpr (Dim == 2 || Dim == 3) { - ippl::ParameterList sp; - throw std::runtime_error("Not implemented Null solver"); - } else { - throw std::runtime_error("Unsupported dimensionality for Null solver"); - } - } - + void initNullSolver() { } + void initFFTSolver() { - if constexpr (Dim == 2 || Dim == 3) { - ippl::ParameterList sp; - sp.add("output_type", FFTSolver_t<T, Dim>::GRAD); - sp.add("use_heffte_defaults", false); - sp.add("use_pencils", true); - sp.add("use_reorder", false); - sp.add("use_gpu_aware", true); - sp.add("comm", ippl::p2p_pl); - sp.add("r2c_direction", 0); - - initSolverWithParams<FFTSolver_t<T, Dim>>(sp); - } else { - throw std::runtime_error("Unsupported dimensionality for FFT solver"); - } + ippl::ParameterList sp; + sp.add("output_type", FFTSolver_t<double, 3>::GRAD); + sp.add("use_heffte_defaults", false); + sp.add("use_pencils", true); + sp.add("use_reorder", false); + sp.add("use_gpu_aware", true); + sp.add("comm", ippl::p2p_pl); + sp.add("r2c_direction", 0); + initSolverWithParams<FFTSolver_t<double, 3>>(sp); } + + void initCGSolver() { } - void initCGSolver() { - ippl::ParameterList sp; - sp.add("output_type", CGSolver_t<T, Dim>::GRAD); - // Increase tolerance in the 1D case - sp.add("tolerance", 1e-10); - - initSolverWithParams<CGSolver_t<T, Dim>>(sp); - } + void initP3MSolver() { } - void initP3MSolver() { - if constexpr (Dim == 3) { - ippl::ParameterList sp; - sp.add("output_type", P3MSolver_t<T, Dim>::GRAD); - sp.add("use_heffte_defaults", false); - sp.add("use_pencils", true); - sp.add("use_reorder", false); - sp.add("use_gpu_aware", true); - sp.add("comm", ippl::p2p_pl); - sp.add("r2c_direction", 0); - - initSolverWithParams<P3MSolver_t<T, Dim>>(sp); - } else { - throw std::runtime_error("Unsupported dimensionality for P3M solver"); - } - } - - void initOpenSolver() { - if constexpr (Dim == 3) { - ippl::ParameterList sp; - sp.add("output_type", OpenSolver_t<T, Dim>::GRAD); - sp.add("use_heffte_defaults", false); - sp.add("use_pencils", true); - sp.add("use_reorder", false); - sp.add("use_gpu_aware", true); - sp.add("comm", ippl::p2p_pl); - sp.add("r2c_direction", 0); - sp.add("algorithm", OpenSolver_t<T, Dim>::HOCKNEY); - - initSolverWithParams<OpenSolver_t<T, Dim>>(sp); - } else { - throw std::runtime_error("Unsupported dimensionality for OPEN solver"); - } - } }; #endif diff --git a/src/PartBunch/PartBunch.cpp b/src/PartBunch/PartBunch.cpp index 938fd2d8d7c14c39f4e29078212a482b2f3cb972..3229e3b986760a7c833924af0c02477e9fbebac3 100644 --- a/src/PartBunch/PartBunch.cpp +++ b/src/PartBunch/PartBunch.cpp @@ -2,6 +2,89 @@ #include <boost/numeric/ublas/io.hpp> #include "Utilities/Util.h" +template<> +void PartBunch<double,3>::setSolver(std::string solver) { + Inform m("setSolver "); + + if (this->solver_m != "") + m << "Warning solver already initiated but overwrite ..." << endl; + + this->solver_m = solver; + + this->fcontainer_m->initializeFields(this->solver_m); + + this->setFieldSolver(std::make_shared<FieldSolver_t>( + this->solver_m, &this->fcontainer_m->getRho(), &this->fcontainer_m->getE(), + &this->fcontainer_m->getPhi())); + + this->fsolver_m->initSolver(); + + + m << "Solver initialized" << endl; + + /// ADA we need to be able to set a load balancer when not having a field solver + this->setLoadBalancer(std::make_shared<LoadBalancer_t>( + this->lbt_m, this->fcontainer_m, this->pcontainer_m, this->fsolver_m)); + + m << "Load Balancer set" << endl; +} + +template<> +void PartBunch<double,3>::spaceChargeEFieldCheck() { + + Inform msg("EParticleStats"); + + auto pE_view = this->pcontainer_m->E.getView(); + + double avgE = 0.0; + double minEComponent = std::numeric_limits<double>::max(); + double maxEComponent = std::numeric_limits<double>::min(); + double minE = std::numeric_limits<double>::max(); + double maxE = std::numeric_limits<double>::min(); + double cc = getCouplingConstant(); + + int myRank = ippl::Comm->rank(); + Kokkos::parallel_reduce( + "check e-field", this->getLocalNum(), + KOKKOS_LAMBDA(const int i, double& loc_avgE, double& loc_minEComponent, + double& loc_maxEComponent, double& loc_minE, double& loc_maxE) { + double EX = pE_view[i][0]*cc; + double EY = pE_view[i][1]*cc; + double EZ = pE_view[i][2]*cc; + + double ENorm = Kokkos::sqrt(EX*EX + EY*EY + EZ*EZ); + + loc_avgE += ENorm; + + loc_minEComponent = EX < loc_minEComponent ? EX : loc_minEComponent; + loc_minEComponent = EY < loc_minEComponent ? EY : loc_minEComponent; + loc_minEComponent = EZ < loc_minEComponent ? EZ : loc_minEComponent; + + loc_maxEComponent = EX > loc_maxEComponent ? EX : loc_maxEComponent; + loc_maxEComponent = EY > loc_maxEComponent ? EY : loc_maxEComponent; + loc_maxEComponent = EZ > loc_maxEComponent ? EZ : loc_maxEComponent; + + loc_minE = ENorm < loc_minE ? ENorm : loc_minE; + loc_maxE = ENorm > loc_maxE ? ENorm : loc_maxE; + }, + Kokkos::Sum<double>(avgE), Kokkos::Min<double>(minEComponent), + Kokkos::Max<double>(maxEComponent), Kokkos::Min<double>(minE), + Kokkos::Max<double>(maxE)); + + MPI_Reduce(myRank == 0 ? MPI_IN_PLACE : &avgE, &avgE, 1, MPI_DOUBLE, MPI_SUM, 0, ippl::Comm->getCommunicator()); + MPI_Reduce(myRank == 0 ? MPI_IN_PLACE : &minEComponent, &minEComponent, 1, MPI_DOUBLE, MPI_MIN, 0, ippl::Comm->getCommunicator()); + MPI_Reduce(myRank == 0 ? MPI_IN_PLACE : &maxEComponent, &maxEComponent, 1, MPI_DOUBLE, MPI_MAX, 0, ippl::Comm->getCommunicator()); + MPI_Reduce(myRank == 0 ? MPI_IN_PLACE : &minE, &minE, 1, MPI_DOUBLE, MPI_MIN, 0, ippl::Comm->getCommunicator()); + MPI_Reduce(myRank == 0 ? MPI_IN_PLACE : &maxE, &maxE, 1, MPI_DOUBLE, MPI_MAX, 0, ippl::Comm->getCommunicator()); + + avgE /= this->getTotalNum(); + msg << "avgENorm = " << avgE << endl; + msg << "minEComponent = " << minEComponent << endl; + msg << "maxEComponent = " << maxEComponent << endl; + msg << "minE = " << minE << endl; + msg << "maxE = " << maxE << endl; +} + template<> void PartBunch<double,3>::calcBeamParameters() { // Usefull constants @@ -97,11 +180,24 @@ void PartBunch<double,3>::calcBeamParameters() { rmax_m(i) = rmax[i]; rmin_m(i) = rmin[i]; } - ippl::Comm->barrier(); + } +template<> +void PartBunch<double,3>::pre_run() { + Inform m("pre_run "); + + static IpplTimings::TimerRef DummySolveTimer = IpplTimings::getTimer("solveWarmup"); + IpplTimings::startTimer(DummySolveTimer); - } + m << " init rho" << endl; + this->fcontainer_m->getRho() = 0.0; + m << " init rho done " << endl; + + this->fsolver_m->runSolver(); + m << " solve done " << endl; + IpplTimings::stopTimer(DummySolveTimer); +} template<> Inform& PartBunch<double,3>::print(Inform& os) { @@ -285,9 +381,7 @@ void PartBunch<double,3>::computeSelfFields() { //divide charge by a 'grid-cube' volume to get [C/m^3] rho = rho *tmp2; - double Npoints = nr_m[0] * nr_m[1] * nr_m[2]; - // auto rhoView = rho.getView(); localDensity2 = 0.; ippl::parallel_reduce( "Density stats", ippl::getRangePolicy(rhoView), @@ -297,18 +391,22 @@ void PartBunch<double,3>::computeSelfFields() { }, Kokkos::Sum<double>(localDensity2) ); ippl::Comm->reduce(localDensity2, Density2, 1, std::plus<double>()); - + + double Npoints = nr_m[0] * nr_m[1] * nr_m[2]; rmsDensity_m = std::sqrt( (1.0 /Npoints) * Density2 / Physics::q_e / Physics::q_e ); this->calcDebyeLength(); m << "gammaz = " << gammaz << endl; m << "hr_scaled = " << hr_scaled << endl; - + m << "coupling constant= " << getCouplingConstant() << endl; + this->fsolver_m->runSolver(); gather(this->pcontainer_m->E, this->fcontainer_m->getE(), this->pcontainer_m->R); - + + spaceChargeEFieldCheck(); + IpplTimings::stopTimer(SolveTimer); } diff --git a/src/PartBunch/PartBunch.hpp b/src/PartBunch/PartBunch.hpp index 75a339f6b1e3032d5416bc19de3463d19464c1bb..c5a29e80de3365feec7ed7744826b4ffcd39215c 100644 --- a/src/PartBunch/PartBunch.hpp +++ b/src/PartBunch/PartBunch.hpp @@ -62,6 +62,14 @@ diagnostics(): calculate statistics and maybe write tp h5 and stat files #include "Algorithms/PartData.h" + +template <typename T> +KOKKOS_INLINE_FUNCTION typename T::value_type L2Norm(T& x) { + return sqrt(dot(x, x).apply()); +} + + + using view_type = typename ippl::detail::ViewType<ippl::Vector<double, 3>, 1>::view_type; @@ -276,11 +284,6 @@ public: IpplTimings::startTimer(prerun); pre_run(); IpplTimings::stopTimer(prerun); - - /* - end wrmup - */ - } void bunchUpdate(); @@ -294,39 +297,10 @@ public: return this->pcontainer_m; } - void setSolver(std::string solver) { - Inform m("setSolver "); - - if (this->solver_m != "") - m << "Warning solver already initiated but overwrite ..." << endl; - - this->solver_m = solver; - - this->fcontainer_m->initializeFields(this->solver_m); - - this->setFieldSolver(std::make_shared<FieldSolver_t>( - this->solver_m, &this->fcontainer_m->getRho(), &this->fcontainer_m->getE(), - &this->fcontainer_m->getPhi())); - - this->fsolver_m->initSolver(); - - /// ADA we need to be able to set a load balancer when not having a field solver - this->setLoadBalancer(std::make_shared<LoadBalancer_t>( - this->lbt_m, this->fcontainer_m, this->pcontainer_m, this->fsolver_m)); - } - - void pre_run() override { - static IpplTimings::TimerRef DummySolveTimer = IpplTimings::getTimer("solveWarmup"); - IpplTimings::startTimer(DummySolveTimer); - - this->fcontainer_m->getRho() = 0.0; - - this->fsolver_m->runSolver(); - - IpplTimings::stopTimer(DummySolveTimer); - - } + void setSolver(std::string solver); + void pre_run() override ; + public: void updateMoments(){ this->pcontainer_m->updateMoments(); @@ -383,10 +357,11 @@ public: */ double getCouplingConstant() const { - return 1.0; + return couplingConstant_m; } - + void setCouplingConstant(double c) { + couplingConstant_m = c; } void calcBeamParameters(); @@ -850,6 +825,10 @@ public: double calculateAngle(double x, double y) { return 0.0; } + + // Sanity check functions + void spaceChargeEFieldCheck(); + }; /* \todo