|
| 1 | +#include <config.h> |
| 2 | + |
| 3 | +#include <opm/grid/CpGrid.hpp> |
| 4 | + |
| 5 | +#if HAVE_OPM_COMMON |
| 6 | +#include <opm/input/eclipse/Deck/Deck.hpp> |
| 7 | +#include <opm/input/eclipse/EclipseState/EclipseState.hpp> |
| 8 | +#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp> |
| 9 | +#include <opm/input/eclipse/Parser/InputErrorAction.hpp> |
| 10 | +#include <opm/input/eclipse/Parser/ParseContext.hpp> |
| 11 | +#include <opm/input/eclipse/Parser/Parser.hpp> |
| 12 | +#endif |
| 13 | + |
| 14 | +#include <fstream> |
| 15 | +#include <filesystem> |
| 16 | +#include <iomanip> |
| 17 | +#include <iostream> |
| 18 | +#include <stdexcept> |
| 19 | +#include <string> |
| 20 | +#include <vector> |
| 21 | + |
| 22 | +namespace { |
| 23 | + |
| 24 | +#if HAVE_OPM_COMMON |
| 25 | +Opm::ParseContext makeFlowLikeParseContext() |
| 26 | +{ |
| 27 | + return Opm::ParseContext({ |
| 28 | + {Opm::ParseContext::PARSE_RANDOM_SLASH, Opm::InputErrorAction::IGNORE}, |
| 29 | + {Opm::ParseContext::PARSE_MISSING_DIMS_KEYWORD, Opm::InputErrorAction::WARN}, |
| 30 | + {Opm::ParseContext::SUMMARY_UNKNOWN_WELL, Opm::InputErrorAction::WARN}, |
| 31 | + {Opm::ParseContext::SUMMARY_UNKNOWN_GROUP, Opm::InputErrorAction::WARN}, |
| 32 | + }); |
| 33 | +} |
| 34 | +#endif |
| 35 | + |
| 36 | +void writeGridFromCpGrid(const Dune::CpGrid& grid, const std::string& output_file) |
| 37 | +{ |
| 38 | + const int ndims = 3; |
| 39 | + const int ncells = grid.numCells(); |
| 40 | + const int nfaces = grid.numFaces(); |
| 41 | + const int nnodes = grid.numVertices(); |
| 42 | + const int ncellfaces = grid.numCellFaces(); |
| 43 | + |
| 44 | + int nfacenodes = 0; |
| 45 | + std::vector<int> face_nodepos; |
| 46 | + std::vector<int> face_nodes; |
| 47 | + face_nodepos.reserve(nfaces + 1); |
| 48 | + face_nodes.reserve(4 * nfaces); |
| 49 | + face_nodepos.push_back(0); |
| 50 | + for (int f = 0; f < nfaces; ++f) { |
| 51 | + const int nv = grid.numFaceVertices(f); |
| 52 | + for (int lv = 0; lv < nv; ++lv) { |
| 53 | + face_nodes.push_back(grid.faceVertex(f, lv)); |
| 54 | + } |
| 55 | + nfacenodes += nv; |
| 56 | + face_nodepos.push_back(nfacenodes); |
| 57 | + } |
| 58 | + |
| 59 | + std::vector<int> face_cells; |
| 60 | + face_cells.reserve(2 * nfaces); |
| 61 | + for (int f = 0; f < nfaces; ++f) { |
| 62 | + face_cells.push_back(grid.faceCell(f, 0)); |
| 63 | + face_cells.push_back(grid.faceCell(f, 1)); |
| 64 | + } |
| 65 | + |
| 66 | + std::vector<int> cell_facepos; |
| 67 | + std::vector<int> cell_faces; |
| 68 | + std::vector<int> cell_facetag; |
| 69 | + cell_facepos.reserve(ncells + 1); |
| 70 | + cell_faces.reserve(ncellfaces); |
| 71 | + cell_facetag.reserve(ncellfaces); |
| 72 | + cell_facepos.push_back(0); |
| 73 | + for (int c = 0; c < ncells; ++c) { |
| 74 | + const int ncf = grid.numCellFaces(c); |
| 75 | + for (int lf = 0; lf < ncf; ++lf) { |
| 76 | + const int face = grid.cellFace(c, lf); |
| 77 | + cell_faces.push_back(face); |
| 78 | + |
| 79 | + const int c0 = grid.faceCell(face, 0); |
| 80 | + const auto& n = grid.faceNormal(face); |
| 81 | + double ox = n[0]; |
| 82 | + double oy = n[1]; |
| 83 | + double oz = n[2]; |
| 84 | + if (c0 != c) { |
| 85 | + ox = -ox; |
| 86 | + oy = -oy; |
| 87 | + oz = -oz; |
| 88 | + } |
| 89 | + |
| 90 | + const double ax = std::abs(ox); |
| 91 | + const double ay = std::abs(oy); |
| 92 | + const double az = std::abs(oz); |
| 93 | + int tag = 0; |
| 94 | + if (ax >= ay && ax >= az) { |
| 95 | + tag = (ox >= 0.0) ? 1 : 0; |
| 96 | + } else if (ay >= ax && ay >= az) { |
| 97 | + tag = (oy >= 0.0) ? 3 : 2; |
| 98 | + } else { |
| 99 | + tag = (oz >= 0.0) ? 5 : 4; |
| 100 | + } |
| 101 | + cell_facetag.push_back(tag); |
| 102 | + } |
| 103 | + cell_facepos.push_back(static_cast<int>(cell_faces.size())); |
| 104 | + } |
| 105 | + |
| 106 | + if (static_cast<int>(cell_faces.size()) != ncellfaces) { |
| 107 | + throw std::runtime_error("Internal inconsistency: numCellFaces() total mismatch"); |
| 108 | + } |
| 109 | + |
| 110 | + std::ofstream out(output_file); |
| 111 | + if (!out) { |
| 112 | + throw std::runtime_error("Failed to open output file: " + output_file); |
| 113 | + } |
| 114 | + |
| 115 | + out << std::setprecision(17) << std::fixed; |
| 116 | + |
| 117 | + const int has_tag = 1; |
| 118 | + const int has_indexmap = 1; |
| 119 | + out << ndims << ' ' << ncells << ' ' << nfaces << ' ' |
| 120 | + << nnodes << ' ' << nfacenodes << ' ' << ncellfaces << ' ' |
| 121 | + << has_tag << ' ' << has_indexmap << '\n'; |
| 122 | + |
| 123 | + const auto cartdims = grid.logicalCartesianSize(); |
| 124 | + out << cartdims[0] << ' ' << cartdims[1] << ' ' << cartdims[2] << '\n'; |
| 125 | + |
| 126 | + for (int v = 0; v < nnodes; ++v) { |
| 127 | + const auto& p = grid.vertexPosition(v); |
| 128 | + out << p[0] << ' ' << p[1] << ' ' << p[2] << ' '; |
| 129 | + } |
| 130 | + out << '\n'; |
| 131 | + |
| 132 | + for (const int value : face_nodepos) { |
| 133 | + out << value << ' '; |
| 134 | + } |
| 135 | + out << '\n'; |
| 136 | + |
| 137 | + for (const int value : face_nodes) { |
| 138 | + out << value << ' '; |
| 139 | + } |
| 140 | + out << '\n'; |
| 141 | + |
| 142 | + for (const int value : face_cells) { |
| 143 | + out << value << ' '; |
| 144 | + } |
| 145 | + out << '\n'; |
| 146 | + |
| 147 | + for (int f = 0; f < nfaces; ++f) { |
| 148 | + out << grid.faceArea(f) << ' '; |
| 149 | + } |
| 150 | + out << '\n'; |
| 151 | + |
| 152 | + for (int f = 0; f < nfaces; ++f) { |
| 153 | + const auto& c = grid.faceCentroid(f); |
| 154 | + out << c[0] << ' ' << c[1] << ' ' << c[2] << ' '; |
| 155 | + } |
| 156 | + out << '\n'; |
| 157 | + |
| 158 | + for (int f = 0; f < nfaces; ++f) { |
| 159 | + const auto& n = grid.faceNormal(f); |
| 160 | + out << n[0] << ' ' << n[1] << ' ' << n[2] << ' '; |
| 161 | + } |
| 162 | + out << '\n'; |
| 163 | + |
| 164 | + for (const int value : cell_facepos) { |
| 165 | + out << value << ' '; |
| 166 | + } |
| 167 | + out << '\n'; |
| 168 | + |
| 169 | + for (std::size_t i = 0; i < cell_faces.size(); ++i) { |
| 170 | + out << cell_faces[i] << ' ' << cell_facetag[i] << ' '; |
| 171 | + } |
| 172 | + out << '\n'; |
| 173 | + |
| 174 | + const auto& global_cell = grid.globalCell(); |
| 175 | + for (const int value : global_cell) { |
| 176 | + out << value << ' '; |
| 177 | + } |
| 178 | + out << '\n'; |
| 179 | + |
| 180 | + for (int c = 0; c < ncells; ++c) { |
| 181 | + out << grid.cellVolume(c) << ' '; |
| 182 | + } |
| 183 | + out << '\n'; |
| 184 | + |
| 185 | + for (int c = 0; c < ncells; ++c) { |
| 186 | + const auto& cc = grid.cellCentroid(c); |
| 187 | + out << cc[0] << ' ' << cc[1] << ' ' << cc[2] << ' '; |
| 188 | + } |
| 189 | + out << '\n'; |
| 190 | +} |
| 191 | + |
| 192 | +} // namespace |
| 193 | + |
| 194 | +int main(int argc, char** argv) |
| 195 | +{ |
| 196 | + Dune::MPIHelper::instance(argc, argv); |
| 197 | + |
| 198 | +#if !HAVE_OPM_COMMON |
| 199 | + std::cerr << "export_grid requires HAVE_OPM_COMMON to parse .DATA files." << std::endl; |
| 200 | + return 2; |
| 201 | +#else |
| 202 | + if (argc != 3) { |
| 203 | + std::cerr << "Usage: " << argv[0] << " <case.DATA> <output.grid>" << std::endl; |
| 204 | + return 1; |
| 205 | + } |
| 206 | + |
| 207 | + const std::string data_file = argv[1]; |
| 208 | + const std::string output_file = argv[2]; |
| 209 | + |
| 210 | + try { |
| 211 | + Dune::CpGrid cpgrid; |
| 212 | + bool built_from_data = false; |
| 213 | + |
| 214 | + try { |
| 215 | + Opm::Parser parser; |
| 216 | + const auto deck = parser.parseFile(data_file, makeFlowLikeParseContext()); |
| 217 | + |
| 218 | + Opm::EclipseGrid eclipse_grid(deck); |
| 219 | + Opm::EclipseState ecl_state(deck); |
| 220 | + |
| 221 | + cpgrid.processEclipseFormat(&eclipse_grid, &ecl_state, false); |
| 222 | + built_from_data = true; |
| 223 | + } catch (const std::exception& e) { |
| 224 | + const std::filesystem::path data_path(data_file); |
| 225 | + const std::filesystem::path egrid_path = |
| 226 | + data_path.parent_path() / (data_path.stem().string() + ".EGRID"); |
| 227 | + if (!std::filesystem::exists(egrid_path)) { |
| 228 | + throw std::runtime_error( |
| 229 | + std::string("Failed to parse DATA and no EGRID fallback found. DATA error: ") + e.what()); |
| 230 | + } |
| 231 | + |
| 232 | + std::cerr << "Warning: failed to build grid directly from DATA (" << e.what() << ")\n" |
| 233 | + << "Falling back to EGRID: " << egrid_path << "\n"; |
| 234 | + Opm::EclipseGrid eclipse_grid(egrid_path.string()); |
| 235 | + cpgrid.processEclipseFormat(&eclipse_grid, nullptr, false); |
| 236 | + } |
| 237 | + |
| 238 | + writeGridFromCpGrid(cpgrid, output_file); |
| 239 | + |
| 240 | + std::cout << "Wrote grid: " << output_file << "\n" |
| 241 | + << " source : " << (built_from_data ? "DATA" : "EGRID fallback") << "\n" |
| 242 | + << " cells/faces/vertices/cellFaces = " |
| 243 | + << cpgrid.numCells() << " / " |
| 244 | + << cpgrid.numFaces() << " / " |
| 245 | + << cpgrid.numVertices() << " / " |
| 246 | + << cpgrid.numCellFaces() << "\n"; |
| 247 | + } catch (const std::exception& e) { |
| 248 | + std::cerr << "Failed to export grid from DATA: " << e.what() << std::endl; |
| 249 | + return 3; |
| 250 | + } |
| 251 | + |
| 252 | + return 0; |
| 253 | +#endif |
| 254 | +} |
0 commit comments