OGS
FileIO/GocadIO/GocadSGridReader.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "GocadSGridReader.h"
5
6#include <algorithm>
7#include <boost/tokenizer.hpp>
8#include <cstddef>
9#include <fstream>
10#include <iostream>
11#include <sstream>
12
13#include "BaseLib/FileTools.h"
16#include "MeshLib/Mesh.h"
18
19namespace FileIO
20{
21namespace Gocad
22{
23using Bitset = boost::dynamic_bitset<>;
24
25GocadSGridReader::GocadSGridReader(std::string const& fname)
26 : _fname(fname),
27 _path(BaseLib::extractPath(fname).empty()
28 ? ""
29 : BaseLib::extractPath(fname) + '/'),
30 _n_face_sets(0),
33{
34 // check if file exists
35 std::ifstream in(_fname.c_str());
36 if (!in)
37 {
38 ERR("Could not open '{:s}'.", _fname);
39 in.close();
40 return;
41 }
42
43 bool pnts_read(false);
44
45 // read information in the stratigraphic grid file
46 std::string line;
47 while (std::getline(in, line))
48 {
49 if (line.empty()) // skip empty lines
50 {
51 continue;
52 }
53 if (line.back() == '\r') // check dos line ending
54 {
55 line.pop_back();
56 }
57 if (line.substr(0, 8) == "HEADER {")
58 {
59 parseHeader(in);
60 }
61 if (line.substr(0, 32) == "GOCAD_ORIGINAL_COORDINATE_SYSTEM")
62 {
63 _coordinate_system.parse(in);
64 continue;
65 }
66 if (line.substr(0, 7) == "AXIS_N ")
67 {
68 parseDims(line);
69 }
70 else if (line.substr(0, 12) == "POINTS_FILE ")
71 {
73 }
74 else if (line.substr(0, 9) == "PROPERTY ")
75 {
78 }
79 else if (line.substr(0, 35) == "BINARY_POINTS_IN_DOUBLE_PRECISION 1")
80 {
82 }
83 else if (line.substr(0, 11) == "FLAGS_FILE ")
84 {
86 }
87 else if (line.substr(0, 18) == "REGION_FLAGS_FILE ")
88 {
90 }
91 else if (line.substr(0, 7) == "REGION " ||
92 line.substr(0, 13) == "MODEL_REGION ")
93 {
94 regions.push_back(Gocad::parseRegion(line));
95 }
96 else if (line.substr(0, 12) == "MODEL_LAYER ")
97 {
98 layers.push_back(Gocad::parseLayer(line, regions));
99 }
100 else if (line.substr(0, 24) == "REGION_FLAGS_BIT_LENGTH ")
101 {
102 std::istringstream iss(line);
103 std::istream_iterator<std::string> it(iss);
104 it++;
105 std::size_t bit_length = std::atoi(it->c_str());
106 if (regions.size() != bit_length)
107 {
108 ERR("{:d} regions read but {:d} expected.\n", regions.size(),
109 bit_length);
110 throw std::runtime_error(
111 "Number of read regions differs from expected.\n");
112 }
113 }
114 else if (line.substr(0, 9) == "FACE_SET ")
115 {
116 // first read the points
117 if (!pnts_read)
118 {
120 pnts_read = true;
121 }
122 parseFaceSet(line, in);
123 }
124 }
125
126#ifndef NDEBUG
127 std::stringstream regions_ss;
128 regions_ss << regions.size() << " regions read:\n";
129 std::copy(regions.begin(), regions.end(),
130 std::ostream_iterator<Gocad::Region>(regions_ss, "\t"));
131 DBUG("{:s}", regions_ss.str());
132
133 std::stringstream layers_ss;
134 layers_ss << layers.size() << " layers read:\n";
135 std::copy(layers.begin(), layers.end(),
136 std::ostream_iterator<Gocad::Layer>(layers_ss, "\n"));
137 DBUG("{:s}", layers_ss.str());
138
139 std::stringstream properties_ss;
140 properties_ss << "meta data for " << _property_meta_data_vecs.size()
141 << " properties read:\n";
142 std::copy(_property_meta_data_vecs.begin(), _property_meta_data_vecs.end(),
143 std::ostream_iterator<Gocad::Property>(properties_ss, "\n"));
144 DBUG("{:s}", properties_ss.str());
145#endif
146
147 // if not done already read the points
148 if (!pnts_read)
149 {
151 }
153 std::vector<Bitset> region_flags = readRegionFlagsBinary();
154 mapRegionFlagsToCellProperties(region_flags);
155
157
158 in.close();
159}
160
162{
163 for (auto node : _nodes)
164 {
165 delete node;
166 }
167 for (auto node : _split_nodes)
168 {
169 delete node;
170 }
171}
172
173std::unique_ptr<MeshLib::Mesh> GocadSGridReader::getMesh() const
174{
175 std::vector<MeshLib::Node*> nodes;
176 std::transform(_nodes.cbegin(), _nodes.cend(), std::back_inserter(nodes),
177 [](MeshLib::Node const* const node)
178 { return new MeshLib::Node(*node); });
179
180 std::vector<MeshLib::Element*> elements(createElements(nodes));
181 applySplitInformation(nodes, elements);
182
183 DBUG("Creating mesh from Gocad SGrid.");
184 std::unique_ptr<MeshLib::Mesh> mesh(new MeshLib::Mesh(
186 true /* compute_element_neighbors */));
188 DBUG("Mesh created.");
189
190 return mesh;
191}
192
194{
195 std::vector<std::string> const& prop_names(getPropertyNames());
196 for (auto const& name : prop_names)
197 {
198 auto prop = getProperty(name);
199 if (!prop)
200 {
201 continue;
202 }
203
204 DBUG("Adding Gocad property '{:s}' with {:d} values.", name,
205 prop->_property_data.size());
206
208 mesh, name, MeshLib::MeshItemType::Cell, 1);
209 if (pv == nullptr)
210 {
211 ERR("Could not create mesh property '{:s}'.", name);
212 continue;
213 }
214 pv->assign(prop->_property_data);
215 }
216}
217
218void GocadSGridReader::parseHeader(std::istream& in)
219{
220 std::string line;
221 while (std::getline(in, line))
222 {
223 if (line.front() == '}')
224 {
225 return;
226 }
227 if (line.substr(0, 27) == "double_precision_binary: on")
228 {
230 }
231 }
233 {
234 DBUG(
235 "GocadSGridReader::parseHeader(): _double_precision_binary == "
236 "true.");
237 }
238}
239
240void GocadSGridReader::parseDims(std::string const& line)
241{
242 std::size_t x_dim(0);
243 std::size_t y_dim(0);
244 std::size_t z_dim(0);
245 boost::tokenizer<> tok(line);
246 auto it(tok.begin());
247 it++; // overread token "AXIS"
248 it++; // overread "N"
249 std::stringstream ssx(*(it),
250 std::stringstream::in | std::stringstream::out);
251 ssx >> x_dim;
252 it++;
253 std::stringstream ssy(*it, std::stringstream::in | std::stringstream::out);
254 ssy >> y_dim;
255 it++;
256 std::stringstream ssz(*it, std::stringstream::in | std::stringstream::out);
257 ssz >> z_dim;
258 _index_calculator = Gocad::IndexCalculator(x_dim, y_dim, z_dim);
259 DBUG(
260 "x_dim = {:d}, y_dim = {:d}, z_dim = {:d} => #nodes = {:d}, #cells = "
261 "{:d}",
262 x_dim, y_dim, z_dim, _index_calculator._n_nodes,
263 _index_calculator._n_cells);
264}
265
266void GocadSGridReader::parseFileName(std::string const& line,
267 std::string& result_string) const
268{
269 boost::char_separator<char> sep(" \r");
270 boost::tokenizer<boost::char_separator<char>> tok(line, sep);
271 auto it(tok.begin());
272 ++it; // overread POINTS_FILE or FLAGS_FILE or REGION_FLAGS_FILE
273 result_string = _path + *it;
274}
275
280void GocadSGridReader::parseFaceSet(std::string& line, std::istream& in)
281{
282 // create and initialize a Gocad::Property object for storing face set data
283 Gocad::Property face_set_property;
284 face_set_property._property_id = _n_face_sets;
285 face_set_property._property_name = "FaceSet";
286 face_set_property._property_class_name = "FaceSetData";
287 face_set_property._property_unit = "unitless";
288 face_set_property._property_data_type = "double";
289 face_set_property._property_data_fname = "";
290 face_set_property._property_no_data_value = -1.0;
291 face_set_property._property_data.resize(_index_calculator._n_cells);
292 std::fill(face_set_property._property_data.begin(),
293 face_set_property._property_data.end(),
294 face_set_property._property_no_data_value);
295
296 std::istringstream iss(line);
297 std::istream_iterator<std::string> it(iss);
298 // Check first word is FACE_SET
299 if (*it != std::string("FACE_SET"))
300 {
301 ERR("Expected FACE_SET keyword but '{:s}' found.", it->c_str());
302 throw std::runtime_error(
303 "In GocadSGridReader::parseFaceSet() expected FACE_SET keyword not "
304 "found.");
305 }
306 ++it;
307 face_set_property._property_name += *it;
308 ++it;
309 auto const n_of_face_set_ids(
310 static_cast<std::size_t>(std::atoi(it->c_str())));
311 std::size_t face_set_id_cnt(0);
312
313 while (std::getline(in, line) && face_set_id_cnt < n_of_face_set_ids)
314 {
315 if (line.back() == '\r')
316 {
317 line.pop_back();
318 }
319 boost::char_separator<char> sep("\t ");
320 boost::tokenizer<boost::char_separator<char>> tokens(line, sep);
321
322 for (auto tok_it = tokens.begin(); tok_it != tokens.end();)
323 {
324 auto const id(static_cast<std::size_t>(std::atoi(tok_it->c_str())));
325 tok_it++;
326 auto const face_indicator(
327 static_cast<std::size_t>(std::atoi(tok_it->c_str())));
328 tok_it++;
329
330 if (id >= _index_calculator._n_nodes)
331 {
332 ERR("Face set id {:d} is greater than the number of nodes "
333 "({:d}).",
334 id, _index_calculator._n_nodes);
335 }
336 else
337 {
338 static_cast<GocadNode*>(_nodes[id])
339 ->setFaceSet(_n_face_sets, face_indicator);
340 std::array<std::size_t, 3> const c(
341 _index_calculator.getCoordsForID(id));
342 if (c[0] >= _index_calculator._x_dim - 1)
343 {
344 ERR("****** i coord {:d} to big for id {:d}.", c[0], id);
345 }
346 if (c[1] >= _index_calculator._y_dim - 1)
347 {
348 ERR("****** j coord {:d} to big for id {:d}.", c[1], id);
349 }
350 if (c[2] >= _index_calculator._z_dim - 1)
351 {
352 ERR("****** k coord {:d} to big for id {:d}.", c[2], id);
353 }
354 std::size_t const cell_id(
355 _index_calculator.getCellIdx(c[0], c[1], c[2]));
356 face_set_property._property_data[cell_id] =
357 static_cast<double>(face_indicator);
358 }
359 face_set_id_cnt++;
360 }
361 }
362
363 if (face_set_id_cnt != n_of_face_set_ids)
364 {
365 ERR("Expected {:d} number of face set ids, read {:d}.",
366 n_of_face_set_ids, face_set_id_cnt);
367 throw std::runtime_error(
368 "Expected number of face set points does not match number of read "
369 "points.");
370 }
371 _n_face_sets++;
372
373 // pre condition: split nodes are read already
374 for (auto split_node : _split_nodes)
375 {
376 std::size_t const id(_index_calculator(split_node->getGridCoords()));
377 split_node->transmitFaceDirections(*_nodes[id]);
378 }
379
380 _property_meta_data_vecs.push_back(face_set_property);
381}
382
383// Reads given number of bits (rounded up to next byte) into a bitset.
384// Used for reading region information which can be represented by some
385// number of bits.
386Bitset readBits(std::ifstream& in, const std::size_t bits)
387{
388 using block_t = Bitset::block_type;
389 auto const bytes = static_cast<std::size_t>(std::ceil(bits / 8.));
390 std::size_t const blocks =
391 bytes + 1 < sizeof(block_t) ? 1 : (bytes + 1) / sizeof(block_t);
392
393 std::vector<block_t> data;
394 data.resize(blocks);
395 std::fill_n(data.data(), blocks, 0);
396 in.read(reinterpret_cast<char*>(data.data()), bytes);
397
398 return Bitset(data.begin(), data.end());
399}
400
402{
403 std::ifstream in(_pnts_fname.c_str(), std::ios::binary);
404 if (!in)
405 {
406 ERR("Could not open points file '{:s}'.", _pnts_fname);
407 throw std::runtime_error("Could not open points file.");
408 }
409
410 std::size_t const n = _index_calculator._n_nodes;
411 _nodes.resize(n);
412
413 double coords[3];
414
415 std::size_t k = 0;
416 while (in && k < n * 3)
417 {
419 {
420 coords[k % 3] =
422 }
423 else
424 {
425 coords[k % 3] =
427 }
428 if ((k + 1) % 3 == 0)
429 {
430 const std::size_t layer_transition_idx(
431 _index_calculator.getCoordsForID(k / 3)[2]);
432 _nodes[k / 3] = new GocadNode(coords, k / 3, layer_transition_idx);
433 }
434 k++;
435 }
436 if (k != n * 3 && !in.eof())
437 {
438 ERR("Read different number of points. Expected {:d} floats, got "
439 "{:d}.\n",
440 n * 3, k);
441 }
442}
443
445 std::vector<Bitset> const& rf)
446{
447 DBUG(
448 "GocadSGridReader::mapRegionFlagsToCellProperties region_flags.size: "
449 "{:d}",
450 rf.size());
451
452 Gocad::Property region_flags;
453 region_flags._property_id = 0;
454 region_flags._property_name = "RegionFlags";
455 region_flags._property_class_name = "RegionFlags";
456 region_flags._property_unit = "unitless";
457 region_flags._property_data_type = "int";
458 region_flags._property_data_fname = "";
459 region_flags._property_no_data_value = -1;
460 std::size_t const n = _index_calculator._n_cells;
461 region_flags._property_data.resize(n);
462 std::fill(region_flags._property_data.begin(),
463 region_flags._property_data.end(), -1);
464
465 // region flags are stored in each node ijk and give the region index for
466 // the ijk-th cell.
467 for (std::size_t i(0); i < _index_calculator._x_dim - 1; i++)
468 {
469 for (std::size_t j(0); j < _index_calculator._y_dim - 1; j++)
470 {
471 for (std::size_t k(0); k < _index_calculator._z_dim - 1; k++)
472 {
473 std::size_t const cell_id(
474 _index_calculator.getCellIdx(i, j, k));
475 std::size_t const node_id(_index_calculator({i, j, k}));
476 for (auto& region : regions)
477 {
478 if (rf[node_id].test(region.bit))
479 {
480 region_flags._property_data[cell_id] += region.bit + 1;
481 }
482 }
483 }
484 }
485 }
486
487 _property_meta_data_vecs.push_back(region_flags);
488}
489
491{
492 for (auto& property : _property_meta_data_vecs)
493 {
494 std::string const& fname(property._property_data_fname);
495 if (property._property_data_fname.empty())
496 {
497 WARN("Empty filename for property {:s}.", property._property_name);
498 continue;
499 }
500 std::vector<float> float_properties = BaseLib::readBinaryVector<float>(
501 fname, 0, _index_calculator._n_cells);
502 DBUG(
503 "GocadSGridReader::readElementPropertiesBinary(): Read {:d} float "
504 "properties from binary file.",
505 _index_calculator._n_cells);
506
507 std::transform(float_properties.cbegin(), float_properties.cend(),
508 float_properties.begin(),
509 [](float const& val)
510 { return BaseLib::swapEndianness(val); });
511
512 property._property_data.resize(float_properties.size());
513 std::copy(float_properties.begin(), float_properties.end(),
514 property._property_data.begin());
515 if (property._property_data.empty())
516 {
517 ERR("Reading of element properties file '{:s}' failed.", fname);
518 }
519 }
520}
521
523{
524 std::vector<Bitset> result;
525
526 std::ifstream in(_region_flags_fname.c_str());
527 if (!in)
528 {
529 ERR("readRegionFlagsBinary(): Could not open file '{:s}' for input.\n",
531 in.close();
532 return result;
533 }
534
535 std::size_t const n = _index_calculator._n_nodes;
536 result.resize(n);
537
538 std::size_t k = 0;
539 while (in && k < n)
540 {
541 result[k++] = readBits(in, regions.size());
542 }
543 if (k != n && !in.eof())
544 {
545 ERR("Read different number of values. Expected {:d}, got {:d}.\n", n,
546 k);
547 }
548 return result;
549}
550std::vector<MeshLib::Element*> GocadSGridReader::createElements(
551 std::vector<MeshLib::Node*> const& nodes) const
552{
553 std::vector<MeshLib::Element*> elements;
554 elements.resize(_index_calculator._n_cells);
555 std::array<MeshLib::Node*, 8> element_nodes{};
556 std::size_t cnt(0);
557 for (std::size_t k(0); k < _index_calculator._z_dim - 1; k++)
558 {
559 for (std::size_t j(0); j < _index_calculator._y_dim - 1; j++)
560 {
561 for (std::size_t i(0); i < _index_calculator._x_dim - 1; i++)
562 {
563 element_nodes[0] = nodes[_index_calculator({i, j, k})];
564 element_nodes[1] = nodes[_index_calculator({i + 1, j, k})];
565 element_nodes[2] = nodes[_index_calculator({i + 1, j + 1, k})];
566 element_nodes[3] = nodes[_index_calculator({i, j + 1, k})];
567 element_nodes[4] = nodes[_index_calculator({i, j, k + 1})];
568 element_nodes[5] = nodes[_index_calculator({i + 1, j, k + 1})];
569 element_nodes[6] =
570 nodes[_index_calculator({i + 1, j + 1, k + 1})];
571 element_nodes[7] = nodes[_index_calculator({i, j + 1, k + 1})];
572 elements[cnt] = new MeshLib::Hex(
573 element_nodes, _index_calculator.getCellIdx(i, j, k));
574 cnt++;
575 }
576 }
577 }
578 return elements;
579}
580
582{
583 std::ifstream in(_fname.c_str());
584 if (!in)
585 {
586 ERR("Could not open '{:s}'.", _fname);
587 in.close();
588 return;
589 }
590
591 // read split information from the stratigraphic grid file
592 std::string line;
593 std::stringstream ss;
594 while (std::getline(in, line))
595 {
596 std::size_t pos(line.find("SPLIT "));
597 if (pos != std::string::npos)
598 {
599 ss << line.substr(pos + 6, line.size() - (pos + 6));
600 // read position in grid
601 std::array<std::size_t, 3> grid_coords{};
602 ss >> grid_coords[0];
603 ss >> grid_coords[1];
604 ss >> grid_coords[2];
605 // read coordinates for the split node
606 double coords[3];
607 ss >> coords[0];
608 ss >> coords[1];
609 ss >> coords[2];
610 // read the id
611 std::size_t id;
612 ss >> id;
613 // read the affected cells
614 std::bitset<8> affected_cells{};
615 for (std::size_t ac = 0; ac < 8; ++ac)
616 {
617 char bit;
618 ss >> bit;
619 affected_cells[ac] = bit != '0';
620 }
621 const std::size_t layer_transition_index(
622 _nodes[id]->getLayerTransitionIndex());
623 _split_nodes.push_back(new GocadSplitNode(coords, id, grid_coords,
624 affected_cells,
625 layer_transition_index));
626 }
627 }
628}
629
631 std::vector<MeshLib::Node*>& nodes,
632 std::vector<MeshLib::Element*> const& elements) const
633{
634 for (auto split_node : _split_nodes)
635 {
636 std::size_t const new_node_pos(nodes.size());
637 nodes.push_back(new MeshLib::Node(split_node->data(), new_node_pos));
638
639 // get grid coordinates
640 std::array<std::size_t, 3> const& gc(split_node->getGridCoords());
641 // get affected cells
642 auto const& affected_cells(split_node->getAffectedCells());
643 // get mesh node to substitute in elements
644 MeshLib::Node const* const node2sub(nodes[_index_calculator(gc)]);
645
646 if (affected_cells[0] && gc[0] < _index_calculator._x_dim - 1 &&
647 gc[1] < _index_calculator._y_dim - 1 &&
648 gc[2] < _index_calculator._z_dim - 1)
649 {
650 const std::size_t idx(
651 _index_calculator.getCellIdx(gc[0], gc[1], gc[2]));
652 modifyElement(elements[idx], node2sub, nodes[new_node_pos]);
653 }
654 if (affected_cells[1] && gc[0] > 0 &&
655 gc[1] < _index_calculator._y_dim - 1 &&
656 gc[2] < _index_calculator._z_dim - 1)
657 {
658 const std::size_t idx(
659 _index_calculator.getCellIdx(gc[0] - 1, gc[1], gc[2]));
660 modifyElement(elements[idx], node2sub, nodes[new_node_pos]);
661 }
662 if (affected_cells[2] && gc[1] > 0 &&
663 gc[0] < _index_calculator._x_dim - 1 &&
664 gc[2] < _index_calculator._z_dim - 1)
665 {
666 const std::size_t idx(
667 _index_calculator.getCellIdx(gc[0], gc[1] - 1, gc[2]));
668 modifyElement(elements[idx], node2sub, nodes[new_node_pos]);
669 }
670 if (affected_cells[3] && gc[0] > 0 && gc[1] > 0 &&
671 gc[2] < _index_calculator._z_dim - 1)
672 {
673 const std::size_t idx(
674 _index_calculator.getCellIdx(gc[0] - 1, gc[1] - 1, gc[2]));
675 modifyElement(elements[idx], node2sub, nodes[new_node_pos]);
676 }
677 if (affected_cells[4] && gc[2] > 0 &&
678 gc[0] < _index_calculator._x_dim - 1 &&
679 gc[1] < _index_calculator._y_dim - 1)
680 {
681 const std::size_t idx(
682 _index_calculator.getCellIdx(gc[0], gc[1], gc[2] - 1));
683 modifyElement(elements[idx], node2sub, nodes[new_node_pos]);
684 }
685 if (affected_cells[5] && gc[0] > 0 && gc[2] > 0 &&
686 gc[1] < _index_calculator._y_dim - 1)
687 {
688 const std::size_t idx(
689 _index_calculator.getCellIdx(gc[0] - 1, gc[1], gc[2] - 1));
690 modifyElement(elements[idx], node2sub, nodes[new_node_pos]);
691 }
692 if (affected_cells[6] && gc[1] > 0 && gc[2] > 0 &&
693 gc[0] < _index_calculator._x_dim - 1)
694 {
695 const std::size_t idx(
696 _index_calculator.getCellIdx(gc[0], gc[1] - 1, gc[2] - 1));
697 modifyElement(elements[idx], node2sub, nodes[new_node_pos]);
698 }
699 if (affected_cells[7] && gc[0] > 0 && gc[1] > 0 && gc[2] > 0)
700 {
701 const std::size_t idx(
702 _index_calculator.getCellIdx(gc[0] - 1, gc[1] - 1, gc[2] - 1));
703 modifyElement(elements[idx], node2sub, nodes[new_node_pos]);
704 }
705 }
706}
707
709 MeshLib::Node const* const node2sub,
710 MeshLib::Node* const substitute_node)
711{
712 // get the node pointers of the cell
713 MeshLib::Node* const* hex_nodes(hex->getNodes());
714 // search for the position the split node will be set to
715 MeshLib::Node* const* node_pos(
716 std::find(hex_nodes, hex_nodes + 8, node2sub));
717 // set the split node instead of the node2sub
718 if (node_pos != hex_nodes + 8)
719 {
720 const_cast<MeshLib::Node**>(
721 hex_nodes)[std::distance(hex_nodes, node_pos)] = substitute_node;
722 }
723}
724
726 std::string const& name) const
727{
728 auto const it(std::find_if(_property_meta_data_vecs.begin(),
730 [&name](Gocad::Property const& p)
731 { return p._property_name == name; }));
732 if (it == _property_meta_data_vecs.end())
733 {
734 return nullptr;
735 }
736 return &*it;
737}
738
739std::vector<std::string> GocadSGridReader::getPropertyNames() const
740{
741 std::vector<std::string> names;
742 std::transform(_property_meta_data_vecs.begin(),
744 std::back_inserter(names),
745 [](Gocad::Property const& p) { return p._property_name; });
746 return names;
747}
748
749std::unique_ptr<MeshLib::Mesh> GocadSGridReader::getFaceSetMesh(
750 std::size_t const face_set_number) const
751{
752 std::vector<MeshLib::Node*> face_set_nodes;
753 std::vector<MeshLib::Element*> face_set_elements;
754
755 for (auto const node : _nodes)
756 {
757 if (node->isMemberOfFaceSet(face_set_number))
758 {
759 addFaceSetQuad(node, face_set_number, face_set_nodes,
760 face_set_elements);
761 }
762 }
763
764 if (face_set_nodes.empty())
765 {
766 return nullptr;
767 }
768
769 for (auto const node : _split_nodes)
770 {
771 if (node->isMemberOfFaceSet(face_set_number))
772 {
773 if (node->getAffectedCells()[0])
774 {
775 addFaceSetQuad(node, face_set_number, face_set_nodes,
776 face_set_elements);
777 }
778 }
779 }
780
781 std::string const mesh_name("FaceSet-" + std::to_string(face_set_number));
782 return std::make_unique<MeshLib::Mesh>(
783 mesh_name, face_set_nodes, face_set_elements,
784 true /* compute_element_neighbors */);
785}
786
788 GocadNode* face_set_node, std::size_t face_set_number,
789 std::vector<MeshLib::Node*>& face_set_nodes,
790 std::vector<MeshLib::Element*>& face_set_elements) const
791{
792 std::array<MeshLib::Node*, 4> quad_nodes{};
793 quad_nodes[0] = new GocadNode(*face_set_node);
794 const std::size_t id(face_set_node->getID());
795 std::array<std::size_t, 3> const c(_index_calculator.getCoordsForID(id));
796
797 const FaceDirection dir(face_set_node->getFaceDirection(face_set_number));
798 switch (dir)
799 {
800 case FaceDirection::U:
801 quad_nodes[1] = new GocadNode(
802 *_nodes[_index_calculator({c[0], c[1] + 1, c[2]})]);
803 quad_nodes[2] = new GocadNode(
804 *_nodes[_index_calculator({c[0], c[1] + 1, c[2] + 1})]);
805 quad_nodes[3] = new GocadNode(
806 *_nodes[_index_calculator({c[0], c[1], c[2] + 1})]);
807 break;
808 case FaceDirection::V:
809 quad_nodes[1] = new GocadNode(
810 *_nodes[_index_calculator({c[0] + 1, c[1], c[2]})]);
811 quad_nodes[2] = new GocadNode(
812 *_nodes[_index_calculator({c[0] + 1, c[1], c[2] + 1})]);
813 quad_nodes[3] = new GocadNode(
814 *_nodes[_index_calculator({c[0], c[1], c[2] + 1})]);
815 break;
816 case FaceDirection::W:
817 quad_nodes[1] = new GocadNode(
818 *_nodes[_index_calculator({c[0] + 1, c[1], c[2]})]);
819 quad_nodes[2] = new GocadNode(
820 *_nodes[_index_calculator({c[0] + 1, c[1] + 1, c[2]})]);
821 quad_nodes[3] = new GocadNode(
822 *_nodes[_index_calculator({c[0], c[1] + 1, c[2]})]);
823 break;
824 default:
825 ERR("Could not create face for node with id {:d}.", id);
826 }
827 std::copy(begin(quad_nodes), end(quad_nodes),
828 back_inserter(face_set_nodes));
829 face_set_elements.push_back(new MeshLib::Quad(quad_nodes));
830}
831
832} // end namespace Gocad
833} // end namespace FileIO
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:22
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
FaceDirection getFaceDirection(std::size_t const face_set_number) const
Definition GocadNode.h:84
Gocad::Property const * getProperty(std::string const &name) const
std::vector< Gocad::Property > _property_meta_data_vecs
std::vector< MeshLib::Element * > createElements(std::vector< MeshLib::Node * > const &nodes) const
std::unique_ptr< MeshLib::Mesh > getFaceSetMesh(std::size_t const face_set_number) const
std::vector< GocadNode * > _nodes
std::vector< Gocad::Region > regions
std::unique_ptr< MeshLib::Mesh > getMesh() const
std::vector< Bitset > readRegionFlagsBinary() const
void addGocadPropertiesToMesh(MeshLib::Mesh &mesh) const
void applySplitInformation(std::vector< MeshLib::Node * > &nodes, std::vector< MeshLib::Element * > const &elements) const
void mapRegionFlagsToCellProperties(std::vector< Bitset > const &rf)
Gocad::CoordinateSystem _coordinate_system
static void modifyElement(MeshLib::Element const *hex, MeshLib::Node const *node2sub, MeshLib::Node *substitute_node)
void parseFaceSet(std::string &line, std::istream &in)
void parseFileName(std::string const &line, std::string &result_string) const
Gocad::IndexCalculator _index_calculator
std::vector< GocadSplitNode * > _split_nodes
std::vector< std::string > getPropertyNames() const
void addFaceSetQuad(GocadNode *face_set_node, std::size_t face_set_number, std::vector< MeshLib::Node * > &face_set_nodes, std::vector< MeshLib::Element * > &face_set_elements) const
std::vector< Gocad::Layer > layers
std::size_t getID() const
virtual Node *const * getNodes() const =0
Get array of element nodes.
T readBinaryValue(std::istream &in)
std::string extractBaseNameWithoutExtension(std::string const &pathname)
double swapEndianness(double const &v)
template std::vector< float > readBinaryVector< float >(std::string const &, std::size_t const, std::size_t const)
boost::dynamic_bitset<> Bitset
Property parseGocadPropertyMetaData(std::string &line, std::istream &in, std::string const &path)
Bitset readBits(std::ifstream &in, const std::size_t bits)
Layer parseLayer(std::string const &line, std::vector< Region > const &regions)
Definition Layer.cpp:23
Region parseRegion(std::string const &line)
Definition Region.cpp:20
PropertyVector< T > * getOrCreateMeshProperty(Mesh &mesh, std::string const &property_name, MeshItemType const item_type, int const number_of_components)
TemplateElement< MeshLib::QuadRule4 > Quad
Definition Quad.h:17
TemplateElement< MeshLib::HexRule8 > Hex
Definition Hex.h:14