diff options
Diffstat (limited to 'CarpetDev/CarpetIOF5/src/output.cc')
-rw-r--r-- | CarpetDev/CarpetIOF5/src/output.cc | 781 |
1 files changed, 491 insertions, 290 deletions
diff --git a/CarpetDev/CarpetIOF5/src/output.cc b/CarpetDev/CarpetIOF5/src/output.cc index 123c40524..b35d43775 100644 --- a/CarpetDev/CarpetIOF5/src/output.cc +++ b/CarpetDev/CarpetIOF5/src/output.cc @@ -39,18 +39,133 @@ namespace CarpetIOF5 { class output_iterator_t { - cGH *const cctkGH; + // Can't be cGH const, since the mode loops change change its + // entries + cGH* const cctkGH; + vector<bool> const output_var; // whether to output this variable + bool const output_everything; bool const is_multipatch; + int group_type; // CCTK_GF or CCTK_ARRAY + int group_index; // if group_type != CCTK_GF; else -1 + vector<int> vindices; // variable indices to output + string gridname; string chartname; - string fragmentname; string topologyname; + string fragmentname; + + + + struct map_indices_t { + int dim; + ivect gsh; + rvect origin, delta; + rvect lower, upper; + + map_indices_t (cGH const* const cctkGH, int const gindex) + { + DECLARE_CCTK_ARGUMENTS; + + if (gindex == -1) { + // grid function + dim = ::dim; + for (int d=0; d<(::dim); ++d) { + gsh[d] = cctk_gsh[d]; + origin[d] = CCTK_ORIGIN_SPACE(d); + delta[d] = CCTK_DELTA_SPACE(d); + } + } else { + // grid array + cGroupDynamicData dyndata; + int const ierr = CCTK_GroupDynamicData (cctkGH, gindex, &dyndata); + assert (not ierr); + // HDF5 and F5 can't handle dim=0 + dim = max(dyndata.dim, 1); + for (int d=0; d<dyndata.dim; ++d) { + gsh[d] = dyndata.gsh[d]; + origin[d] = 0.0; + delta[d] = 1.0; + } + for (int d=dyndata.dim; d<(::dim); ++d) { + gsh[d] = 1; + origin[d] = 0.0; + delta[d] = 1.0; + } + } + for (int d=0; d<(::dim); ++d) { + lower[d] = origin[d]; + upper[d] = lower[d] + (gsh[d]-1) * delta[d]; + } + } + }; + + struct component_indices_t: map_indices_t { + // elements >=dim remain undefined + ivect lbnd, lsh, lghosts, ughosts; + ivect imin, imax, ioff, ilen; + rvect clower, cupper; + + component_indices_t (cGH const* const cctkGH, int const gindex) + : map_indices_t(cctkGH, gindex) + { + DECLARE_CCTK_ARGUMENTS; + DECLARE_CCTK_PARAMETERS; + + if (gindex == -1) { + // grid function + for (int d=0; d<(::dim); ++d) { + lbnd[d] = cctk_lbnd[d]; + lsh[d] = cctk_lsh[d]; + lghosts[d] = cctk_bbox[2*d ] ? 0 : cctk_nghostzones[d]; + ughosts[d] = cctk_bbox[2*d+1] ? 0 : cctk_nghostzones[d]; + } + } else { + // grid array + cGroupDynamicData dyndata; + int const ierr = CCTK_GroupDynamicData (cctkGH, gindex, &dyndata); + assert (not ierr); + for (int d=0; d<dyndata.dim; ++d) { + lbnd[d] = dyndata.lbnd[d]; + lsh[d] = dyndata.lsh[d]; + lghosts[d] = dyndata.bbox[2*d ] ? 0 : dyndata.nghostzones[d]; + ughosts[d] = dyndata.bbox[2*d+1] ? 0 : dyndata.nghostzones[d]; + } + for (int d=dyndata.dim; d<(::dim); ++d) { + lbnd[d] = 0; + lsh[d] = 1; + lghosts[d] = 0; + ughosts[d] = 0; + } + } + for (int d=0; d<(::dim); ++d) { + imin[d] = 0; + imax[d] = lsh[d]; + if (not output_ghost_points) { + int const overlap = min(ughosts[d], minimum_component_overlap); + imin[d] += lghosts[d]; + imax[d] -= ughosts[d] - overlap; + lghosts[d] = 0; + ughosts[d] = overlap; + } + ioff[d] = lbnd[d] + imin[d]; + ilen[d] = imax[d] - imin[d]; + clower[d] = lower[d] + ioff[d] * delta[d]; + cupper[d] = clower[d] + (ilen[d]-1) * delta[d]; + } + } + }; + + public: - output_iterator_t (cGH *const cctkGH_) + output_iterator_t (cGH* const cctkGH_, + vector<bool> const& output_var_, + bool const output_everything_) : cctkGH(cctkGH_), + output_var(output_var_), + output_everything(output_everything_), is_multipatch (CCTK_IsFunctionAliased("MultiPatch_GetSystemSpecification")) { @@ -58,10 +173,40 @@ namespace CarpetIOF5 { void iterate (hid_t const file) { - int const rl = 0; - ENTER_LEVEL_MODE(cctkGH, rl) { + // Iterate over the variables in groups, first all grid + // functions, then all non-GF groups + group_type = CCTK_GF; + group_index = -1; + vindices.clear(); + for (int vindex=0; vindex<CCTK_NumVars(); ++vindex) { + if (output_var.at(vindex)) { + int const gindex = CCTK_GroupIndexFromVarI(vindex); + if (CCTK_GroupTypeI(gindex) == CCTK_GF) { + vindices.push_back (vindex); + } + } + } + if (not vindices.empty()) { output_simulation (file); - } LEAVE_LEVEL_MODE; + } + + group_type = CCTK_ARRAY; + for (group_index=0; group_index<CCTK_NumGroups(); ++group_index) { + if (CCTK_GroupTypeI(group_index) != CCTK_GF) { + vindices.clear(); + int const first_vindex = CCTK_FirstVarIndexI (group_index); + int const num_vars = CCTK_NumVarsInGroupI (group_index); + for (int vindex=first_vindex; vindex<first_vindex+num_vars; ++vindex) + { + if (output_var.at(vindex)) { + vindices.push_back (vindex); + } + } + if (not vindices.empty()) { + output_simulation (file); + } + } + } } @@ -70,65 +215,86 @@ namespace CarpetIOF5 { void output_simulation (hid_t const file) { - assert (is_level_mode() and reflevel==0); - DECLARE_CCTK_ARGUMENTS; + DECLARE_CCTK_PARAMETERS; indent_t indent; + bool error_flag = false; gridname = generate_gridname(cctkGH); - chartname = generate_chartname(cctkGH); - cout << indent << "simulation=" << gridname << "\n"; - ivect const reffact = spacereffacts.AT(reflevel); - F5Path *const globalpath = F5Rcreate_vertex_refinement3D - (file, cctk_time, gridname.c_str(), &v2h(reffact)[0], - chartname.c_str()); - - // Choose (arbitrarily) the root level as default topology, for - // readers which don't understand AMR - F5Rlink_default_vertex_topology (globalpath, &v2h(reffact)[0]); - - // Define iteration - F5Rset_timestep (globalpath, cctk_iteration); - - // Attach Cactus/Carpet metadata - write_metadata (cctkGH, globalpath->Grid_hid); - - // Close topology - F5close (globalpath); + assert (is_global_mode()); - // Iterate over all maps (on the root level) - BEGIN_MAP_LOOP(cctkGH, CCTK_GF) { - output_map (file); - } END_MAP_LOOP; - } - - - - void output_map (hid_t const file) - { - DECLARE_CCTK_ARGUMENTS; - indent_t indent; - - assert (is_singlemap_mode() and reflevel==0); - - cout << indent << "map=" << Carpet::map << "\n"; - - fragmentname = generate_fragmentname(cctkGH, Carpet::map); + chartname = generate_chartname(cctkGH); - // Iterate over all refinement levels of this map - int const m = Carpet::map; - BEGIN_GLOBAL_MODE(cctkGH) { - BEGIN_REFLEVEL_LOOP(cctkGH) { - if (vhh.AT(m)->local_components(reflevel) > 0) { - // Continue only if this process owns a component of this - // map (on this level) - ENTER_SINGLEMAP_MODE(cctkGH, m, CCTK_GF) { + int const max_rl = group_type == CCTK_GF ? reflevels : 1; + for (int rl=0; rl<max_rl; ++rl) { + // Continue only if this level exists at this iteration + assert (maxtimereflevelfact % timereffacts.AT(rl) == 0); + int const do_every = + group_type == CCTK_GF ? maxtimereflevelfact / timereffacts.AT(rl) : 1; + if (cctkGH->cctk_iteration % do_every == 0) { + ENTER_LEVEL_MODE(cctkGH, rl) { + DECLARE_CCTK_ARGUMENTS; + + assert (timelevel == 0); + int const max_tl = + output_everything or output_all_timelevels ? + (group_type == CCTK_GF ? + timelevels : + CCTK_NumTimeLevelsI(group_index)) : + 1; + for (timelevel=0; timelevel<max_tl; ++timelevel) { + cctkGH->cctk_time = tt->get_time (mglevel, reflevel, timelevel); + + // Choose (arbitrarily) the root level as default + // topology, for readers which don't understand AMR + if (reflevel == 0) { + ivect const reffact = spacereffacts.AT(reflevel); + F5Path *const globalpath = F5Rcreate_vertex_refinement3D + (file, cctk_time, gridname.c_str(), &v2h(reffact)[0], + chartname.c_str()); + assert (globalpath); + FAILWARN (F5Rlink_default_vertex_topology (globalpath, + &v2h(reffact)[0])); + + // Define iteration + FAILWARN (F5Rset_timestep (globalpath, cctk_iteration)); + + // Attach Cactus/Carpet metadata + if (timelevel == 0) { + // hid_t const metadata_group = globalpath->Grid_hid; + ostringstream pathname; + pathname << FIBER_CONTENT_GRIDS << "/" << gridname; + hid_t group; + group = H5Gopen (globalpath->ContentsGroup_hid, + pathname.str().c_str(), + H5P_DEFAULT); + if (group < 0) { + group = H5Gcreate (globalpath->ContentsGroup_hid, + pathname.str().c_str(), + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + assert (group >= 0); + write_metadata (cctkGH, group); + herr_t const herr = H5Gclose (group); + assert (not herr); + } + + // Close topology + F5close (globalpath); + + } // if reflevel==0 + output_reflevel (file); - } LEAVE_SINGLEMAP_MODE; - } - } END_REFLEVEL_LOOP; - } END_GLOBAL_MODE; + + } // for timelevel + timelevel = 0; + cctkGH->cctk_time = tt->get_time (mglevel, reflevel, timelevel); + + } LEAVE_LEVEL_MODE; + } // if do_every + } // for rl + } @@ -140,98 +306,120 @@ namespace CarpetIOF5 { cout << indent << "reflevel=" << reflevel << "\n"; + assert (is_level_mode()); + ivect const reffact = spacereffacts.AT(reflevel); - topologyname = generate_topologyname(cctkGH, Carpet::map, reffact); + topologyname = generate_topologyname(cctkGH, group_index, reffact); // Define grid hierarchy - int const indexdepth = 0; // vertices + map_indices_t const mi(cctkGH, group_index); + int const indexdepth = vhh.at(0)->refcent == vertex_centered ? 0 : 1; F5Path *const path = F5Rcreate_coordinate_topology (file, &cctk_time, gridname.c_str(), chartname.c_str(), topologyname.c_str(), indexdepth, - dim, dim, &v2h(reffact)[0]); + mi.dim, mi.dim, &v2h(reffact)[0]); + assert (path); - // Determine level coordinates - ivect gsh; - rvect origin, delta; - rvect lower, upper; - for (int d=0; d<dim; ++d) { - gsh[d] = cctk_gsh[d]; - origin[d] = CCTK_ORIGIN_SPACE(d); - delta[d] = CCTK_DELTA_SPACE(d); - lower[d] = origin[d]; - upper[d] = lower[d] + (gsh[d]-1) * delta[d]; - } + BEGIN_LOCAL_MAP_LOOP (cctkGH, CCTK_GF) { + output_map (path); + } END_LOCAL_MAP_LOOP; + + // Close topology + F5close (path); + } + + + + void output_map (F5Path *const path) + { + DECLARE_CCTK_ARGUMENTS; + indent_t indent; + bool error_flag = false; + + cout << indent << "map=" << Carpet::map << "\n"; + + assert (is_singlemap_mode()); if (not is_multipatch) { // Define level geometry - F5_vec3_double_t const vlower = v2d(lower); - F5_vec3_double_t const vupper = v2d(upper); - F5_vec3_double_t const vdelta = v2d(delta); - F5Fwrite_linear (path, FIBER_HDF5_POSITIONS_STRING, - dim, &v2h(gsh)[0], - F5T_COORD3_DOUBLE, - &vlower, &vdelta); - F5Fset_range (path, &vlower, &vupper); + map_indices_t const mi(cctkGH, group_index); + F5_vec3_double_t const vlower = v2d(mi.lower); + F5_vec3_double_t const vupper = v2d(mi.upper); + F5_vec3_double_t const vdelta = v2d(mi.delta); + static vector<ChartDomain_IDs*> charts; + if (charts.size() < dim+1) { + charts.resize(dim+1, NULL); + charts.at(3) = F5B_standard_cartesian_chart3D(); + } + if (not charts.at(mi.dim)) { + assert (mi.dim != 0); + char const* coordnames[] = {"x", "y", "z"}; + ostringstream chartnamebuf; + chartnamebuf << "Cartesian " << mi.dim << "D"; + charts.at(mi.dim) = + F5B_new_global_float_chart(coordnames, + mi.dim, chartnamebuf.str().c_str(), + F5_FORTRAN_ORDER); + assert (charts.at(mi.dim)); + } + hid_t const type = charts.at(mi.dim)->DoublePrecision.Point_hid_t; + FAILWARN (F5Fwrite_linear (path, FIBER_HDF5_POSITIONS_STRING, + mi.dim, &v2h(mi.gsh)[0], + type, + &vlower, &vdelta)); +#warning "TODO: path and chart don't match" + FAILWARN (F5Fset_range (path, &vlower, &vupper)); } BEGIN_LOCAL_COMPONENT_LOOP (cctkGH, CCTK_GF) { output_component (path); } END_LOCAL_COMPONENT_LOOP; - - // Close topology - F5close (path); } - - - + + + void output_component (F5Path *const path) { DECLARE_CCTK_ARGUMENTS; + DECLARE_CCTK_PARAMETERS; indent_t indent; + bool error_flag = false; - cout << indent << "component=" << component << "\n"; + cout << indent + << "component=" << component << " " + << "(local_component=" << local_component << ")\n"; - // Determine component coordinates - ivect gsh; - ivect lbnd, lsh, lghosts, ughosts; - rvect origin, delta; - rvect clower, cupper; - for (int d=0; d<dim; ++d) { - gsh[d] = cctk_gsh[d]; - lbnd[d] = cctk_lbnd[d]; - lsh[d] = cctk_lsh[d]; - // F5 counts the total overlap, which is the sum of the ghost - // zones on this and the adjacent component - lghosts[d] = cctk_bbox[2*d ] ? 0 : 2*cctk_nghostzones[d]; - ughosts[d] = cctk_bbox[2*d+1] ? 0 : 2*cctk_nghostzones[d]; - origin[d] = CCTK_ORIGIN_SPACE(d); - delta[d] = CCTK_DELTA_SPACE(d); - clower[d] = origin[d] + cctk_lbnd[d] * delta[d]; - cupper[d] = clower[d] + (lsh[d]-1) * delta[d]; - } + assert (is_local_mode()); + + fragmentname = generate_fragmentname(cctkGH, Carpet::map, component); // Define coordinates - if (not is_multipatch) { + // TODO: also define and use is_cartesian for each map + if (not is_multipatch and group_type == CCTK_GF) { // (This is redundant, since the level's overall bounding box // was already defined above, but it provides the individual // components' bounding boxes.) - F5Fwrite_linear_fraction (path, FIBER_HDF5_POSITIONS_STRING, - cctk_dim, &v2h(gsh)[0], &v2h(lsh)[0], - F5T_COORD3_DOUBLE, - &clower, &delta, &v2h(lbnd)[0], - fragmentname.c_str()); + component_indices_t const ci(cctkGH, group_index); + FAILWARN (F5Fwrite_linear_fraction (path, FIBER_HDF5_POSITIONS_STRING, + ci.dim, + &v2h(ci.gsh)[0], &v2h(ci.ilen)[0], + F5T_COORD3_DOUBLE, + &ci.clower, &ci.delta, + &v2h(ci.ioff)[0], + fragmentname.c_str())); } else { + // Output coordinates output_variable (path, CCTK_VarIndex("grid::x"), true); } - // Output some variables - output_variable (path, CCTK_VarIndex("grid::r")); - - output_variable (path, CCTK_VarIndex("grid::x")); - output_variable (path, CCTK_VarIndex("grid::y")); - output_variable (path, CCTK_VarIndex("grid::z")); + // Output variables + for (vector<int>::const_iterator + vi = vindices.begin(); vi != vindices.end(); ++vi) + { + output_variable (path, *vi); + } } @@ -242,13 +430,19 @@ namespace CarpetIOF5 { DECLARE_CCTK_ARGUMENTS; DECLARE_CCTK_PARAMETERS; indent_t indent; + bool error_flag = false; int ierr; assert (var >= 0); - { + if (write_positions) { + cout << indent << "positions\n"; + } else { char *const fullname = CCTK_FullName(var); - cout << indent << "variable=" << fullname << "\n"; + char *const groupname = CCTK_GroupNameFromVarI(var); + cout << indent + << "variable=" << fullname << " (group=" << groupname << ")\n"; + free (groupname); free (fullname); } @@ -259,49 +453,36 @@ namespace CarpetIOF5 { ierr = CCTK_GroupData (group, &groupdata); assert (not ierr); - // TODO - assert (groupdata.grouptype == CCTK_GF); - assert (groupdata.vartype == CCTK_VARIABLE_REAL); - assert (groupdata.disttype == CCTK_DISTRIB_DEFAULT); - assert (groupdata.stagtype == 0); - assert (groupdata.dim == cctk_dim); - - int const timelevel = 0; + assert ((groupdata.grouptype == CCTK_GF) == (group_type == CCTK_GF)); - // Determine component coordinates - int const dim = cctk_dim; - ivect gsh; - ivect lbnd, lsh, lghosts, ughosts; - ivect imin, imax, ioff, ilen; - ivect const izero(0); - for (int d=0; d<dim; ++d) { - gsh[d] = cctk_gsh[d]; - lbnd[d] = cctk_lbnd[d]; - lsh[d] = cctk_lsh[d]; - // F5 counts the total overlap, which is the sum of the ghost - // zones on this and the adjacent component - lghosts[d] = cctk_bbox[2*d ] ? 0 : 2*cctk_nghostzones[d]; - ughosts[d] = cctk_bbox[2*d+1] ? 0 : 2*cctk_nghostzones[d]; - imin[d] = 0; - imax[d] = lsh[d]; - if (not output_ghost_points) { - imin[d] += lghosts[d] / 2; - imax[d] -= ughosts[d] / 2; - lghosts[d] = 0; - ughosts[d] = 0; - } - ioff[d] = lbnd[d] + imin[d]; - ilen[d] = imax[d] - imin[d]; + // Output distrib=constant variables only on process 0 + switch (groupdata.disttype) { + case CCTK_DISTRIB_CONSTANT: + if (CCTK_MyProc(cctkGH) != 0) return; + break; + case CCTK_DISTRIB_DEFAULT: + // do nothing + break; + default: + assert (0); } + assert (groupdata.stagtype == 0); + assert (groupdata.dim == dim); + #warning "TODO: Do not output symmetry zones (unless requested by the user)" #warning "TODO: Do not output buffer zones (is that easily possible?)" + int const will_cover_complete_domain = not is_multipatch and reflevel==0; + + cGroupDynamicData dyndata; + ierr = CCTK_GroupDynamicData (cctkGH, group, &dyndata); + assert (not ierr); + + // Only output active timelevels + if (timelevel >= dyndata.activetimelevels) return; - enum tensortype_t { - tt_scalar, tt_vector, tt_error - }; tensortype_t tensortype = tt_error; @@ -327,6 +508,10 @@ namespace CarpetIOF5 { tensortype = tt_scalar; break; case 3: tensortype = tt_vector; break; + case 6: + tensortype = tt_symtensor; break; + case 9: + tensortype = tt_tensor; break; default: // fallback: output group as scalars tensortype = tt_scalar; break; @@ -337,129 +522,174 @@ namespace CarpetIOF5 { if (tensortype != tt_scalar and var != v0) { // TODO: don't do this; instead, keep track of which groups // have been output - char *const fullname = CCTK_FullName(var); - indent_t indent; - cout << indent << "skipping output since it is not the first variable in its group\n"; - free (fullname); + indent_t indent2; + cout << indent2 << "skipping output since it is not the first variable in its group\n"; return; } + hid_t type = -1; + int num_comps = 0; + string name; + switch (tensortype) { case tt_scalar: { // Scalar field - CCTK_REAL const *const rdata = - (CCTK_REAL const*)CCTK_VarDataPtrI (cctkGH, timelevel, var); - assert (rdata); + assert (not write_positions); + switch (groupdata.vartype) { + case CCTK_VARIABLE_INT: type = H5T_NATIVE_INT; break; + case CCTK_VARIABLE_REAL: type = H5T_NATIVE_DOUBLE; break; + default: assert(0); + } + num_comps = 1; + name = generate_fieldname (cctkGH, var, tensortype); + break; + } - int const vartype = CCTK_VarTypeI(var); - assert (vartype == CCTK_VARIABLE_REAL); - vector<CCTK_REAL> idata (prod(ilen)); - for (int k=0; k<ilen[2]; ++k) { - for (int j=0; j<ilen[1]; ++j) { - for (int i=0; i<ilen[0]; ++i) { - int const isrc = - CCTK_GFINDEX3D(cctkGH, imin[0]+i,imin[1]+j,imin[2]+k); - int const idst = i + ilen[0] * (j + ilen[1] * k); - idata[idst] = rdata[isrc]; + case tt_vector: { + // Vector field, or positions + switch (groupdata.vartype) { + case CCTK_VARIABLE_REAL: + type = write_positions ? F5T_COORD3_DOUBLE : F5T_VEC3_DOUBLE; + break; + default: assert(0); + } + num_comps = dim; + name = + write_positions ? + FIBER_HDF5_POSITIONS_STRING : + generate_fieldname (cctkGH, var, tensortype); + if (write_positions) { + htri_t const exists = + H5Lexists (path->Representation_hid, name.c_str(), H5P_DEFAULT); + assert (exists >= 0); + if (exists) { + string const fragmentpath = name + "/" + fragmentname; + htri_t const exists2 = + H5Lexists (path->Representation_hid, fragmentpath.c_str(), + H5P_DEFAULT); + assert (exists2 >= 0); + if (exists2) { + // Write positions only once + indent_t indent2; + cout << indent2 << "skipping output since the positions have already been output\n"; + return; } } } - void const *const data = &idata.front(); + break; + } - char *const groupname = CCTK_GroupName(group); - char *const fullname = CCTK_FullName(var); - // Use the variable name instead of the group name if we may - // output several variables per group + case tt_symtensor: { + // Symmetric tensor field assert (not write_positions); - char const *const name = groupdata.numvars == 1 ? groupname : fullname; -#if 0 - F5Fwrite_fraction (path, name, - dim, - is_multipatch ? NULL : &v2h(gsh)[0], &v2h(lsh)[0], - H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, - data, - &v2h(lbnd)[0], &v2h(lghosts)[0], &v2h(ughosts)[0], - fragmentname.c_str(), H5P_DEFAULT); -#endif - F5Fwrite_fraction (path, name, - dim, - is_multipatch ? NULL : &v2h(gsh)[0], &v2h(ilen)[0], - H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, - data, - &v2h(ioff)[0], &v2h(izero)[0], &v2h(izero)[0], - fragmentname.c_str(), H5P_DEFAULT); - free (groupname); - free (fullname); + switch (groupdata.vartype) { + case CCTK_VARIABLE_REAL: type = F5T_METRIC33_DOUBLE; break; + default: assert(0); + } + num_comps = dim*(dim+1)/2; + name = generate_fieldname (cctkGH, var, tensortype); break; } - case tt_vector: { - // Vector field - CCTK_REAL const* rdata[cctk_dim]; - vector<vector<CCTK_REAL> > idata(cctk_dim); - void const* data[cctk_dim]; - for (int d=0; d<cctk_dim; ++d) { - rdata[d] = - (CCTK_REAL const*)CCTK_VarDataPtrI (cctkGH, timelevel, v0+d); - assert (rdata[d]); - - int const vartype = CCTK_VarTypeI(var); - assert (vartype == CCTK_VARIABLE_REAL); - idata[d].resize (prod(ilen)); - for (int k=0; k<ilen[2]; ++k) { - for (int j=0; j<ilen[1]; ++j) { - for (int i=0; i<ilen[0]; ++i) { - int const isrc = - CCTK_GFINDEX3D(cctkGH, imin[0]+i,imin[1]+j,imin[2]+k); - int const idst = i + ilen[0] * (j + ilen[1] * k); - idata[d][idst] = rdata[d][isrc]; - } - } - } - data[d] = &idata[d].front(); - + case tt_tensor: { + // Non-symmetric tensor field + assert (not write_positions); + switch (groupdata.vartype) { + case CCTK_VARIABLE_REAL: type = F5T_BIVEC3_DOUBLE; break; + default: assert(0); } - char *const groupname = CCTK_GroupName(group); - char const *const name = - write_positions ? FIBER_HDF5_POSITIONS_STRING : groupname; - hid_t const type = - write_positions ? F5T_COORD3_DOUBLE : F5T_VEC3_DOUBLE; - int const will_cover_complete_domain = 0; -#if 0 - F5FSwrite_fraction (path, name, - dim, - is_multipatch ? NULL : &v2h(gsh)[0], &v2h(lsh)[0], - type, type, - data, - &v2h(lbnd)[0], &v2h(lghosts)[0], &v2h(ughosts)[0], - fragmentname.c_str(), H5P_DEFAULT, - will_cover_complete_domain); -#endif - F5FSwrite_fraction (path, name, - dim, - is_multipatch ? NULL : &v2h(gsh)[0], &v2h(ilen)[0], - type, type, - data, - &v2h(ioff)[0], &v2h(izero)[0], &v2h(izero)[0], - fragmentname.c_str(), H5P_DEFAULT, - will_cover_complete_domain); - free (groupname); + num_comps = dim*dim; + name = generate_fieldname (cctkGH, var, tensortype); break; } default: assert (0); } + + // Write data + assert (type >= 0); + assert (num_comps > 0); + assert (name.size() > 0); + + component_indices_t const ci(cctkGH, group_index); + + CCTK_REAL const* rdata[num_comps]; + vector<vector<CCTK_REAL> > idata(num_comps); + void const* data[num_comps]; + for (int d=0; d<num_comps; ++d) { + rdata[d] = (CCTK_REAL const*)CCTK_VarDataPtrI(cctkGH, timelevel, var+d); + assert (rdata[d]); + + int const vartype = CCTK_VarTypeI(var); + assert (vartype == CCTK_VARIABLE_REAL); + idata[d].resize (prod(ci.ilen)); + for (int k=0; k<ci.ilen[2]; ++k) { + for (int j=0; j<ci.ilen[1]; ++j) { + for (int i=0; i<ci.ilen[0]; ++i) { + int const isrc = + ci.imin[0]+i + ci.lsh[0] * + (ci.imin[1]+j + ci.lsh[1] * (ci.imin[2]+k)); + int const idst = i + ci.ilen[0] * (j + ci.ilen[1] * k); + idata[d][idst] = rdata[d][isrc]; + } + } + } + data[d] = &idata[d].front(); + } + + // Dataset properties + hid_t const prop = H5Pcreate (H5P_DATASET_CREATE); + assert (prop >= 0); + // Enable compression if requested + if (compression_level >= 0) { + FAILWARN (H5Pset_chunk (prop, dim, &v2h(ci.ilen).reverse()[0])); + FAILWARN (H5Pset_deflate (prop, compression_level)); + } + // Enable checksums if requested + if (use_checksums) { + FAILWARN (H5Pset_chunk (prop, dim, &v2h(ci.ilen).reverse()[0])); + FAILWARN (H5Pset_fletcher32 (prop)); + } + + if (num_comps == 1 and not separate_single_component_tensors) { + // Write single-component tensors into non-separated fractions + // for convenience (could also use a separated compound + // instead) + FAILWARN + (F5Fwrite_fraction (path, name.c_str(), + dim, + is_multipatch ? NULL : &v2h(ci.gsh)[0], + &v2h(ci.ilen)[0], + type, type, data[0], + &v2h(ci.ioff)[0], + &v2h(ci.lghosts)[0], &v2h(ci.ughosts)[0], + fragmentname.c_str(), prop)); + } else { + FAILWARN + (F5FSwrite_fraction (path, name.c_str(), + dim, + is_multipatch ? NULL : &v2h(ci.gsh)[0], + &v2h(ci.ilen)[0], + type, type, data, + &v2h(ci.ioff)[0], + &v2h(ci.lghosts)[0], &v2h(ci.ughosts)[0], + fragmentname.c_str(), prop, + will_cover_complete_domain)); + } + + FAILWARN (H5Pclose (prop)); + } }; // class output_iterator_t - void write_metadata (cGH *const cctkGH, hid_t const file) + void write_metadata (cGH const* const cctkGH, hid_t const file) { DECLARE_CCTK_PARAMETERS; @@ -475,6 +705,12 @@ namespace CarpetIOF5 { // files (to save space), or write it into a separate metadata // file + // Create metadata only once + // TODO: update metadata at some point + htri_t const exists = H5Lexists (file, metadata_group, H5P_DEFAULT); + assert (exists >= 0); + if (exists) return; + // Create a group to hold all metadata hid_t const group = H5Gcreate (file, metadata_group, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); @@ -501,10 +737,14 @@ namespace CarpetIOF5 { (group, "run id", (char const*) UniqueRunID(cctkGH)); } + // Don't write this attribute; the number of files may change + // after recovering, or after recombining files +#if 0 // Number of I/O processes (i.e. the number of output files) int const nprocs = CCTK_nProcs(cctkGH); int const nioprocs = nprocs; WriteAttribute (group, "nioprocs", nioprocs); +#endif // Write parameters into a separate dataset (they may be too large // for an attribute) @@ -524,53 +764,14 @@ namespace CarpetIOF5 { - extern "C" - void F5_Output (CCTK_ARGUMENTS) + void output (cGH const* const cctkGH, + hid_t const file, + vector<bool> const& output_var, + bool const output_everything) { - DECLARE_CCTK_ARGUMENTS; - DECLARE_CCTK_PARAMETERS; - - herr_t herr; - - - - assert (is_global_mode()); - CCTK_VInfo (CCTK_THORNSTRING, "F5_Output: iteration=%d", cctk_iteration); - - - - // We don't know how to open multiple files yet - assert (strcmp (file_content, "everything") == 0); - - // Open file - static bool first_time = true; - - string const basename = - generate_basename (cctkGH, CCTK_VarIndex("grid::r")); - int const myproc = CCTK_MyProc(cctkGH); - int const proc = myproc; - string const name = - create_filename (cctkGH, basename, proc, first_time); - - indent_t indent; - cout << indent << "process=" << proc << "\n"; - - bool const truncate_file = first_time and IO_TruncateOutputFiles(cctkGH); - hid_t const file = - truncate_file ? - H5Fcreate (name.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT) : - H5Fopen (name.c_str(), H5F_ACC_RDWR, H5P_DEFAULT); - assert (file >= 0); - first_time = false; - - // write_metadata (cctkGH, file); - - output_iterator_t iterator(cctkGH); + output_iterator_t + iterator(const_cast<cGH*>(cctkGH), output_var, output_everything); iterator.iterate (file); - - // Close file - herr = H5Fclose (file); - assert (not herr); } } // end namespace CarpetIOF5 |