/* Copyright 2023 Inria, Bretagne–Atlantique Research Center This file is part of the Open Porous Media project (OPM). OPM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OPM 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 General Public License for more details. You should have received a copy of the GNU General Public License along with OPM. If not, see . */ #include #include #include #include #include #include #include #include namespace Opm::GridDataOutput { template SimMeshDataAccessor:: SimMeshDataAccessor(const GridView& gridView, Dune::PartitionSet dunePartition) : gridView_(gridView) , dunePartition_(dunePartition) { dimw_ = GridView::dimension; // this is an enum partition_value_ = dunePartition.value; countEntities(); } template bool SimMeshDataAccessor::polyhedralCellPresent() const { for (const auto& cit : elements(gridView_, dunePartition_)) { auto corner_geom = cit.geometry(); if (Dune::VTK::geometryType(corner_geom.type()) == Dune::VTK::polyhedron) { return true; } } return false; } template void SimMeshDataAccessor::countEntities() { // We include all the vertices for this ranks partition const auto& vert_partition = vertices(gridView_, Dune::Partitions::all); nvertices_ = std::distance(vert_partition.begin(), vert_partition.end()); const auto& cell_partition = elements(gridView_, dunePartition_); ncells_ = 0; ncorners_ = 0; for (const auto& cit : cell_partition) { auto corner_geom = cit.geometry(); ncorners_ += corner_geom.corners(); ++ncells_; } } template template long SimMeshDataAccessor:: writeGridPoints(T* x_inout, T* y_inout, T* z_inout, long max_size) const { if (max_size < nvertices_) { OPM_THROW(std::runtime_error, "Opm::GridDataOutput::writeGridPoints( T& x_inout, T& " "y_inout, T& z_inout ) " + " Input objects max_size (" + std::to_string(max_size) + ") is not sufficient to fit the nvertices_ values (" + std::to_string(nvertices_) + ")"); } long i = 0; if (dimw_ == 3) { for (const auto& vit : vertices(gridView_, Dune::Partitions::all)) { auto xyz_local = vit.geometry().corner(0); // vertices only have one corner x_inout[i] = static_cast(xyz_local[0]); y_inout[i] = static_cast(xyz_local[1]); z_inout[i] = static_cast(xyz_local[2]); i++; } } else if (dimw_ == 2) { for (const auto& vit : vertices(gridView_, Dune::Partitions::all)) { auto xyz_local = vit.geometry().corner(0); // vertices only have one corner x_inout[i] = static_cast(xyz_local[0]); y_inout[i] = static_cast(xyz_local[1]); z_inout[i] = static_cast(0.0); i++; } } assert(i == nvertices_); // As we are templated on the // Dune::PartitionSet, this cannot change return i; } template template long SimMeshDataAccessor:: writeGridPoints(VectType& x_inout, VectType& y_inout, VectType& z_inout) const { const std::size_t check_size_x = x_inout.size(); const std::size_t check_size_y = y_inout.size(); const std::size_t check_size_z = z_inout.size(); using VT = decltype(x_inout.data()[0]); if ((check_size_x < static_cast(nvertices_)) || (check_size_y < static_cast(nvertices_)) || (check_size_z < static_cast(nvertices_))) { // assert(check_size >= nvertices_); OPM_THROW(std::runtime_error, "Opm::GridDataOutput::writeGridPoints( VectType& x_inout, VectType& " "y_inout, VectType& z_inout ) At least one of the inputs" + " object x size " + std::to_string(check_size_x) + " object y size " + std::to_string(check_size_y) + " object z size " + std::to_string(check_size_z) + " is not sufficient to fit the nvertices_ values( " + std::to_string(nvertices_) + " )"); } long i = 0; if (dimw_ == 3) { for (const auto& vit : vertices(gridView_, Dune::Partitions::all)) { auto xyz_local = vit.geometry().corner(0); // vertices only have one corner x_inout.data()[i] = static_cast(xyz_local[0]); y_inout.data()[i] = static_cast(xyz_local[1]); z_inout.data()[i] = static_cast(xyz_local[2]); i++; } } else if (dimw_ == 2) { double td = 0.0; for (const auto& vit : vertices(gridView_, Dune::Partitions::all)) { auto xyz_local = vit.geometry().corner(0); // vertices only have one corner x_inout.data()[i] = static_cast(xyz_local[0]); y_inout.data()[i] = static_cast(xyz_local[1]); z_inout.data()[i] = static_cast(td); i++; } } assert(i == nvertices_); // As we are templated on the // Dune::PartitionSet, this cannot change return i; } template template long SimMeshDataAccessor:: writeGridPoints_AOS(T* xyz_inout, long max_size) const { if (max_size < nvertices_ * 3) { assert(max_size >= nvertices_ * 3); OPM_THROW(std::runtime_error, "Opm::GridDataOutput::writeGridPoints_AOS( T* xyz_inout ) " + " Input objects max_size (" + std::to_string(max_size) + ") is not sufficient to fit the nvertices_ * 3 values (" + std::to_string(nvertices_ * 3) + ")"); } long i = 0; if (dimw_ == 3) { for (const auto& vit : vertices(gridView_, Dune::Partitions::all)) { auto xyz_local = vit.geometry().corner(0); xyz_inout[i++] = static_cast(xyz_local[0]); xyz_inout[i++] = static_cast(xyz_local[1]); xyz_inout[i++] = static_cast(xyz_local[2]); } } else if (dimw_ == 2) { for (const auto& vit : vertices(gridView_, Dune::Partitions::all)) { auto xyz_local = vit.geometry().corner(0); xyz_inout[i++] = static_cast(xyz_local[0]); xyz_inout[i++] = static_cast(xyz_local[1]); xyz_inout[i++] = static_cast(0.0); } } return i / 3; } template template long SimMeshDataAccessor:: writeGridPoints_AOS(VectType& xyz_inout) const { const std::size_t check_size = xyz_inout.size(); using VT = decltype(xyz_inout.data()[0]); if (check_size < static_cast(nvertices_ * 3)) { assert(check_size >= nvertices_ * 3); OPM_THROW(std::runtime_error, "Opm::GridDataOutput::writeGridPoints_AOS( VectType& xyz_inout ) " + " Input objects check_size (" + std::to_string(check_size) + ") is not sufficient to fit the nvertices_ * 3 values (" + std::to_string(nvertices_ * 3) + ")"); } long i = 0; if (dimw_ == 3) { for (const auto& vit : vertices(gridView_, Dune::Partitions::all)) { auto xyz_local = vit.geometry().corner(0); xyz_inout.data()[i++] = static_cast(xyz_local[0]); xyz_inout[i++] = static_cast(xyz_local[1]); xyz_inout[i++] = static_cast(xyz_local[2]); } } else if (dimw_ == 2) { double td = 0.0; for (const auto& vit : vertices(gridView_, Dune::Partitions::all)) { auto xyz_local = vit.geometry().corner(0); xyz_inout[i++] = static_cast(xyz_local[0]); xyz_inout[i++] = static_cast(xyz_local[1]); xyz_inout[i++] = static_cast(td); } } return i / 3; } template template long SimMeshDataAccessor:: writeGridPoints_SOA(T* xyz_inout, long max_size) const { if (max_size < nvertices_ * 3) { // assert(max_size >= nvertices_ * 3); OPM_THROW(std::runtime_error, "Opm::GridDataOutput::writeGridPoints_SOA( T& xyz_inout ) " + " Input objects max_size (" + std::to_string(max_size) + ") is not sufficient to fit the nvertices_ * 3 values (" + std::to_string(nvertices_ * 3) + ")"); } long i = 0; // Get offsets into structure T* xyz_inout_y = xyz_inout + nvertices_; T* xyz_inout_z = xyz_inout + (2 * nvertices_); if (dimw_ == 3) { for (const auto& vit : vertices(gridView_, Dune::Partitions::all)) { auto xyz_local = vit.geometry().corner(0); xyz_inout[i] = static_cast(xyz_local[0]); xyz_inout_y[i] = static_cast(xyz_local[1]); xyz_inout_z[i] = static_cast(xyz_local[2]); i++; } } else if (dimw_ == 2) { for (const auto& vit : vertices(gridView_, Dune::Partitions::all)) { auto xyz_local = vit.geometry().corner(0); xyz_inout[i] = static_cast(xyz_local[0]); xyz_inout_y[i] = static_cast(xyz_local[1]); xyz_inout_z[i] = static_cast(0.0); i++; } } return i; } template template long SimMeshDataAccessor:: writeGridPoints_SOA(VectType& xyz_inout) const { const std::size_t check_size = xyz_inout.size(); if (check_size < static_cast(nvertices_ * 3)) { // assert(check_size >= nvertices_ * 3); OPM_THROW(std::runtime_error, "Opm::GridDataOutput::writeGridPoints_SOA( VectType& xyz_inout ) " + " Input objects check_size (" + std::to_string(check_size) + ") is not sufficient to fit the nvertices_ * 3 values (" + std::to_string(nvertices_ * 3) + ")"); } using VT = decltype(xyz_inout.data()[0]); long i = 0; // Get offsets into structure VT* xyz_inout_y = xyz_inout.data() + nvertices_; VT* xyz_inout_z = xyz_inout.data() + (2 * nvertices_); if (dimw_ == 3) { for (const auto& vit : vertices(gridView_, Dune::Partitions::all)) { auto xyz_local = vit.geometry().corner(0); xyz_inout.data()[i] = static_cast(xyz_local[0]); xyz_inout_y[i] = static_cast(xyz_local[1]); xyz_inout_z[i] = static_cast(xyz_local[2]); i++; } } else if (dimw_ == 2) { double td = 0.0; for (const auto& vit : vertices(gridView_, Dune::Partitions::all)) { auto xyz_local = vit.geometry().corner(0); xyz_inout.data()[i] = static_cast(xyz_local[0]); xyz_inout_y[i] = static_cast(xyz_local[1]); xyz_inout_z[i] = static_cast(td); i++; } } return i; } template template long SimMeshDataAccessor:: writeConnectivity(Integer* connectivity_inout, ConnectivityVertexOrder whichOrder, long max_size) const { if (max_size < ncorners_) { OPM_THROW(std::runtime_error, "Opm::GridDataOutput::writeConnectivity( T* connectivity_inout,... ) " + " Input max_size value (" + std::to_string(max_size) + ") is not sufficient to fit the ncorners_ values (" + std::to_string(ncorners_) + ")"); } long i = 0; if (whichOrder == DUNE) { // DUNE order for (const auto& cit : elements(gridView_, dunePartition_)) { auto cell_corners = cit.geometry().corners(); for (auto vx = 0; vx < cell_corners; ++vx) { const int vxIdx = gridView_.indexSet().subIndex(cit, vx, 3); connectivity_inout[i + vx] = vxIdx; } i += cell_corners; } } else { // VTK order for (const auto& cit : elements(gridView_, dunePartition_)) { auto cell_corners = cit.geometry().corners(); for (auto vx = 0; vx < cell_corners; ++vx) { const int vxIdx = gridView_.indexSet().subIndex(cit, vx, 3); int vtkOrder; vtkOrder = Dune::VTK::renumber(cit.type(), vx); connectivity_inout[i + vtkOrder] = vxIdx; } i += cell_corners; } } return i; } template template long SimMeshDataAccessor:: writeConnectivity(VectType& connectivity_inout, ConnectivityVertexOrder whichOrder) const { const std::size_t check_size = connectivity_inout.size(); if (check_size < static_cast(ncorners_)) { // assert(check_size >= ncorners_); OPM_THROW(std::runtime_error, "Opm::GridDataOutput::writeConnectivity( VectType& " "connectivity_inout ) " + " Input objects size (" + std::to_string(check_size) + ") is not sufficient to fit the ncorners_ values (" + std::to_string(ncorners_) + ")"); } long i = 0; if (whichOrder == DUNE) { // DUNE order for (const auto& cit : elements(gridView_, dunePartition_)) { auto cell_corners = cit.geometry().corners(); for (auto vx = 0; vx < cell_corners; ++vx) { const int vxIdx = gridView_.indexSet().subIndex(cit, vx, 3); connectivity_inout.data()[i + vx] = vxIdx; } i += cell_corners; } } else { // VTK order for (const auto& cit : elements(gridView_, dunePartition_)) { auto cell_corners = cit.geometry().corners(); for (auto vx = 0; vx < cell_corners; ++vx) { const int vxIdx = gridView_.indexSet().subIndex(cit, vx, 3); int vtkOrder; vtkOrder = Dune::VTK::renumber(cit.type(), vx); connectivity_inout.data()[i + vtkOrder] = vxIdx; } i += cell_corners; } } return i; } template template long SimMeshDataAccessor:: writeOffsetsCells(Integer* offsets_inout, long max_size) const { if (max_size < ncells_) { // assert(max_size >= ncells_); OPM_THROW(std::runtime_error, "Opm::GridDataOutput::writeOffsetsCells( T* offsets_inout ) " + " Input objects max_size (" + std::to_string(max_size) + ") is not sufficient to fit the ncells_ values (" + std::to_string(ncells_) + ")"); } long i = 1; offsets_inout[0] = 0; for (const auto& cit : elements(gridView_, dunePartition_)) { auto cell_corners = cit.geometry().corners(); offsets_inout[i] = offsets_inout[i - 1] + cell_corners; i++; } return i; // This should be 1 greater than ncells_ } template template long SimMeshDataAccessor:: writeOffsetsCells(VectType& offsets_inout) const { const std::size_t check_size = offsets_inout.size(); if (check_size < static_cast(ncells_)) { // assert(check_size >= ncells_); OPM_THROW(std::runtime_error, "Opm::GridDataOutput::writeOffsetsCells( VectType& " "offsets_inout ) " + " Input objects size (" + std::to_string(offsets_inout.size()) + ") is not sufficient to fit the ncells_ values (" + std::to_string(ncells_) + ")"); } // using VT = decltype(offsets_inout.data()[0]); long i = 1; offsets_inout.data()[0] = 0; for (const auto& cit : elements(gridView_, dunePartition_)) { auto cell_corners = cit.geometry().corners(); offsets_inout.data()[i] = offsets_inout.data()[i - 1] + cell_corners; i++; } return i; // This should be 1 greater than ncells_ } template template long SimMeshDataAccessor:: writeCellTypes(Integer* types_inout, long max_size) const { if (max_size < ncells_) { // assert(max_size >= ncells_); OPM_THROW(std::runtime_error, "Opm::GridDataOutput::writeCellTypes( T* types_inout ) " + " Input objects max_size (" + std::to_string(max_size) + ") is not sufficient to fit the ncells_ values (" + std::to_string(ncells_) + ")"); } int i = 0; for (const auto& cit : elements(gridView_, dunePartition_)) { Integer vtktype = static_cast(Dune::VTK::geometryType(cit.type())); types_inout[i++] = vtktype; } return i; } template template long SimMeshDataAccessor:: writeCellTypes(VectType& types_inout) const { const std::size_t check_size = types_inout.size(); if (check_size < static_cast(ncells_)) { OPM_THROW(std::runtime_error, "Opm::GridDataOutput::writeCellTypes( VectType& types_inout ) " + " Input objects check_size (" + std::to_string(check_size) + ") is not sufficient to fit the ncells_ values (" + std::to_string(ncells_) + ")"); } int i = 0; for (const auto& cit : elements(gridView_, dunePartition_)) { int vtktype = static_cast(Dune::VTK::geometryType(cit.type())); types_inout.data()[i++] = vtktype; } return i; } template std::string SimMeshDataAccessor:: getPartitionTypeString() const { if (this->dunePartition_ == Dune::Partitions::all) { return "Dune::Partitions::all"; } if (this->dunePartition_ == Dune::Partitions::interior) { return "Dune::Partitions::interior"; } if (this->dunePartition_ == Dune::Partitions::interiorBorder) { return "Dune::Partitions::interiorBorder"; } if (this->dunePartition_ == Dune::Partitions::interiorBorderOverlap) { return "Dune::Partitions::interiorBorderOverlap"; } if (this->dunePartition_ == Dune::Partitions::front) { return "Dune::Partitions::front"; } if (this->dunePartition_ == Dune::Partitions::interiorBorderOverlapFront) { return "Dune::Partitions::InteriorBorderOverlapFront"; } if (this->dunePartition_ == Dune::Partitions::border) { return "Dune::Partitions::border"; } if (this->dunePartition_ == Dune::Partitions::ghost) { return "Dune::Partitions::ghost"; } return "Unknown Dune::PartitionSet<>"; } template void SimMeshDataAccessor:: printGridDetails(std::ostream& outstr) const { outstr << "Dune Partition = " << partition_value_ << ", " << getPartitionTypeString() << std::endl; outstr << "ncells_: " << getNCells() << std::endl; outstr << "nvertices_: " << getNVertices() << std::endl; outstr << "ncorners_: " << getNCorners() << std::endl; } } // namespace Opm::GridDataOutput