diff --git a/docs/source/usage/parameters.rst b/docs/source/usage/parameters.rst index cf4b025cc..e5eb977e0 100644 --- a/docs/source/usage/parameters.rst +++ b/docs/source/usage/parameters.rst @@ -92,7 +92,7 @@ These boxes also contain a field mesh, if space charge calculations are enabled. * ``geometry.dynamic_size`` (``boolean``) optional (default: ``true`` for dynamic) Use dynamic (``true``) resizing of the field mesh, via ``geometry.prob_relative``, or static sizing (``false``), via ``geometry.prob_lo``/``geometry.prob_hi``. -* ``geometry.prob_relative`` (positive ``float``, unitless) optional (default: ``3.0``) +* ``geometry.prob_relative`` (positive ``float`` array with ``amr.max_level`` entries, unitless) optional (default: ``3.0 1.0 1.0 ...``) By default, we dynamically extract the minimum and maximum of the particle positions in the beam. The field mesh spans, per direction, multiple times the maximum physical extent of beam particles, as given by this factor. The beam minimum and maximum extent are symmetrically padded by the mesh. diff --git a/docs/source/usage/python.rst b/docs/source/usage/python.rst index 77ee7419a..334c2c198 100644 --- a/docs/source/usage/python.rst +++ b/docs/source/usage/python.rst @@ -45,13 +45,15 @@ General .. py:property:: prob_relative + This is a list with ``amr.max_level`` + 1 entries. + By default, we dynamically extract the minimum and maximum of the particle positions in the beam. The field mesh spans, per direction, multiple times the maximum physical extent of beam particles, as given by this factor. The beam minimum and maximum extent are symmetrically padded by the mesh. For instance, ``1.2`` means the mesh will span 10% above and 10% below the beam; ``1.0`` means the beam is exactly covered with the mesh. - Default: ``3.0``. + Default: ``[3.0 1.0 1.0 ...]``. When set, turns ``dynamic_size`` to ``True``. .. py:property:: dynamic_size diff --git a/examples/cfchannel/run_cfchannel_10nC.py b/examples/cfchannel/run_cfchannel_10nC.py index 7965a26ca..bb5ce9b37 100755 --- a/examples/cfchannel/run_cfchannel_10nC.py +++ b/examples/cfchannel/run_cfchannel_10nC.py @@ -15,7 +15,7 @@ sim.n_cell = [48, 48, 40] # [72, 72, 64] for increased precision sim.particle_shape = 2 # B-spline order sim.space_charge = True -sim.prob_relative = 3.0 +sim.prob_relative = [3.0] # sim.diagnostics = False # benchmarking sim.slice_step_diagnostics = True diff --git a/examples/expanding_beam/README.rst b/examples/expanding_beam/README.rst index 8b0359645..abe830a56 100644 --- a/examples/expanding_beam/README.rst +++ b/examples/expanding_beam/README.rst @@ -14,6 +14,11 @@ expands to twice its original size. This is tested using the second moments of In this test, the initial and final values of :math:`\sigma_x`, :math:`\sigma_y`, :math:`\sigma_t`, :math:`\epsilon_x`, :math:`\epsilon_y`, and :math:`\epsilon_t` must agree with nominal values. +This test uses mesh-refinement to solve the space charge force. +The coarse grid wraps the beam maximum extent by 300%, emulating "open boundary" conditions. +The refined grid in level 1 spans 110% of the beam maximum extent. +The grid spacing is adaptively adjusted as the beam evolves. + Run --- diff --git a/examples/expanding_beam/input_expanding.in b/examples/expanding_beam/input_expanding.in index 23b5546b7..536cad6a1 100644 --- a/examples/expanding_beam/input_expanding.in +++ b/examples/expanding_beam/input_expanding.in @@ -34,5 +34,12 @@ monitor.backend = h5 algo.particle_shape = 2 algo.space_charge = true -amr.n_cell = 56 56 48 -geometry.prob_relative = 3.0 +# Space charge solver with one MR level +amr.max_level = 1 +amr.n_cell = 16 16 20 +geometry.prob_relative = 3.0 1.1 + +# Space charger solver without MR +#amr.max_level = 0 +#amr.n_cell = 56 56 48 +#geometry.prob_relative = 3.0 diff --git a/examples/expanding_beam/run_expanding.py b/examples/expanding_beam/run_expanding.py index cb0e303ef..3ae74dc01 100755 --- a/examples/expanding_beam/run_expanding.py +++ b/examples/expanding_beam/run_expanding.py @@ -9,14 +9,18 @@ import amrex.space3d as amr from impactx import ImpactX, RefPart, distribution, elements +pp_amr = amr.ParmParse("amr") +pp_amr.add("max_level", 1) + sim = ImpactX() # set numerical parameters and IO control -sim.n_cell = [56, 56, 48] +sim.n_cell = [16, 16, 20] +# sim.max_level = 1 # TODO: not yet implemented sim.particle_shape = 2 # B-spline order sim.space_charge = True sim.dynamic_size = True -sim.prob_relative = 3.0 +sim.prob_relative = [3.0, 1.1] # beam diagnostics # sim.diagnostics = False # benchmarking diff --git a/src/ImpactX.H b/src/ImpactX.H index b3c2dacac..3b98c1d2a 100644 --- a/src/ImpactX.H +++ b/src/ImpactX.H @@ -100,11 +100,13 @@ namespace impactx */ void init_warning_logger (); - private: //! Tag cells for refinement. TagBoxArray tags is built on level lev grids. - void ErrorEst (int lev, amrex::TagBoxArray& tags, amrex::Real time, - int ngrow) override; + void ErrorEst (int lev, + amrex::TagBoxArray& tags, + amrex::Real time, + int ngrow) override; + private: //! Make a new level from scratch using provided BoxArray and DistributionMapping. //! Only used during initialization. void MakeNewLevelFromScratch (int lev, amrex::Real time, const amrex::BoxArray& ba, diff --git a/src/ImpactX.cpp b/src/ImpactX.cpp index b6b0610d7..7e948c4f0 100644 --- a/src/ImpactX.cpp +++ b/src/ImpactX.cpp @@ -23,10 +23,12 @@ #include #include #include +#include #include #include #include +#include #include @@ -82,7 +84,6 @@ namespace impactx // init blocks / grids & MultiFabs AmrCore::InitFromScratch(0.0); - amrex::Print() << "boxArray(0) " << boxArray(0) << std::endl; // alloc particle containers // the lost particles have an extra runtime attribute: s when it was lost @@ -98,6 +99,12 @@ namespace impactx // register shortcut m_particle_container->SetLostParticleContainer(m_particles_lost.get()); + + // print AMReX grid summary + if (amrex::ParallelDescriptor::IOProcessor()) { + std::cout << "\nGrids Summary:\n"; + printGridSummary(std::cout, 0, finestLevel()); + } } void ImpactX::evolve () @@ -194,7 +201,7 @@ namespace impactx m_particle_container->DepositCharge(m_rho, this->refRatio()); // poisson solve in x,y,z - spacecharge::PoissonSolve(*m_particle_container, m_rho, m_phi); + spacecharge::PoissonSolve(*m_particle_container, m_rho, m_phi, this->ref_ratio); // calculate force in x,y,z spacecharge::ForceFromSelfFields(m_space_charge_field, diff --git a/src/initialization/InitAmrCore.cpp b/src/initialization/InitAmrCore.cpp index 18412dd2a..b42d9ac13 100644 --- a/src/initialization/InitAmrCore.cpp +++ b/src/initialization/InitAmrCore.cpp @@ -130,7 +130,12 @@ namespace details // Periodicity (none) amrex::Array const is_periodic{AMREX_D_DECL(0,0,0)}; - amrex::Geometry const geom(domain, rb, amrex::CoordSys::cartesian, is_periodic); - return {geom, amr_info}; + // Mesh-refinement + int max_level = 0; + pp_amr.query("max_level", max_level); + // amrex::AmrMesh::InitAmrMesh will query amr.ref_ratio or amr.ref_ratio_vect on its own + amrex::Vector const & ref_ratios = amrex::Vector(); + + return {rb, max_level, n_cell_v, amrex::CoordSys::cartesian, ref_ratios, is_periodic}; } } // namespace impactx::initialization diff --git a/src/initialization/InitMeshRefinement.cpp b/src/initialization/InitMeshRefinement.cpp index d9eef334e..2412c8d0f 100644 --- a/src/initialization/InitMeshRefinement.cpp +++ b/src/initialization/InitMeshRefinement.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -26,14 +27,128 @@ namespace impactx { - /** Tag cells for refinement. TagBoxArray tags is built on level lev grids. +namespace detail +{ + amrex::Vector + read_mr_prob_relative () + { + amrex::ParmParse pp_amr("amr"); + amrex::ParmParse pp_geometry("geometry"); + + int max_level = 0; + pp_amr.query("max_level", max_level); + + // The box is expanded beyond the min and max of the particle beam. + amrex::Vector prob_relative(max_level + 1, 1.0); + prob_relative[0] = 3.0; // top/bottom pad the beam on the lowest level by default by its width + pp_geometry.queryarr("prob_relative", prob_relative); + + if (prob_relative[0] < 3.0) + ablastr::warn_manager::WMRecordWarning( + "ImpactX::read_mr_prob_relative", + "Dynamic resizing of the mesh uses a geometry.prob_relative " + "padding of less than 3 for level 0. This might result in boundary " + "artifacts for space charge calculation. " + "There is no minimum good value for this parameter, consider " + "doing a convergence test.", + ablastr::warn_manager::WarnPriority::high + ); + + if (prob_relative[0] < 1.0) + throw std::runtime_error("geometry.prob_relative must be >= 1.0 (the beam size) on the coarsest level"); + + // check that prob_relative[0] > prob_relative[1] > prob_relative[2] ... + amrex::Real last_lev_rel = std::numeric_limits::max(); + for (int lev = 0; lev <= max_level; ++lev) { + amrex::Real const prob_relative_lvl = prob_relative[lev]; + if (prob_relative_lvl <= 0.0) + throw std::runtime_error("geometry.prob_relative must be strictly positive for all levels"); + if (prob_relative_lvl > last_lev_rel) + throw std::runtime_error("geometry.prob_relative must be descending over refinement levels"); + + last_lev_rel = prob_relative_lvl; + } + + return prob_relative; + } +} + /** Tag cells on level for refinement. * - * @todo this function is not (yet) implemented. + * @param lev the current level to refine + * @param tags the TagBoxArray tags are built on level lev grids + * @param time current simulation time, unused + * @param ngrow unused legacy argument that is always zero */ - void ImpactX::ErrorEst (int lev, amrex::TagBoxArray& tags, amrex::Real time, int ngrow) + void ImpactX::ErrorEst ( + int lev, + amrex::TagBoxArray& tags, + [[maybe_unused]] amrex::Real time, + [[maybe_unused]] int ngrow + ) { - // todo - amrex::ignore_unused(lev, tags, time, ngrow); + // level zero is of size in meters (per dimension): + // rb_0 = beam_width * prob_relative[lvl=0] + // level zero is of size in cells: + // nx_0 = amr.n_cell + // level one is of size in meters: + // rb_1 = beam_width * prob_relative[lvl=1] + // level one is of size in cells: + // nx_1 = amr.n_cell * rb_1 / rb_0 * amr.ref_ratio[lvl=0] + // = amr.n_cell * prob_relative[lvl=1] / prob_relative[lvl=0] * amr.ref_ratio[lvl=0] + // level one lowest/highest cell index to refine: + // ref_1_lo = nx_1 / nx_0 / 2 + // ref_1_hi = ref_1_lo + nx_1 + // ... + // level n is of size in cells: + // nx_n = amr.n_cell * rb_n / rb_0 * amr.ref_ratio[lvl=n-1] * amr.ref_ratio[lvl=n-2] * ... * amr.ref_ratio[lvl=0] + // = amr.n_cell * prob_relative[lvl=n] / prob_relative[lvl=0] * amr.ref_ratio[lvl=n-1] * amr.ref_ratio[lvl=n-2] * ... * amr.ref_ratio[lvl=0] + // = n_cell_{n-1} * prob_relative[lvl=n] / prob_relative[lvl=0] * amr.ref_ratio[lvl=n-1] + // level n+1 is of size in cells: + // nx_nup = n_cell_n * prob_relative[lvl=n+1] / prob_relative[lvl=0] * amr.ref_ratio[lvl=n] + // level n and n+1 have the following difference in cells, if coarsened to level n + // nx_n_diff = (nx_n - nx_nup / amr.ref_ratio[lvl=n]) + // level n lowest/highest cell index to refine: + // ref_n_lo = small_end_n + nx_n_diff / 2 + // ref_n_hi = big_end_n - nx_n_diff / 2 + + const auto dom = boxArray(lev).minimalBox(); // covered index space of the current level + auto const r_cell_n = amrex::RealVect(dom.size()); // on the current level + amrex::RealVect const r_ref_ratio = ref_ratio[lev]; + + // level width relative to beam width + amrex::Vector const prob_relative = detail::read_mr_prob_relative(); + + amrex::RealVect const n_cell_nup = amrex::RealVect(r_cell_n) * r_ref_ratio + * prob_relative[lev+1] / prob_relative[0]; + amrex::RealVect const n_cell_diff = (r_cell_n - n_cell_nup / r_ref_ratio); + + amrex::RealVect const r_fine_tag_lo = amrex::RealVect(dom.smallEnd()) + n_cell_diff / 2.0; + amrex::RealVect const r_fine_tag_hi = amrex::RealVect(dom.bigEnd()) - n_cell_diff / 2.0; + + amrex::IntVect const fine_tag_lo = { + AMREX_D_DECL((int)std::ceil(r_fine_tag_lo[0]), (int)std::ceil(r_fine_tag_lo[1]), (int)std::ceil(r_fine_tag_lo[2])) + }; + amrex::IntVect const fine_tag_hi = { + AMREX_D_DECL((int)std::ceil(r_fine_tag_hi[0]), (int)std::ceil(r_fine_tag_hi[1]), (int)std::ceil(r_fine_tag_hi[2])) + }; + + amrex::Box const fine_tag = {fine_tag_lo, fine_tag_hi}; + +#ifdef AMREX_USE_OMP +#pragma omp parallel if (amrex::Gpu::notInLaunchRegion()) +#endif + for (amrex::MFIter mfi(tags); mfi.isValid(); ++mfi) + { + const amrex::Box& bx = mfi.fabbox(); + const auto& fab = tags.array(mfi); + ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + amrex::IntVect const idx {AMREX_D_DECL(i, j, k)}; + if (fine_tag.contains(idx)) { + fab(i,j,k) = amrex::TagBox::SET; + } + }); + } } /** Make a new level from scratch using provided BoxArray and DistributionMapping. @@ -41,7 +156,7 @@ namespace impactx * Only used during initialization. */ void ImpactX::MakeNewLevelFromScratch (int lev, amrex::Real time, const amrex::BoxArray& ba, - const amrex::DistributionMapping& dm) + const amrex::DistributionMapping& dm) { amrex::ignore_unused(time); @@ -148,36 +263,27 @@ namespace impactx bool dynamic_size = true; pp_geometry.query("dynamic_size", dynamic_size); - amrex::RealBox rb; + amrex::Vector rb(this->finestLevel() + 1); // extent per level if (dynamic_size) { - // The box is expanded beyond the min and max of particles. - // This controlled by the variable `frac` below. - amrex::Real frac = 3.0; - pp_geometry.query("prob_relative", frac); - - if (frac < 3.0) - ablastr::warn_manager::WMRecordWarning( - "ImpactX::ResizeMesh", - "Dynamic resizing of the mesh uses a geometry.prob_relative " - "with less than 3x the beam size. This might result in boundary " - "artifacts for space charge calculation. " - "There is no minimum good value for this parameter, consider " - "doing a convergence test.", - ablastr::warn_manager::WarnPriority::high - ); - - if (frac < 1.0) - throw std::runtime_error("geometry.prob_relative must be >= 1.0 (the beam size) on the coarsest level"); + // The coarsest level is expanded (or reduced) relative the min and max of particles. + auto const prob_relative = detail::read_mr_prob_relative(); + amrex::Real const frac = prob_relative[0]; amrex::RealVect const beam_min(x_min, y_min, z_min); amrex::RealVect const beam_max(x_max, y_max, z_max); amrex::RealVect const beam_width(beam_max - beam_min); amrex::RealVect const beam_padding = beam_width * (frac - 1.0) / 2.0; // added to the beam extent --^ ^-- box half above/below the beam - rb.setLo(beam_min - beam_padding); - rb.setHi(beam_max + beam_padding); + + // In AMReX, all levels have the same problem domain, that of the + // coarsest level, even if only partly covered. + for (int lev = 0; lev <= this->finestLevel(); ++lev) + { + rb[lev].setLo(beam_min - beam_padding); + rb[lev].setHi(beam_max + beam_padding); + } } else { @@ -188,21 +294,28 @@ namespace impactx pp_geometry.getarr("prob_lo", prob_lo); pp_geometry.getarr("prob_hi", prob_hi); - rb = {prob_lo.data(), prob_hi.data()}; + rb[0] = {prob_lo.data(), prob_hi.data()}; + + if (this->max_level > 1) + amrex::Abort("Did not implement ResizeMesh for static domains and >1 MR levels."); } // updating geometry.prob_lo/hi for consistency - amrex::Vector const prob_lo = {rb.lo()[0], rb.lo()[1], rb.lo()[2]}; - amrex::Vector const prob_hi = {rb.hi()[0], rb.hi()[1], rb.hi()[2]}; + amrex::Vector const prob_lo = {rb[0].lo()[0], rb[0].lo()[1], rb[0].lo()[2]}; + amrex::Vector const prob_hi = {rb[0].hi()[0], rb[0].hi()[1], rb[0].hi()[2]}; pp_geometry.addarr("prob_lo", prob_lo); pp_geometry.addarr("prob_hi", prob_hi); // Resize the domain size - amrex::Geometry::ResetDefaultProbDomain(rb); - for (int lev = 0; lev <= this->max_level; ++lev) { + amrex::Geometry::ResetDefaultProbDomain(rb[0]); + + for (int lev = 0; lev <= this->finestLevel(); ++lev) + { amrex::Geometry g = Geom(lev); - g.ProbDomain(rb); - amrex::AmrMesh::SetGeometry(lev, g); + g.ProbDomain(rb[lev]); + SetGeometry(lev, g); + + m_particle_container->SetParticleGeometry(lev, g); } } } // namespace impactx diff --git a/src/particles/ChargeDeposition.cpp b/src/particles/ChargeDeposition.cpp index b51e06545..784f5dab5 100644 --- a/src/particles/ChargeDeposition.cpp +++ b/src/particles/ChargeDeposition.cpp @@ -9,6 +9,8 @@ */ #include "ImpactXParticleContainer.H" +#include +#include #include #include @@ -26,12 +28,17 @@ namespace impactx std::unordered_map & rho, amrex::Vector const & ref_ratio) { - // loop over refinement levels + using namespace amrex::literals; // for _rt and _prt + + // reset the values in rho to zero int const nLevel = this->finestLevel(); for (int lev = 0; lev <= nLevel; ++lev) { + rho.at(lev).setVal(0.); + } + + // loop fine-to-coarse over refinement levels + for (int lev = nLevel; lev >= 0; --lev) { amrex::MultiFab & rho_at_level = rho.at(lev); - // reset the values in rho to zero - rho_at_level.setVal(0.); // get simulation geometry information amrex::Geometry const & gm = this->Geom(lev); @@ -83,11 +90,89 @@ namespace impactx } } + // TODO: Call portion's of WarpX' SyncRho from fine to coarser levels + // TODO: do coarsening to a temp, local lev-1 patch + // TODO: start communicating this patch into rho_at_level_minus_1 + // note: this can either move parts from WarpXComm.cpp (SyncRho & AddRhoFromFineLevelandSumBoundary) + // or use code from SyncPhi in ABLASTR's PoissonSolve (in opposite order: FP->CP here) + // needed for solving the levels by levels: + // - coarser level is initial guess for finer level + // - coarser level provides boundary values for finer level patch + // Interpolation from phi[lev] to phi[lev+1] + // (This provides both the boundary conditions and initial guess for phi[lev+1]) + + if (lev > 0) { + // Allocate rho_cp with the same distribution map as lev + amrex::BoxArray ba = rho[lev].boxArray(); + const amrex::IntVect &refratio = ref_ratio[lev - 1]; + ba.coarsen(refratio); // index space is now coarsened + + // Number of guard cells to fill on coarse patch and number of components + const amrex::IntVect ngrow = (rho[lev].nGrowVect() + refratio - 1) / refratio; // round up int division + const int ncomp = 1; // rho is a scalar + amrex::MultiFab rho_cp(ba, rho[lev].DistributionMap(), ncomp, ngrow); + + // coarsen the data + ablastr::coarsen::average::Coarsen( + rho_cp, + rho[lev], + refratio + ); + + // add to the lower level + const amrex::Periodicity& crse_period = this->Geom(lev - 1).periodicity(); + + // On a coarse level, the data in mf_comm comes from the + // coarse patch of the fine level. They are unfiltered and uncommunicated. + // We need to add it to the fine patch of the current level. + amrex::MultiFab fine_lev_cp( + rho[lev-1].boxArray(), + rho[lev-1].DistributionMap(), + 1, + 0); + fine_lev_cp.setVal(0.0); + fine_lev_cp.ParallelAdd( + rho_cp, + 0, + 0, + 1, + rho_cp.nGrowVect(), + amrex::IntVect(0), + crse_period + ); + // We now need to create a mask to fix the double counting. + auto owner_mask = amrex::OwnerMask(fine_lev_cp, crse_period); + auto const& mma = owner_mask->const_arrays(); + auto const& sma = fine_lev_cp.const_arrays(); + auto const& dma = rho[lev-1].arrays(); + amrex::ParallelFor( + fine_lev_cp, + amrex::IntVect(0), + ncomp, + [=] AMREX_GPU_DEVICE (int bno, int i, int j, int k, int n) + { + if (mma[bno](i,j,k) && sma[bno](i,j,k,n) != 0.0_rt) { + dma[bno](i,j,k,n) += sma[bno](i,j,k,n); + } + } + ); + } // if (lev > 0) + + // charge filters + // note: we do this after SyncRho, because the physical (dx) size of + // the stencil is different for each level + // note: we might not be able to do this after SumBoundary because we would then + // not have valid filtered values in the guard. We access the guard + // when we sum contributions from particles close to the + // MR border between levels. + //ApplyFilterandSumBoundaryRho(lev, lev, rho[lev-1], 0, 1); + // start async charge communication for this level rho_at_level.SumBoundary_nowait(); //int const comp = 0; //rho_at_level.SumBoundary_nowait(comp, comp, rho_at_level.nGrowVect()); - } + + } // lev // finalize communication for (int lev = 0; lev <= nLevel; ++lev) diff --git a/src/particles/spacecharge/PoissonSolve.H b/src/particles/spacecharge/PoissonSolve.H index 4ab77021c..d6772f2a1 100644 --- a/src/particles/spacecharge/PoissonSolve.H +++ b/src/particles/spacecharge/PoissonSolve.H @@ -27,11 +27,13 @@ namespace impactx::spacecharge * @param[in] pc container of the particles that deposited rho * @param[in] rho charge per level * @param[inout] phi scalar potential per level + * @param[in] rel_ref_ratio mesh refinement ratio between levels */ void PoissonSolve ( ImpactXParticleContainer const & pc, std::unordered_map & rho, - std::unordered_map & phi + std::unordered_map & phi, + amrex::Vector rel_ref_ratio ); } // namespace impactx diff --git a/src/particles/spacecharge/PoissonSolve.cpp b/src/particles/spacecharge/PoissonSolve.cpp index 371f2a0bc..aedc6affe 100644 --- a/src/particles/spacecharge/PoissonSolve.cpp +++ b/src/particles/spacecharge/PoissonSolve.cpp @@ -26,7 +26,8 @@ namespace impactx::spacecharge void PoissonSolve ( ImpactXParticleContainer const & pc, std::unordered_map & rho, - std::unordered_map & phi + std::unordered_map & phi, + amrex::Vector rel_ref_ratio ) { using namespace amrex::literals; @@ -87,6 +88,7 @@ namespace impactx::spacecharge sorted_phi.emplace_back(&phi[lev]); } + const bool do_single_precision_comms = false; ablastr::fields::computePhi( sorted_rho, sorted_phi, @@ -98,10 +100,10 @@ namespace impactx::spacecharge pc.GetParGDB()->Geom(), pc.GetParGDB()->DistributionMap(), pc.GetParGDB()->boxArray(), - poisson_boundary_handler - /* + poisson_boundary_handler, do_single_precision_comms, - this->ref_ratio, + rel_ref_ratio + /* post_phi_calculation, gett_new(0), eb_farray_box_factory diff --git a/src/python/ImpactX.cpp b/src/python/ImpactX.cpp index c24b53118..e2537981a 100644 --- a/src/python/ImpactX.cpp +++ b/src/python/ImpactX.cpp @@ -43,6 +43,8 @@ namespace detail auto get_or_throw (std::string const & prefix, std::string const & name) { T value; + // TODO: if array do queryarr + // bool const has_name = amrex::ParmParse(prefix).queryarr(name.c_str(), value); bool const has_name = amrex::ParmParse(prefix).query(name.c_str(), value); if (!has_name) @@ -103,8 +105,17 @@ void init_ImpactX (py::module& m) ) // from amrex::AmrMesh - .def_property_readonly("max_level", + .def_property("max_level", [](ImpactX & ix){ return ix.maxLevel(); }, + [](ImpactX & /* ix */, int /* max_level */) { + throw std::runtime_error("setting n_cell is not yet implemented"); + /* + amrex::ParmParse pp_amr("amr"); + pp_amr.add("max_level", max_level); + */ + + // note, this must be done *before* initGrids is called + }, "The maximum mesh-refinement level for the simulation." ) .def_property_readonly("finest_level", @@ -141,9 +152,9 @@ void init_ImpactX (py::module& m) [](ImpactX & /* ix */) { return detail::get_or_throw("geometry", "prob_relative"); }, - [](ImpactX & /* ix */, amrex::Real frac) { + [](ImpactX & /* ix */, std::vector frac) { amrex::ParmParse pp_geometry("geometry"); - pp_geometry.add("prob_relative", frac); + pp_geometry.addarr("prob_relative", frac); }, "The field mesh spans, per direction, multiple times the maximum physical extent of beam particles, as given by this factor." )