| 1167 | } |
| 1168 | |
| 1169 | void |
| 1170 | WarpX::SyncCurrent (const std::string& current_fp_string) |
| 1171 | { |
| 1172 | using ablastr::fields::Direction; |
| 1173 | |
| 1174 | ABLASTR_PROFILE("WarpX::SyncCurrent()"); |
| 1175 | |
| 1176 | bool const skip_lev0_coarse_patch = true; |
| 1177 | |
| 1178 | ablastr::fields::MultiLevelVectorField const& J_fp = m_fields.get_mr_levels_alldirs(current_fp_string, finest_level); |
| 1179 | |
| 1180 | // If warpx.do_current_centering = 1, center currents from nodal grid to staggered grid |
| 1181 | if (do_current_centering) |
| 1182 | { |
| 1183 | ablastr::fields::MultiLevelVectorField const& J_fp_nodal = m_fields.get_mr_levels_alldirs(FieldType::current_fp_nodal, finest_level); |
| 1184 | |
| 1185 | AMREX_ALWAYS_ASSERT_WITH_MESSAGE(finest_level <= 1, |
| 1186 | "warpx.do_current_centering=1 not supported with more than one fine levels"); |
| 1187 | for (int lev = 0; lev <= finest_level; lev++) |
| 1188 | { |
| 1189 | constexpr auto all_dirs = std::array{Direction{0}, Direction{1}, Direction{2}}; |
| 1190 | for (const auto& dir : all_dirs){ |
| 1191 | ::UpdateCurrentNodalToStag( |
| 1192 | *J_fp[lev][dir], *J_fp_nodal[lev][dir], |
| 1193 | m_current_centering_nox, m_current_centering_noy, m_current_centering_noz, |
| 1194 | device_current_centering_stencil_coeffs_x, |
| 1195 | device_current_centering_stencil_coeffs_y, |
| 1196 | device_current_centering_stencil_coeffs_z); |
| 1197 | } |
| 1198 | } |
| 1199 | } |
| 1200 | |
| 1201 | // If there is a single level, we apply the filter on the fp data and |
| 1202 | // then call SumBoundary that adds data from different boxes. This needs |
| 1203 | // to be done because a particle near a box boundary may deposit current |
| 1204 | // at a given (i,j,k) that is on the edge or in the ghost region of that |
| 1205 | // box while at the same time that (i,j,k) is also in the valid region |
| 1206 | // of another box. After SumBoundary, the result is as if there is only |
| 1207 | // a single box on a single process. Also note we need to call |
| 1208 | // SumBoundary even if there is only a single process, because a process |
| 1209 | // may have multiple boxes. Furthermore, even if there is only a single |
| 1210 | // box on a single process, SumBoundary should also be called if there |
| 1211 | // are periodic boundaries. So we always call SumBoundary even if it |
| 1212 | // might be a no-op in some cases, because the function does not perform |
| 1213 | // any communication if not necessary. |
| 1214 | // |
| 1215 | // When there are multiple levels, we need to send data from fine levels |
| 1216 | // to coarse levels. In the implementation below, we loop over levels |
| 1217 | // from the finest to the coarsest. On each level, filtering and |
| 1218 | // SumBoundary are done as the last two things. So the communication |
| 1219 | // data on the sender side are always unfiltered and unsummed. The |
| 1220 | // receivers are responsible for filtering that is dependent on the grid |
| 1221 | // resolution. On the finest level, we coarsen the unsummed fp data onto |
| 1222 | // cp grids, which are the coarsened version of the fp grids with the |
| 1223 | // same DistributionMapping. Then on the level below, We use ParallelAdd |
| 1224 | // to add the finer level's cp data onto the current level's fp |
| 1225 | // data. After that, we apply filter and SumBoundary to the finer |
| 1226 | // level's cp MultiFab. At this time, the finer level's fp and cp data |
no test coverage detected