diff --git a/src/io/new_dumpers/hdf5_file.hh b/src/io/new_dumpers/hdf5_file.hh index a4a14fc03..c50344aad 100644 --- a/src/io/new_dumpers/hdf5_file.hh +++ b/src/io/new_dumpers/hdf5_file.hh @@ -1,254 +1,306 @@ /** * @file dumper_hdf5.cc * * @author Nicolas Richart * * @date creation Tue Oct 03 2017 * * @brief Dump data in xdmf format * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_iterators.hh" #include "dumper_field.hh" #include "dumper_file_base.hh" #include "support.hh" /* -------------------------------------------------------------------------- */ #include #include #include #include #include /* -------------------------------------------------------------------------- */ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define ENDIANNESS(x) (x##LE) #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #define ENDIANNESS(x) (x##BE) #else #error "Does not know from which end to open the eggs" #endif namespace akantu { namespace dumper { namespace { #define TIDX(x) std::type_index(typeid(x)) hid_t datatype_id_out(const std::type_index & type_idx) { const static std::unordered_map type_ids{ {TIDX(int), sizeof(int) == 4 ? ENDIANNESS(H5T_STD_I32) : ENDIANNESS(H5T_STD_I64)}, {TIDX(unsigned int), sizeof(int) == 4 ? ENDIANNESS(H5T_STD_U32) : ENDIANNESS(H5T_STD_U64)}, {TIDX(int32_t), ENDIANNESS(H5T_STD_I32)}, {TIDX(int64_t), ENDIANNESS(H5T_STD_I64)}, {TIDX(uint32_t), ENDIANNESS(H5T_STD_U32)}, {TIDX(uint64_t), ENDIANNESS(H5T_STD_U64)}, {TIDX(bool), ENDIANNESS(H5T_STD_U8)}, {TIDX(float), ENDIANNESS(H5T_IEEE_F32)}, {TIDX(double), ENDIANNESS(H5T_IEEE_F64)}, }; return type_ids.at(type_idx); } hid_t datatype_id_in(const std::type_index & type_idx) { const static std::unordered_map type_ids{ {TIDX(int), H5T_NATIVE_INT}, {TIDX(unsigned int), H5T_NATIVE_UINT}, {TIDX(int32_t), H5T_NATIVE_INT32}, {TIDX(int64_t), H5T_NATIVE_INT64}, {TIDX(uint32_t), H5T_NATIVE_UINT32}, {TIDX(uint64_t), H5T_NATIVE_UINT64}, {TIDX(bool), H5T_NATIVE_CHAR}, {TIDX(float), H5T_NATIVE_FLOAT}, {TIDX(double), H5T_NATIVE_DOUBLE}, }; return type_ids.at(type_idx); } #undef TIDX } // namespace namespace HDF5 { namespace fs = boost::filesystem; - enum class EntityType { _group, _dataset, _file, _dataspace }; + enum class EntityType { _group, _dataset, _file, _dataspace, _link }; struct Entity { hid_t id; fs::path path; EntityType type; Entity(const fs::path & path, EntityType type) : path(path), type(std::move(type)) {} ~Entity() { switch (type) { case EntityType::_group: H5Gclose(id); break; case EntityType::_file: H5Fclose(id); break; case EntityType::_dataset: H5Dclose(id); break; case EntityType::_dataspace: H5Sclose(id); break; + case EntityType::_link: + break; } } }; class File : public FileBase { public: File(SupportBase & support, const fs::path & path) : FileBase(support) { auto path_wof = path; path_wof.remove_filename(); if (not fs::exists(path_wof)) { fs::create_directories(path_wof); } auto file = std::make_unique("/", EntityType::_file); file->id = H5Fcreate(path.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); support.addProperty("hdf5_file", path.string()); entities.push_back(std::move(file)); /* Turn off error handling */ H5Eset_auto(H5E_DEFAULT, NULL, NULL); } ~File() override = default; protected: auto & openGroup(const std::string & path) { auto & group = *entities.back(); auto && new_group = std::make_unique(group.path, EntityType::_group); new_group->path /= path; auto status = H5Oexists_by_name(group.id, new_group->path.c_str(), H5P_DEFAULT); if (status <= 0) { AKANTU_DEBUG_INFO("DumperHDF5: creating group " << path); new_group->id = H5Gcreate(group.id, new_group->path.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); } else { AKANTU_DEBUG_INFO("DumperHDF5: opening group " << path << " in " << group.path); new_group->id = H5Gopen(group.id, new_group->path.c_str(), H5P_DEFAULT); } entities.push_back(std::move(new_group)); return *entities.back(); } + auto & createSymlink(const std::string & path, const std::string & link) { + auto & group = *entities.back(); + + auto && new_link = + std::make_unique(group.path, EntityType::_link); + new_link->path /= path; + + auto status = + H5Lcreate_soft(link.c_str(), group.id, new_link->path.c_str(), + H5P_DEFAULT, H5P_DEFAULT); + + AKANTU_DEBUG_ASSERT(status >= 0, "Could not create HDF5 link " + << new_link->path.c_str() << " -> " + << link.c_str() + << ", status=" << status); + + entities.push_back(std::move(new_link)); + return *entities.back(); + } + protected: void dump(FieldArrayBase & field) override { auto & group = *entities.back(); auto data_set = std::make_unique(group.path, EntityType::_dataset); data_set->path /= field.getName(); auto status = H5Oexists_by_name(group.id, data_set->path.c_str(), H5P_DEFAULT); decltype(data_set) data_space; if (status <= 0) { hsize_t dims[2]; dims[0] = field.size(); dims[1] = field.getNbComponent(); data_space = std::make_unique("", EntityType::_dataspace); data_space->id = H5Screate_simple(2, dims, NULL); AKANTU_DEBUG_INFO("DumperHDF5: creating dataset " << field.getName() << " in " << group.path.generic_string()); data_set->id = H5Dcreate( group.id, data_set->path.c_str(), datatype_id_out(field.type()), data_space->id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); field.addProperty("hdf5_path", data_set->path.generic_string()); } else { AKANTU_DEBUG_INFO("HDF5: opening existing dataset " << data_set->path); data_set->id = H5Dopen(group.id, data_set->path.c_str(), H5P_DEFAULT); } AKANTU_DEBUG_INFO("HDF5: writing dataset " << data_set->path); H5Dwrite(data_set->id, datatype_id_in(field.type()), H5S_ALL, H5S_ALL, H5P_DEFAULT, field.data()); } void dump(FieldElementMapArrayBase & field) override { auto & group = openGroup(field.getName()); field.addProperty("hdf5_path", group.path.generic_string()); for (auto && type : field.elementTypes()) { dump(field.array(type)); } entities.pop_back(); } void dump(Support & support) override { + if (support.hasProperty("hdf5_release") and + support.getRelease() == support.getProperty("hdf5_release")) { + auto & link = createSymlink( + support.getName(), support.getProperty("hdf5_path")); + entities.pop_back(); + } + auto & group = openGroup(support.getName()); support.addProperty("hdf5_path", group.path.generic_string()); openGroup("nodes"); auto && nodes = support.getNodes(); dump(nodes); entities.pop_back(); auto && connectivities = support.getConnectivities(); dump(connectivities); + support.addProperty("hdf5_release", support.getRelease()); + // auto && data_grp = Group(loc_id, path_ + "/data"); openGroup("groups"); for (auto && support : support.getSubSupports()) { dump(*support.second); } + + // groups + entities.pop_back(); + + // mesh entities.pop_back(); } void dump(Support & support) override { const auto & parent_support = support.getParentSupport(); auto & group = openGroup(support.getName()); support.addProperty("hdf5_path", group.path.generic_string()); support.addProperty( "hdf5_file", parent_support.getProperty("hdf5_file")); dump(support.getElements()); entities.pop_back(); } void dump(SupportBase & support) override { FileBase::dump(support); } + void dump() override { + auto & group = openGroup("steps"); + + if (support.hasProperty("time")) { + auto & group = + openGroup(std::to_string(support.getProperty("time"))); + } + + FileBase::dump(support); + + if (support.hasProperty("time")) { + entities.pop_back(); + } + entities.pop_back(); + } + private: std::vector> entities; }; } // namespace HDF5 } // namespace dumper } // namespace akantu diff --git a/src/io/new_dumpers/xdmf_file.hh b/src/io/new_dumpers/xdmf_file.hh index c2a6aa545..1b2e7b2d4 100644 --- a/src/io/new_dumpers/xdmf_file.hh +++ b/src/io/new_dumpers/xdmf_file.hh @@ -1,338 +1,404 @@ /** * @file xdmf_file.hh * * @author Nicolas Richart * * @date creation Thu Oct 12 2017 * * @brief A Documented file. * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "dumper_file_base.hh" #include "xml_helper.hh" /* -------------------------------------------------------------------------- */ #include #include #include #include #include /* -------------------------------------------------------------------------- */ namespace { #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ static const auto ENDIAN{"Little"}; #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ static const auto ENDIAN{"Big"}; #else #error "Does not know from which end to open the eggs" #endif } // namespace #ifndef __AKANTU_XDMF_FILE_HH__ #define __AKANTU_XDMF_FILE_HH__ namespace akantu { namespace dumper { namespace { std::string xdmf_type(const ElementType & type) { static std::map element_map{ {_triangle_3, "Triangle"}, {_quadrangle_4, "Quadrilateral"}, {_tetrahedron_4, "Tetrahedron"}, {_pentahedron_6, "Wedge"}, {_hexahedron_8, "Hexahedron"}, {_triangle_6, "Tri_6"}, {_quadrangle_8, "Quad_8"}, {_tetrahedron_10, "Tet_10"}, {_pentahedron_15, "Wedge_15"}, {_hexahedron_20, "Hex_20"}}; return element_map[type]; } #define TIDX(x) std::type_index(typeid(x)) auto xdmf_datatype(const std::type_index & type_idx) { const static std::unordered_map> type_ids{ {TIDX(int), {"Int", 4}}, {TIDX(unsigned int), {"UInt", 4}}, {TIDX(int32_t), {"Int", 4}}, {TIDX(int64_t), {"Int", 8}}, {TIDX(uint32_t), {"UInt", 4}}, {TIDX(uint64_t), {"Int", 8}}, {TIDX(bool), {"UChar", 1}}, {TIDX(float), {"Float", 4}}, {TIDX(double), {"Float", 8}}, }; return type_ids.at(type_idx); } std::string xdmf_geometry(char dim) { switch (dim) { case 1: //[[gnu::fallthrougth]]; case 2: return "XY"; case 3: return "XYZ"; default: AKANTU_EXCEPTION("Dim " << dim << " is not a recognized geometry"); } } } // namespace namespace XDMF { namespace fs = boost::filesystem; class File : public XML::File, public dumper::FileBase { using Tag = XML::Tag; using CloseTag = XML::CloseTag; public: /* ---------------------------------------------------------------------- */ File(SupportBase & support, const boost::filesystem::path & path) : XML::File(path), FileBase(support), path(path) { - *this << "\n"; + *this << "\n"; *this << "\n"; - *this << Tag("Xdmf")("Version", "2.0")( + + current_xdmf_element.push_back(1); + + *this << Tag("Xdmf")("Version", "3.0")( "xmlns:xi", "http://www.w3.org/2001/XInclude"); *this << Tag("Domain"); support.addProperty("xdmf_file", path.string()); if (not support.hasProperty("dump_count")) return; auto mesh_name = support.getName(); *this << Tag("Grid")("Name", mesh_name + ":all")( "GridType", "Collection")("CollectionType", "Temporal"); } /* -------------------------------------------------------------------- */ File(SupportBase & support, const boost::filesystem::path & path, - const std::vector & current_xdmf_path) + const std::vector & current_xdmf_path, + const std::vector & current_xdmf_element) : XML::File(path), FileBase(support), include(true), - current_xdmf_path(current_xdmf_path), path(path) {} + current_xdmf_path(current_xdmf_path), + current_xdmf_element(current_xdmf_element), path(path) {} /* -------------------------------------------------------------------- */ ~File() = default; /* -------------------------------------------------------------------- */ XML::File & operator<<(const std::string & str) override { return XML::File::operator<<(str); } /* -------------------------------------------------------------------- */ XML::File & operator<<(const Tag & tag) override { XML::File::operator<<(tag); if (tag.autoclosing()) { + if (not current_xdmf_element.empty()) { + ++(current_xdmf_element.back()); + } + return *this; } auto tag_ = tag.tag(); if (tag.hasProperty("Name")) { tag_ += "[@Name=\"" + tag.getProperty("Name") + "\"]"; } + current_xdmf_path.push_back(tag_); + current_xdmf_element.push_back(1); + + //*this << "\n"; return *this; } /* -------------------------------------------------------------------- */ XML::File & operator<<(const CloseTag & tag) override { XML::File::operator<<(tag); current_xdmf_path.pop_back(); + current_xdmf_element.pop_back(); + if (not current_xdmf_element.empty()) { + ++(current_xdmf_element.back()); + } return *this; } /* -------------------------------------------------------------------- */ void dump() override { - if (include) { - auto count = support.getProperty("dump_count"); - *this << Tag("Grid")("CollectionType", "Spatial")( - "GridType", "Collection")("Name", - "model_" + std::to_string(count)); - if (support.hasProperty("time")) { - *this << Tag("Time", true)("TimeType", "Single")( - "Value", support.getProperty("time")); - } + // if (include) { + auto count = support.getProperty("dump_count"); + *this << Tag("Grid")("CollectionType", "Spatial")( + "GridType", "Collection")("Name", "model_" + std::to_string(count)); - FileBase::dump(); - return; + if (support.hasProperty("time")) { + *this << Tag("Information", true)("Name", "Time")( + "Value", support.getProperty("time")); } - auto count = support.getProperty("dump_count"); - auto include_path = getIncludeFilename(count); + FileBase::dump(); + + *this << CloseTag{}; + // return; + // } + + // auto count = support.getProperty("dump_count"); + // auto include_path = getIncludeFilename(count); - File xdmf_include(support, include_path, current_xdmf_path); - xdmf_include.dump(); + // File xdmf_include(support, include_path, current_xdmf_path); + // xdmf_include.dump(); - auto sub_path = - fs::relative(include_path, fs::path(path).remove_filename()); - *this << Tag("xi:include", true)("href", sub_path.string()); + // auto sub_path = + // fs::relative(include_path, fs::path(path).remove_filename()); + // *this << Tag("xi:include", true)("href", sub_path.string()); } private: fs::path getIncludeFilename(std::size_t num) { std::stringstream sstr; sstr << std::setw(5) << std::setfill('0') << num; auto include_path = path; include_path.remove_filename(); include_path /= "xmfs"; include_path /= path.stem().string() + '_' + sstr.str() + path.extension().string(); return include_path; } std::string currentXMFPath() const { auto tmp = fs::path("/"); for (auto && tag : current_xdmf_path) { tmp /= tag; } return tmp.generic_string(); } + std::string currentXMFElement() const { + auto tmp = fs::path("/"); + auto copy = current_xdmf_element; + copy.pop_back(); + for (auto && tag : copy) { + tmp /= std::to_string(tag); + } + + return tmp.generic_string(); + } + std::string getName(const ID & name, const Qualified & type) const { std::stringstream sstr; sstr << name << ":" << type.type; if (type.ghost_type != _not_ghost) { sstr << ":" << type.ghost_type; } return sstr.str(); } protected: /* -------------------------------------------------------------------- */ void dump(FieldArrayBase & field) override { auto && support = field.getSupport(); auto && tag = Tag("DataItem"); - - // if (reference and field.hasProperty("xdmf_path")) { - // *this << tag("Reference", "XML"); - // *this << (field.getProperty("xdmf_path")) << "\n"; - // } else - if (field.hasProperty("hdf5_path")) { + if (field.hasProperty("xdmf_element")) { + *this << Tag("xi:include", true)( + "xpointer", "element(" + + field.getProperty("xdmf_element") + + ")"); + //*this << tag("Reference", "XML"); + //*this << (field.getProperty("xdmf_path")) << "\n"; + } else if (field.hasProperty("hdf5_path")) { auto && dims = std::make_tuple(field.size(), field.getNbComponent()); auto && hdf5_path = fs::relative( fs::path(support.getProperty("hdf5_file")), fs::path(support.getProperty("xdmf_file")) .remove_filename()) .string() + ":" + field.getProperty("hdf5_path"); auto && xdmf_datatype_ = xdmf_datatype(field.type()); /* clang-format off */ *this << tag("Name", field.getName()) ("Dimensions", dims) ("Format", "HDF") ("NumberType", xdmf_datatype_.first) ("Precision", xdmf_datatype_.second) ("Endian", ENDIAN); /* clang-format on */ *this << hdf5_path << "\n"; field.addProperty("xdmf_path", currentXMFPath()); + field.addProperty("xdmf_element", currentXMFElement()); } else { AKANTU_EXCEPTION("The XML and Binary format are not implemented yet"); } *this << CloseTag{}; } /* -------------------------------------------------------------------- */ void dump(FieldElementMapArrayBase & /*field*/) override {} /* -------------------------------------------------------------------- */ void dump(Support & support) override { auto && mesh_name = support.getName(); auto && nodes = support.getNodes(); - *this << Tag("Grid")("CollectionType", "Spatial")( - "GridType", "Collection")("Name", mesh_name); - - support.addProperty("xdmf_path", currentXMFPath()); - - for (auto && type : support.elementTypes()) { - auto & connectivities = support.getConnectivities(); - auto & conn = connectivities.array(type); - auto && conn_name = getName(mesh_name, type); - - *this << Tag("Grid")("Name", conn_name)("GridType", "Uniform"); - - // Topology - *this << Tag("Topology")("TopologyType", xdmf_type(type))( - "NumberOfElements", conn.size()); - dump(conn); - *this << CloseTag{}; - - // Geometry - *this << Tag("Geometry")("GeometryType", - xdmf_geometry(nodes.getNbComponent())); - dump(nodes); - *this << CloseTag{}; + if (support.hasProperty("xdmf_element")) { + auto element = support.getProperty("xdmf_element"); + *this << Tag("xi:include", true)("xpointer", + "element(" + element + ")"); + } else { + *this << Tag("Grid")("CollectionType", "Spatial")( + "GridType", "Collection")("Name", mesh_name); + support.addProperty("xdmf_path", currentXMFPath()); + support.addProperty("xdmf_element", currentXMFElement()); + + for (auto && type : support.elementTypes()) { + auto & connectivities = support.getConnectivities(); + auto & conn = connectivities.array(type); + auto && conn_name = getName(mesh_name, type); + + *this << Tag("Grid")("Name", conn_name)("GridType", "Uniform"); + + // Topology + if (conn.hasProperty("xdmf_element")) { + auto element = + fs::path(conn.getProperty("xdmf_element")) + .parent_path() + .string(); + *this << Tag("xi:include", true)("xpointer", + "element(" + element + ")"); + } else { + *this << Tag("Topology")("TopologyType", xdmf_type(type))( + "NumberOfElements", conn.size()); + dump(conn); + *this << CloseTag{}; + } + + // Geometry + if (nodes.hasProperty("xdmf_element")) { + auto element = + fs::path(nodes.getProperty("xdmf_element")) + .parent_path() + .string(); + *this << Tag("xi:include", true)("xpointer", + "element(" + element + ")"); + } else { + *this << Tag("Geometry")("GeometryType", + xdmf_geometry(nodes.getNbComponent())); + dump(nodes); + *this << CloseTag{}; + } + + *this << CloseTag{}; + } *this << CloseTag{}; } - *this << CloseTag{}; for (auto && support : support.getSubSupports()) { dump(*support.second); } } - /* ------------------------------------------------------------------------ - */ + /* -------------------------------------------------------------------- */ void dump(Support & support) override { const auto & parent_support = support.getParentSupport(); fs::path xdmf_parent = parent_support.getProperty("xdmf_path"); auto parent_name = parent_support.getName(); auto name = parent_name + ":" + support.getName(); + if (support.hasProperty("xdmf_element")) { + auto element = support.getProperty("xdmf_element"); + *this << Tag("xi:include", true)("xpointer", + "element(" + element + ")"); + return; + } + *this << Tag("Grid")("Name", name)("GridType", "Collection")( "CollectionType", "Spatial"); support.addProperty("xdmf_path", currentXMFPath()); + support.addProperty("xdmf_element", currentXMFElement()); support.addProperty( "xdmf_file", parent_support.getProperty("xdmf_file")); auto & elements = support.getElements(); for (auto && type : support.elementTypes()) { auto xdmf_path = xdmf_parent; auto && name = getName(support.getName(), type); *this << Tag("Grid")("Name", name)("GridType", "Subset")("Section", "DataItem"); dump(elements.array(type)); *this << Tag("Grid")("Name", "Target")("Reference", "XML"); xdmf_path /= "Grid[@Name=\"" + getName(parent_name, type) + "\"]"; *this << xdmf_path.generic_string() << "\n"; *this << CloseTag{}; *this << CloseTag{}; } *this << CloseTag{}; } void dump(SupportBase & support) override { FileBase::dump(support); } public: bool include{false}; std::vector current_xdmf_path; + std::vector current_xdmf_element; boost::filesystem::path path; }; } // namespace XDMF } // namespace dumper } // namespace akantu #endif /* __AKANTU_XDMF_FILE_HH__ */ diff --git a/src/io/new_dumpers/xml_helper.hh b/src/io/new_dumpers/xml_helper.hh index ce720bd53..9df53039e 100644 --- a/src/io/new_dumpers/xml_helper.hh +++ b/src/io/new_dumpers/xml_helper.hh @@ -1,251 +1,246 @@ /** * @file xml_helper.hh * * @author Nicolas Richart * * @date creation Mon Oct 09 2017 * * @brief A Documented file. * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include #include #include #include #include #include #include /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_XML_HELPER_HH__ #define __AKANTU_XML_HELPER_HH__ namespace akantu { namespace dumper { namespace XML { namespace { template struct bool_pack; template using all_true = std::is_same, bool_pack>; template struct TupleUnpackHelper { template static void print(std::stringstream & sstr, const std::tuple & t) { TupleUnpackHelper::print(sstr, t); sstr << " " << std::get(t); } }; template <> struct TupleUnpackHelper<1> { template static void print(std::stringstream & sstr, const std::tuple & t) { sstr << std::get<0>(t); } }; } // namespace - /* ------------------------------------------------------------------------ - */ + /* ---------------------------------------------------------------------- */ class File; - /* ------------------------------------------------------------------------ - */ + /* ---------------------------------------------------------------------- */ class Tag { public: Tag(std::string tag, bool autoclosing_ = false) : tag_(std::move(tag)), autoclosing_(autoclosing_) {} Tag & operator()(const std::string & property, const std::string & value) { properties.emplace(property, value); return *this; } template Tag & operator()(const std::string & property, const T & value, std::enable_if_t< std::is_same())), std::string>::value> * /* unused */ = nullptr) { properties.emplace(property, std::to_string(value)); return *this; } template Tag & operator()( const std::string & property, const std::tuple & value, std::enable_if_t< all_true::value...>::value> * /* unused */ = nullptr) { std::stringstream sstr; TupleUnpackHelper::print(sstr, value); properties.emplace(property, sstr.str()); return *this; } const std::string & getProperty(const std::string & property) const { return properties.at(property); } bool hasProperty(const std::string & property) const { return (properties.find(property) != properties.end()); } const std::string & tag() const { return tag_; } bool autoclosing() const { return autoclosing_; } private: friend File; std::string tag_; bool autoclosing_{false}; std::map properties; }; - /* ------------------------------------------------------------------------ - */ + /* ---------------------------------------------------------------------- */ struct CloseTag {}; - /* ------------------------------------------------------------------------ - */ + /* ---------------------------------------------------------------------- */ class Indent { public: explicit Indent(char nb = 2) { for (char i = 0; i < nb; i++) { increment += " "; } } Indent & operator++() { indent += increment; return *this; } Indent & operator--() { indent = indent.substr(0, indent.size() - increment.size()); return *this; } std::string str() const { return indent; } private: std::string increment{""}; std::string indent{""}; }; - /* ----------------------------------------------------------------------- - */ + /* ---------------------------------------------------------------------- */ namespace fs = boost::filesystem; class File { public: explicit File(const boost::filesystem::path & path) { auto path_wof = path; path_wof.remove_filename(); if (not fs::exists(path_wof)) { fs::create_directories(path_wof); } stream.open(path.string()); } File(const File &) = delete; File(File &&) = delete; File & operator=(const File &) = delete; File & operator=(File &&) = delete; ~File() { auto size = tag_heap.size(); for (std::size_t i = 0; i < size; ++i) { *this << CloseTag{}; } stream.close(); } virtual File & operator<<(const std::string & str) { if (new_line) { stream << indent.str(); new_line = false; } auto pos_ret = str.find('\n'); if (pos_ret == std::string::npos) { // not carry return stream << str; } else { stream << str.substr(0, pos_ret + 1); new_line = true; if (pos_ret != str.size() - 1) { this->operator<<(str.substr(pos_ret + 1)); } } return *this; } virtual File & operator<<(const CloseTag & /* unused */) { --indent; *this << "\n"; tag_heap.pop_back(); return *this; } virtual File & operator<<(const Tag & t) { if (not t.autoclosing()) { tag_heap.push_back(t.tag()); } *this << "<" << t.tag(); std::for_each(t.properties.begin(), t.properties.end(), [&](auto && p) { *this << " " << p.first << "=\"" << p.second << "\""; }); if (t.autoclosing()) { *this << " /"; } *this << ">\n"; if (not t.autoclosing()) { ++indent; } return *this; } private: std::ofstream stream; Indent indent{2}; std::vector tag_heap; bool new_line{true}; }; } // namespace XML } // namespace dumper } // namespace akantu #endif /* __AKANTU_XML_HELPER_HH__ */ /* -------------------------------------------------------------------------- */ diff --git a/src/mesh/element_group.cc b/src/mesh/element_group.cc index f95f37672..7fd2d7fac 100644 --- a/src/mesh/element_group.cc +++ b/src/mesh/element_group.cc @@ -1,249 +1,240 @@ /** * @file element_group.cc * * @author Dana Christen * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Wed Nov 13 2013 * @date last modification: Wed Dec 09 2020 * * @brief Stores information relevent to the notion of domain boundary and * surfaces. * * * @section LICENSE * * Copyright (©) 2014-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "element_group.hh" #include "aka_csr.hh" #include "group_manager.hh" #include "group_manager_inline_impl.hh" #include "mesh.hh" #include "mesh_utils.hh" -<<<<<<< Updated upstream #if defined(AKANTU_COHESIVE_ELEMENT) #include "cohesive_element_inserter.hh" #endif #include #include #include -======= -/* -------------------------------------------------------------------------- */ -#include -#include -#include -/* -------------------------------------------------------------------------- */ -#include "element_group.hh" ->>>>>>> Stashed changes /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ ElementGroup::ElementGroup(const std::string & group_name, const Mesh & mesh, NodeGroup & node_group, UInt dimension, const std::string & id) : mesh(mesh), name(group_name), elements("elements", id), node_group(node_group), dimension(dimension) { AKANTU_DEBUG_IN(); // this->registerDumper("paraview_" + group_name, group_name, // true); // this->addDumpFilteredMesh(mesh, elements, node_group.getNodes(), // _all_dimensions); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ ElementGroup::ElementGroup(const ElementGroup & /*other*/) = default; /* -------------------------------------------------------------------------- */ void ElementGroup::clear() { elements.free(); } /* -------------------------------------------------------------------------- */ void ElementGroup::clear(ElementType type, GhostType ghost_type) { if (elements.exists(type, ghost_type)) { elements(type, ghost_type).clear(); } } /* -------------------------------------------------------------------------- */ bool ElementGroup::empty() const { return elements.empty(); } /* -------------------------------------------------------------------------- */ void ElementGroup::append(const ElementGroup & other_group) { AKANTU_DEBUG_IN(); node_group.append(other_group.node_group); /// loop on all element types in all dimensions for (auto ghost_type : ghost_types) { for (auto type : other_group.elementTypes(_ghost_type = ghost_type, _element_kind = _ek_not_defined)) { const Array & other_elem_list = other_group.elements(type, ghost_type); UInt nb_other_elem = other_elem_list.size(); Array * elem_list; UInt nb_elem = 0; /// create current type if doesn't exists, otherwise get information if (elements.exists(type, ghost_type)) { elem_list = &elements(type, ghost_type); nb_elem = elem_list->size(); } else { elem_list = &(elements.alloc(0, 1, type, ghost_type)); } /// append new elements to current list elem_list->resize(nb_elem + nb_other_elem); std::copy(other_elem_list.begin(), other_elem_list.end(), elem_list->begin() + nb_elem); } } this->optimize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ElementGroup::printself(std::ostream & stream, int indent) const { std::string space(indent, AKANTU_INDENT); stream << space << "ElementGroup [" << std::endl; stream << space << " + name: " << name << std::endl; stream << space << " + dimension: " << dimension << std::endl; elements.printself(stream, indent + 1); node_group.printself(stream, indent + 1); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ void ElementGroup::optimize() { // increasing the locality of data when iterating on the element of a group for (auto ghost_type : ghost_types) { for (auto type : elements.elementTypes(_ghost_type = ghost_type)) { auto & els = elements(type, ghost_type); std::sort(els.begin(), els.end()); auto end = std::unique(els.begin(), els.end()); els.resize(end - els.begin()); } } node_group.optimize(); } /* -------------------------------------------------------------------------- */ void ElementGroup::fillFromNodeGroup() { CSR node_to_elem; MeshUtils::buildNode2Elements(this->mesh, node_to_elem, this->dimension); std::set seen; for (auto node : node_group) { auto ite = node_to_elem.begin(node); auto ende = node_to_elem.end(node); for (auto && element : node_to_elem.getRow(node)) { if (this->dimension != _all_dimensions && this->dimension != Mesh::getSpatialDimension(element.type)) { continue; } if (seen.find(element) != seen.end()) { continue; } auto nb_nodes_per_element = Mesh::getNbNodesPerElement(element.type); auto conn = mesh.getConnectivity(element); UInt count = 0; for (auto && n : conn) { count += (this->node_group.getNodes().find(n) != UInt(-1) ? 1 : 0); } if (count == nb_nodes_per_element) { this->add(element); } seen.insert(element); } } this->optimize(); } /* -------------------------------------------------------------------------- */ void ElementGroup::addDimension(UInt dimension) { this->dimension = std::max(dimension, this->dimension); } /* -------------------------------------------------------------------------- */ void ElementGroup::onNodesAdded(const Array & new_nodes, const NewNodesEvent & event) { #if defined(AKANTU_COHESIVE_ELEMENT) if (aka::is_of_type(event)) { // nodes might have changed in the connectivity node_group.clear(); const auto & mesh_to_mesh_facet = mesh.getData("mesh_to_mesh_facet"); for (auto ghost_type : ghost_types) { for (auto type : elements.elementTypes(_ghost_type = ghost_type)) { auto & els = elements(type, ghost_type); if (not mesh_to_mesh_facet.exists(type, ghost_type)) { continue; } const auto & mesh_to_mesh_facet_type = mesh_to_mesh_facet(type, ghost_type); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto && conn_it = make_view(mesh.getConnectivity(type, ghost_type), nb_nodes_per_element) .begin(); auto && mesh_facet_conn_it = make_view(mesh.getMeshFacets().getConnectivity(type, ghost_type), nb_nodes_per_element) .begin(); for (auto element : els) { auto && mesh_facet_conn = mesh_facet_conn_it[mesh_to_mesh_facet_type(element).element]; auto && conn = conn_it[element]; conn = mesh_facet_conn; for (auto && n : conn) { node_group.add(n, false); } } } } node_group.optimize(); } #endif } /* -------------------------------------------------------------------------- */ } // namespace akantu