// // Class AmrPartBunch // This class is used to represent a bunch in AMR mode. // // Copyright (c) 2017 - 2019, Matthias Frey, Paul Scherrer Institut, Villigen PSI, Switzerland // All rights reserved // // Implemented as part of the PhD thesis // "Precise Simulations of Multibunches in High Intensity Cyclotrons" // // This file is part of OPAL. // // OPAL is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // You should have received a copy of the GNU General Public License // along with OPAL. If not, see . // #include "AmrPartBunch.h" #include "Utilities/OpalException.h" AmrPartBunch::AmrPartBunch(const PartData *ref) : PartBunchBase(new AmrPartBunch::pbase_t(new AmrLayout_t()), ref) , amrobj_mp(nullptr) , amrpbase_mp(dynamic_cast(pbase_m.get())) , fieldlayout_m(nullptr) { amrpbase_mp->initializeAmr(); } AmrPartBunch::AmrPartBunch(const PartData *ref, pbase_t* pbase_p) : PartBunchBase(new AmrPartBunch::pbase_t(new AmrLayout_t(&pbase_p->getAmrLayout())), ref) , amrobj_mp(nullptr) , amrpbase_mp(dynamic_cast(pbase_m.get())) , fieldlayout_m(nullptr) { amrpbase_mp->initializeAmr(); } AmrPartBunch::~AmrPartBunch() { } AmrPartBunch::pbase_t *AmrPartBunch::getAmrParticleBase() { return amrpbase_mp; } const AmrPartBunch::pbase_t *AmrPartBunch::getAmrParticleBase() const { return amrpbase_mp; } void AmrPartBunch::initialize(FieldLayout_t */*fLayout*/) { // Layout_t* layout = static_cast(&getLayout()); } void AmrPartBunch::do_binaryRepart() { if ( amrobj_mp && !amrobj_mp->isRefined() ) { /* In the first call to this function we * intialize all fine levels */ amrobj_mp->initFineLevels(); } else { bool isForbidTransform = amrpbase_mp->isForbidTransform(); if ( !isForbidTransform ) { /* * regrid in boosted frame */ this->updateLorentzFactor(); // Lorentz transform + mapping to [-1,1] amrpbase_mp->domainMapping(); amrpbase_mp->setForbidTransform(true); } this->update(); if ( !isForbidTransform ) { amrpbase_mp->setForbidTransform(false); // map particles back + undo Lorentz transform amrpbase_mp->domainMapping(true); } } } Vector_t AmrPartBunch::get_hr() const { const double& scalefactor = amrpbase_mp->getScalingFactor(); return hr_m * scalefactor; } void AmrPartBunch::set_meshEnlargement(double dh) { // set dh_m = dh PartBunchBase::set_meshEnlargement(dh); // update base geometry with new mesh enlargement AmrLayout_t* layout_p = &amrpbase_mp->getAmrLayout(); layout_p->setBoundingBox(dh); // if amrobj_mp != nullptr --> we need to regrid this->do_binaryRepart(); } AmrPartBunch::VectorPair_t AmrPartBunch::getEExtrema() { return amrobj_mp->getEExtrema(); } double AmrPartBunch::getRho(int x, int y, int z) { /* This function is called in * H5PartWrapperForPC::writeStepData(PartBunchBase* bunch) * and * H5PartWrapperForPT::writeStepData(PartBunchBase* bunch) * in case of Options::rhoDump = true. * * Currently, we do not support writing multilevel grid data that's why * we average the values down to the coarsest level. */ return amrobj_mp->getRho(x, y, z); } FieldLayout_t &AmrPartBunch::getFieldLayout() { //TODO Implement throw OpalException("AmrPartBunch::getFieldLayout() ", "Not yet Implemented."); return *fieldlayout_m; } void AmrPartBunch::boundp() { IpplTimings::startTimer(boundpTimer_m); //if(!R.isDirty() && stateOfLastBoundP_ == unit_state_) return; if ( !(R.isDirty() || ID.isDirty() ) && stateOfLastBoundP_ == unit_state_) return; //-DW stateOfLastBoundP_ = unit_state_; if ( amrobj_mp ) { /* we do an explicit domain mapping of the particles and then * forbid it during the regrid process, this way it's only * executed ones --> saves computation */ bool isForbidTransform = amrpbase_mp->isForbidTransform(); if ( !isForbidTransform ) { this->updateLorentzFactor(); // Lorentz transform + mapping to [-1,1] amrpbase_mp->domainMapping(); amrpbase_mp->setForbidTransform(true); } this->update(); if ( !isForbidTransform ) { amrpbase_mp->setForbidTransform(false); // map particles back + undo Lorentz transform amrpbase_mp->domainMapping(true); } } else { // At this point an amrobj_mp needs already be set throw GeneralClassicException("AmrPartBunch::boundp() ", "AmrObject pointer is not set."); } R.resetDirtyFlag(); IpplTimings::stopTimer(boundpTimer_m); } void AmrPartBunch::computeSelfFields() { IpplTimings::startTimer(selfFieldTimer_m); if ( !fs_m->hasValidSolver() ) throw OpalException("AmrPartBunch::computeSelfFields() ", "No field solver."); amrobj_mp->computeSelfFields(); IpplTimings::stopTimer(selfFieldTimer_m); } void AmrPartBunch::computeSelfFields(int bin) { IpplTimings::startTimer(selfFieldTimer_m); amrobj_mp->computeSelfFields(bin); IpplTimings::stopTimer(selfFieldTimer_m); } void AmrPartBunch::computeSelfFields_cycl(double gamma) { IpplTimings::startTimer(selfFieldTimer_m); amrobj_mp->computeSelfFields_cycl(gamma); IpplTimings::stopTimer(selfFieldTimer_m); } void AmrPartBunch::computeSelfFields_cycl(int bin) { IpplTimings::startTimer(selfFieldTimer_m); /* make sure it is refined in multi-bunch case */ if ( !amrobj_mp->isRefined() ) { amrobj_mp->initFineLevels(); } amrobj_mp->computeSelfFields_cycl(bin); IpplTimings::stopTimer(selfFieldTimer_m); } void AmrPartBunch::setAmrDomainRatio(const std::vector& ratio) { AmrLayout_t* layout_p = &amrpbase_mp->getAmrLayout(); layout_p->setDomainRatio(ratio); } void AmrPartBunch::gatherLevelStatistics() { int nLevel = amrobj_mp->maxLevel() + 1; std::unique_ptr partPerLevel( new size_t[nLevel] ); globalPartPerLevel_m.reset( new size_t[nLevel] ); for (int i = 0; i < nLevel; ++i) partPerLevel[i] = globalPartPerLevel_m[i] = 0.0; // do not modify LocalNumPerLevel in here!!! auto& LocalNumPerLevel = amrpbase_mp->getLocalNumPerLevel(); for (size_t i = 0; i < LocalNumPerLevel.size(); ++i) partPerLevel[i] = LocalNumPerLevel[i]; reduce(*partPerLevel.get(), *globalPartPerLevel_m.get(), nLevel, std::plus()); } const size_t& AmrPartBunch::getLevelStatistics(int l) const { return globalPartPerLevel_m[l]; } void AmrPartBunch::updateLorentzFactor(int bin) { double gamma = this->get_gamma(); if ( this->weHaveBins() ) { gamma = this->getBinGamma(bin); } /* At the beginning of simulation the Lorentz factor * is not yet set since PartBunchBase::calcBeamParameters * is not yet called. Therefore, we do this ugly workaround. */ bool init = true; if ( gamma >= 1.0 ) { init = false; } if ( init ) { gamma = 1.0; } updateLorentzFactor(gamma); } void AmrPartBunch::updateLorentzFactor(double gamma) { // keep all 1.0, except longitudinal direction Vector_t lorentzFactor(1.0, 1.0, 1.0); if (OpalData::getInstance()->isInOPALCyclMode()) { lorentzFactor[1] = gamma; } else { lorentzFactor[2] = gamma; } amrpbase_mp->setLorentzFactor(lorentzFactor); } void AmrPartBunch::updateFieldContainers_m() { } void AmrPartBunch::updateDomainLength(Vektor& grid) { grid = amrobj_mp->getBaseLevelGridPoints(); } void AmrPartBunch::updateFields(const Vector_t& /*hr*/, const Vector_t& /*origin*/) { //TODO regrid; called in boundp() // amrobj_mp->updateMesh(); }