#include #include #include #include #include #include "cctk.h" #include "util_ErrorCodes.h" #include "util_Table.h" #include "bbox.hh" #include "data.hh" #include "defs.hh" #include "ggf.hh" #include "vect.hh" #include "carpet.hh" #include "interp.hh" namespace CarpetInterp { using namespace std; using namespace Carpet; typedef vect ivect; typedef vect rvect; typedef bbox ibbox; #define ind_rc(m,rl,c) ind_rc_(m,rl,minrl,maxrl,c,maxncomps,vhh) static inline int ind_rc_(int const m, int const rl, int const minrl, int const maxrl, int const c, int const maxncomps, vector const hh) { assert (m>=0 && m=minrl && rl=0 && maxrl<=hh.at(m)->reflevels()); assert (c>=0 && c=0 && maxncomps<=hh.at(m)->components(rl)); int const ind = (rl-minrl) * maxncomps + c; assert (ind>=0 && ind < (maxrl-minrl) * maxncomps); return ind; } #define ind_prc(p,m,rl,c) \ ind_prc_(p,nprocs,m,rl,minrl,maxrl,c,maxncomps,cgh,vhh) static inline int ind_prc_(int const p, int const nprocs, int const m, int const rl, int const minrl, int const maxrl, int const c, int const maxncomps, cGH const * const cgh, vector const hh) { assert (p>=0 && p=0 && m=minrl && rl=0 && maxrl<=hh.at(m)->reflevels()); assert (c>=0 && c=0 && maxncomps<=hh.at(m)->components(rl)); int const ind = (p * (maxrl-minrl) + (rl-minrl)) * maxncomps + c; assert (ind>=0 && ind < nprocs * (maxrl-minrl) * maxncomps); return ind; } void CarpetInterpStartup () { CCTK_OverloadInterpGridArrays (InterpGridArrays); } int InterpGridArrays (cGH const * const cgh, int const N_dims, int const local_interp_handle, int const param_table_handle, int const coord_system_handle, int const N_interp_points, int const interp_coords_type_code, void const * const interp_coords [], int const N_input_arrays, CCTK_INT const input_array_variable_indices [], int const N_output_arrays, CCTK_INT const output_array_type_codes [], void * const output_arrays []) { if (CCTK_IsFunctionAliased ("SymmetryInterpolate")) { return SymmetryInterpolate (cgh, N_dims, local_interp_handle, param_table_handle, coord_system_handle, N_interp_points, interp_coords_type_code, interp_coords, N_input_arrays, input_array_variable_indices, N_output_arrays, output_array_type_codes, output_arrays); } else { return Carpet_DriverInterpolate (cgh, N_dims, local_interp_handle, param_table_handle, coord_system_handle, N_interp_points, interp_coords_type_code, interp_coords, N_input_arrays, input_array_variable_indices, N_output_arrays, output_array_type_codes, output_arrays); } } extern "C" CCTK_INT Carpet_DriverInterpolate (CCTK_POINTER_TO_CONST const cgh_, CCTK_INT const N_dims, CCTK_INT const local_interp_handle, CCTK_INT const param_table_handle, CCTK_INT const coord_system_handle, CCTK_INT const N_interp_points, CCTK_INT const interp_coords_type_code, CCTK_POINTER_TO_CONST const interp_coords [], CCTK_INT const N_input_arrays, CCTK_INT const input_array_variable_indices [], CCTK_INT const N_output_arrays, CCTK_INT const output_array_type_codes [], CCTK_POINTER const output_arrays []) { cGH const * const cgh = static_cast (cgh_); int ierr; assert (cgh); assert (N_dims == dim); if (is_meta_mode()) { CCTK_WARN (0, "It is not possible to interpolate in meta mode"); } bool const want_global_mode = is_global_mode(); // Get some information MPI_Comm const comm = CarpetMPIComm (); int const myproc = CCTK_MyProc (cgh); int const nprocs = CCTK_nProcs (cgh); assert (myproc>=0 && myprocreflevels() : reflevel+1; // Multiple convergence levels are not supported assert (mglevels == 1); int const ml = 0; int maxncomps = 0; for (int rl=minrl; rlcomponents(rl)); } // Find the time interpolation order int partype; void const * const parptr = CCTK_ParameterGet ("prolongation_order_time", "Carpet", &partype); assert (parptr); assert (partype == PARAMETER_INTEGER); int const prolongation_order_time = * (CCTK_INT const *) parptr; CCTK_REAL const current_time = cgh->cctk_time / cgh->cctk_delta_time; vector interpolation_times (N_interp_points); bool interpolation_times_differ; ierr = Util_TableGetRealArray (param_table_handle, N_interp_points, &interpolation_times.front(), "interpolation_times"); if (ierr == UTIL_ERROR_TABLE_NO_SUCH_KEY) { for (int n=0; n time_deriv_order (N_interp_points); bool have_time_derivs; ierr = Util_TableGetIntArray (param_table_handle, N_interp_points, &time_deriv_order.front(), "time_deriv_order"); if (ierr == UTIL_ERROR_TABLE_NO_SUCH_KEY) { for (int n=0; nbaseextent; delta[d] = (upper[d] - lower[d]) / (baseext.upper()[d] - baseext.lower()[d]); } #else rvect const lower = rvect::ref(cgh->cctk_origin_space); rvect const delta = rvect::ref(cgh->cctk_delta_space) / maxreflevelfact; rvect const upper = lower + delta * (vhh.at(m)->baseextent.upper() - vhh.at(m)->baseextent.lower()); #endif assert (N_interp_points >= 0); assert (interp_coords); for (int d=0; d= 0); if (N_interp_points > 0) { assert (output_arrays); for (int j=0; j rlev (N_interp_points); // refinement level of point n vector home (N_interp_points); // component of point n vector homecnts ((maxrl-minrl) * maxncomps); // number of points in component c for (int n=0; n(interp_coords[d])[n]; } // Find the component that this grid point belongs to rlev.at(n) = -1; home.at(n) = -1; if (all(pos>=lower && pos<=upper)) { for (int rl=maxrl-1; rl>=minrl; --rl) { int const fact = maxreflevelfact / ipow(reffact, rl) * ipow(mgfact, mglevel); ivect const ipos = ivect(floor((pos - lower) / (delta * fact) + 0.5)) * fact; assert (all(ipos % vhh.at(m)->bases().at(rl).at(ml).stride() == 0)); // TODO: use something faster than a linear search for (int c=0; ccomponents(rl); ++c) { if (vhh.at(m)->extents().at(rl).at(c).at(ml).contains(ipos)) { rlev.at(n) = rl; home.at(n) = c; goto found; } } } } CCTK_VWarn (3, __LINE__, __FILE__, CCTK_THORNSTRING, "Interpolation point #%d at [%g,%g,%g] is not on any grid patch", n, pos[0], pos[1], pos[2]); // Map the point (arbitrarily) to the first component of the // coarsest grid rlev.at(n) = minrl; home.at(n) = 0; found: assert (rlev.at(n)>=minrl && rlev.at(n)=0 && home.at(n)components(rlev.at(n))); ++ homecnts.at(ind_rc(m, rlev.at(n), home.at(n))); } // for n // Communicate counts vector allhomecnts(nprocs * (maxrl-minrl) * maxncomps); MPI_Allgather (&homecnts .at(0), (maxrl-minrl) * maxncomps, MPI_INT, &allhomecnts.at(0), (maxrl-minrl) * maxncomps, MPI_INT, comm); // Create coordinate patches vector > allcoords (nprocs * (maxrl-minrl) * maxncomps); for (int p=0; pcomponents(rl); ++c) { ivect lo (0); ivect up (1); up[0] = allhomecnts.at(ind_prc(p,m,rl,c)); up[1] = dim; ivect str (1); ibbox extent (lo, up-str, str); allcoords.at(ind_prc(p,m,rl,c)).allocate (extent, p); } } } // Fill in local coordinate patches { vector tmpcnts ((maxrl-minrl) * maxncomps); for (int n=0; n=minrl && rl=0 && ccomponents(rl)); assert (tmpcnts.at(ind_rc(m,rl,c)) >= 0); assert (tmpcnts.at(ind_rc(m,rl,c)) < homecnts.at(ind_rc(m,rl,c))); assert (dim==3); for (int d=0; d(interp_coords[d])[n]; } ++ tmpcnts.at(c + (rl-minrl)*maxncomps); } for (int rl=minrl; rlcomponents(rl); ++c) { assert (tmpcnts.at(ind_rc(m,rl,c)) == homecnts.at(ind_rc(m,rl,c))); } } } // Transfer coordinate patches for (comm_state state; !state.done(); state.step()) { for (int p=0; pcomponents(rl); ++c) { allcoords.at(ind_prc(p,m,rl,c)).change_processor (state, vhh.at(m)->processors().at(rl).at(c)); } } } } // Create output patches vector > alloutputs (nprocs * (maxrl-minrl) * maxncomps, -1); vector > allstatuses (nprocs * (maxrl-minrl) * maxncomps, -1); for (int p=0; pcomponents(rl); ++c) { ivect const lo (0); ivect up (1); up[0] = allhomecnts.at(ind_prc(p,m,rl,c)); up[1] = N_output_arrays; ivect const str (1); ibbox const extent (lo, up-str, str); alloutputs.at(ind_prc(p,m,rl,c)).allocate (extent, vhh.at(m)->processors().at(rl).at(c)); ivect const slo (0); ivect sup (1); sup[0] = allhomecnts.at(ind_prc(p,m,rl,c)); ivect const sstr (1); ibbox const sextent (lo, up-str, str); allstatuses.at(ind_prc(p,m,rl,c)).allocate (sextent, vhh.at(m)->processors().at(rl).at(c)); } } } // // Do the local interpolation // int overall_ierr = 0; BEGIN_GLOBAL_MODE(cgh) { for (int rl=minrl; rl(cgh), rl); // Number of necessary time levels CCTK_REAL const level_time = cgh->cctk_time / cgh->cctk_delta_time; bool const need_time_interp = (interpolation_times_differ || have_time_derivs || (fabs(current_time - level_time) > 1e-12 * (fabs(level_time) + fabs(current_time) + fabs(cgh->cctk_delta_time)))); assert (! (! want_global_mode && ! interpolation_times_differ && ! have_time_derivs && need_time_interp)); int const num_tl = need_time_interp ? prolongation_order_time + 1 : 1; BEGIN_MAP_LOOP(cgh, CCTK_GF) { BEGIN_LOCAL_COMPONENT_LOOP(cgh, CCTK_GF) { // Find out about the local geometry ivect lsh; rvect coord_origin, coord_delta; for (int d=0; dcctk_lsh[d]; coord_delta[d] = cgh->cctk_delta_space[d] / cgh->cctk_levfac[d]; coord_origin[d] = cgh->cctk_origin_space[d] + (cgh->cctk_lbnd[d] + 1.0 * cgh->cctk_levoff[d] / cgh->cctk_levoffdenom[d]) * coord_delta[d]; } // Find out about the grid functions vector input_array_type_codes(N_input_arrays); vector input_arrays(N_input_arrays); for (int n=0; n=0 && vi=0 && gi tmp_interp_coords (dim); for (int d=0; d > tmp_output_arrays (num_tl); vector tmp_status_array (num_tl); for (int tl=0; tl=0 && vi=0 && gi=0); int my_num_tl; CCTK_INT interp_num_time_levels; int const ilen = Util_TableGetInt (table, &interp_num_time_levels, "InterpNumTimelevels"); if (ilen == UTIL_ERROR_TABLE_NO_SUCH_KEY) { my_num_tl = num_tl; } else if (ilen >= 0) { my_num_tl = interp_num_time_levels; assert (my_num_tl>0 && my_num_tl<=num_tl); } else { assert (0); } if (input_array_variable_indices[n] == -1) { input_arrays.at(n) = 0; } else if (tl >= my_num_tl) { // Do a dummy interpolation from a later timelevel int const vi = input_array_variable_indices[n]; assert (vi>=0 && vi=0 && vi= 0); ierr = CCTK_InterpLocalUniform (N_dims, local_interp_handle, param_table_handle, &coord_origin[0], &coord_delta[0], npoints, interp_coords_type_code, &tmp_interp_coords[0], N_input_arrays, &lsh[0], &input_array_type_codes[0], &input_arrays[0], N_output_arrays, output_array_type_codes, &tmp_output_arrays.at(tl)[0]); if (ierr) { CCTK_VWarn (4, __LINE__, __FILE__, CCTK_THORNSTRING, "The local interpolator returned the error code %d", ierr); } overall_ierr = min(overall_ierr, ierr); ierr = Util_TableDeleteKey (param_table_handle, "per_point_status"); assert (! ierr); } // for tl // Interpolate in time, if necessary if (need_time_interp) { for (int j=0; j operand_indices (N_output_arrays); ierr = Util_TableGetIntArray (param_table_handle, N_output_arrays, &operand_indices.front(), "operand_indices"); if (ierr == UTIL_ERROR_TABLE_NO_SUCH_KEY) { assert (N_output_arrays == N_input_arrays); for (int m=0; m=0 && vi=0 && gi=0); int my_num_tl; CCTK_INT interp_num_time_levels; int const ilen = Util_TableGetInt (table, &interp_num_time_levels, "InterpNumTimelevels"); if (ilen == UTIL_ERROR_TABLE_NO_SUCH_KEY) { my_num_tl = num_tl; } else if (ilen >= 0) { my_num_tl = interp_num_time_levels; assert (my_num_tl>0 && my_num_tl<=num_tl); } else { assert (0); } if (! interpolation_times_differ && ! have_time_derivs) { // Get interpolation times CCTK_REAL const time = current_time; vector times(my_num_tl); for (int tl=0; tltime (-tl, reflevel, mglevel); } // Calculate interpolation weights vector tfacs(my_num_tl); switch (my_num_tl) { case 1: // no interpolation // We have to assume that any GF with one timelevel // is constant in time!!! // assert (fabs((time - times.at(0)) / fabs(time + times.at(0) + cgh->cctk_delta_time)) < 1e-12); tfacs.at(0) = 1.0; break; case 2: // linear (2-point) interpolation tfacs.at(0) = (time - times.at(1)) / (times.at(0) - times.at(1)); tfacs.at(1) = (time - times.at(0)) / (times.at(1) - times.at(0)); break; case 3: // quadratic (3-point) interpolation tfacs.at(0) = (time - times.at(1)) * (time - times.at(2)) / ((times.at(0) - times.at(1)) * (times.at(0) - times.at(2))); tfacs.at(1) = (time - times.at(0)) * (time - times.at(2)) / ((times.at(1) - times.at(0)) * (times.at(1) - times.at(2))); tfacs.at(2) = (time - times.at(0)) * (time - times.at(1)) / ((times.at(2) - times.at(0)) * (times.at(2) - times.at(1))); break; default: assert (0); } // Interpolate assert (output_array_type_codes[j] == CCTK_VARIABLE_REAL); for (int k=0; k times(my_num_tl); for (int tl=0; tltime (-tl, reflevel, mglevel); } // Calculate interpolation weights vector tfacs(my_num_tl); switch (deriv_order) { case 0: switch (my_num_tl) { case 1: // no interpolation // We have to assume that any GF with one timelevel // is constant in time!!! // assert (fabs((time - times.at(0)) / fabs(time + times.at(0) + cgh->cctk_delta_time)) < 1e-12); tfacs.at(0) = 1.0; break; case 2: // linear (2-point) interpolation tfacs.at(0) = (time - times.at(1)) / (times.at(0) - times.at(1)); tfacs.at(1) = (time - times.at(0)) / (times.at(1) - times.at(0)); break; case 3: // quadratic (3-point) interpolation tfacs.at(0) = (time - times.at(1)) * (time - times.at(2)) / ((times.at(0) - times.at(1)) * (times.at(0) - times.at(2))); tfacs.at(1) = (time - times.at(0)) * (time - times.at(2)) / ((times.at(1) - times.at(0)) * (times.at(1) - times.at(2))); tfacs.at(2) = (time - times.at(0)) * (time - times.at(1)) / ((times.at(2) - times.at(0)) * (times.at(2) - times.at(1))); break; default: assert (0); } break; case 1: switch (my_num_tl) { case 2: // linear (2-point) interpolation // first order accurate tfacs.at(0) = (1 - times.at(1)) / (times.at(0) - times.at(1)); tfacs.at(1) = (1 - times.at(0)) / (times.at(1) - times.at(0)); break; case 3: // quadratic (3-point) interpolation // second order accurate tfacs.at(0) = ((1 - times.at(1)) * (time - times.at(2)) + (time - times.at(1)) * (1 - times.at(2))) / ((times.at(0) - times.at(1)) * (times.at(0) - times.at(2))); tfacs.at(1) = ((1 - times.at(0)) * (time - times.at(2)) + (time - times.at(0)) * (1 - times.at(2))) / ((times.at(1) - times.at(0)) * (times.at(1) - times.at(2))); tfacs.at(2) = ((1 - times.at(0)) * (time - times.at(1)) + (time - times.at(0)) * (1 - times.at(1))) / ((times.at(2) - times.at(0)) * (times.at(2) - times.at(1))); break; default: assert (0); } break; case 2: switch (my_num_tl) { case 3: // quadratic (3-point) interpolation // second order accurate tfacs.at(0) = 2 * (1 - times.at(1)) * (1 - times.at(2)) / ((times.at(0) - times.at(1)) * (times.at(0) - times.at(2))); tfacs.at(1) = 2 * (1 - times.at(0)) * (1 - times.at(2)) / ((times.at(1) - times.at(0)) * (times.at(1) - times.at(2))); tfacs.at(2) = 2 * (1 - times.at(0)) * (1 - times.at(1)) / ((times.at(2) - times.at(0)) * (times.at(2) - times.at(1))); break; default: assert (0); } break; default: assert (0); } // switch time_deriv_order CCTK_REAL & dest = alloutputs.at(ind_prc(p,m,reflevel,component))[ivect(k,j,0)]; dest = 0; for (int tl=0; tl(cgh)); } // for rl } END_GLOBAL_MODE; // Transfer output patches back for (comm_state state; !state.done(); state.step()) { for (int p=0; pcomponents(rl); ++c) { alloutputs.at(ind_prc(p,m,rl,c)).change_processor (state, p); allstatuses.at(ind_prc(p,m,rl,c)).change_processor (state, p); } } } } // Read out local output patches { vector tmpcnts ((maxrl-minrl) * maxncomps); CCTK_INT local_interpolator_status = 0; for (int n=0; n(output_arrays[j])[n] = alloutputs.at(ind_prc(myproc,m,rl,c))[ivect(tmpcnts.at(ind_rc(m,rl,c)),j,0)]; } local_interpolator_status = min (local_interpolator_status, allstatuses.at(ind_prc(myproc,m,rl,c))[ivect(tmpcnts.at(ind_rc(m,rl,c)),0,0)]); ++ tmpcnts.at(ind_rc(m,rl,c)); } for (int rl=minrl; rlcomponents(rl); ++c) { assert (tmpcnts.at(ind_rc(m,rl,c)) == homecnts.at(ind_rc(m,rl,c))); } } ierr = Util_TableSetInt (param_table_handle, local_interpolator_status, "local_interpolator_status"); assert (ierr >= 0); } int global_overall_ierr; MPI_Allreduce (&overall_ierr, &global_overall_ierr, 1, MPI_INT, MPI_MIN, comm); // Done. return global_overall_ierr; } } // namespace CarpetInterp