17#include "../general/tinyxml2.h"
43 MFEM_VERIFY(version == 10 || version == 12 || version == 13,
44 "unknown MFEM mesh version");
52 MFEM_VERIFY(ident ==
"dimension",
"invalid mesh file");
58 MFEM_VERIFY(ident ==
"elements",
"invalid mesh file");
71 MFEM_VERIFY(ident ==
"attribute_sets",
"invalid mesh file");
81 MFEM_VERIFY(ident ==
"boundary",
"invalid mesh file");
94 MFEM_VERIFY(ident ==
"bdr_attribute_sets",
"invalid mesh file");
104 MFEM_VERIFY(ident ==
"vertices",
"invalid mesh file");
108 input >> ws >> ident;
109 if (ident !=
"nodes")
152 input >>
a >> p1 >> p2;
161 input >>
a >> ind[0];
169 int ints[32], attr, n;
180 >> ints[0] >> ints[1];
181 ints[0]--; ints[1]--;
191 for (
int j = 0; j < n; j++)
216 for (
int j = 0; j <
Dim; j++)
241 for (
int j = 0; j <
Dim; j++)
252 for (
int j = 0; j < 4; j++)
257#ifdef MFEM_USE_MEMALLOC
274 for (
int j = 0; j < 3; j++)
285 int i, j, ints[32], attr;
286 const int buflen = 1024;
298 input.getline(buf, buflen);
299 input.getline(buf, buflen);
301 input.getline(buf, buflen);
302 input.getline(buf, buflen);
303 input.getline(buf, buflen);
310 input.getline(buf, buflen);
317 input >> vari >> attr;
318 for (j = 0; j < 4; j++)
323 input.getline(buf, buflen);
324 input.getline(buf, buflen);
333 input.getline(buf, buflen);
334 input.getline(buf, buflen);
336 input.getline(buf, buflen);
337 input.getline(buf, buflen);
338 input.getline(buf, buflen);
345 input.getline(buf, buflen);
351 input >> vari >> attr;
352 for (j = 0; j < 8; j++)
357 input.getline(buf, buflen);
365 for (j = 0; j < 4; j++)
370 input.getline(buf, buflen);
378{ 0, 1, 2, 3, 4, 7, 5, 6, 8, 9 };
383{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
388{ 0, 2, 1, 3, 5, 4, 8, 7, 6, 11, 10, 9, 12, 14, 13, 17, 16, 15};
393 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
394 24, 22, 21, 23, 20, 25, 26
401 int &curved,
int &read_gf,
bool &finalize_topo)
403 int np = points.
Size()/3;
409 bool legacy_elem =
false, lagrange_elem =
false;
413 int j = (i > 0) ? cell_offsets[i-1] : 0;
414 int ct = cell_types[i];
417 if (cell_attributes.
Size() > 0)
419 elements[i]->SetAttribute(cell_attributes[i]);
425 int prism_vertices[6];
426 for (
int k=0; k<6; ++k)
430 elements[i]->SetVertices(prism_vertices);
434 elements[i]->SetVertices(&cell_data[j]);
441 else { legacy_elem =
true; }
443 MFEM_VERIFY(
Dim == -1 ||
Dim == elem_dim,
444 "Elements with different dimensions are not supported");
445 MFEM_VERIFY(order == -1 || order == elem_order,
446 "Elements with different orders are not supported");
447 MFEM_VERIFY(legacy_elem != lagrange_elem,
448 "Mixing of legacy and Lagrange cell types is not supported");
457 real_t min_value, max_value;
458 for (
int d = 3; d > 0; --d)
460 min_value = max_value = points(3*0 + d-1);
461 for (
int i = 1; i < np; i++)
463 min_value = std::min(min_value, points(3*i + d-1));
464 max_value = std::max(max_value, points(3*i + d-1));
465 if (min_value != max_value)
475 if (order == 1 && !lagrange_elem)
479 for (
int i = 0; i < np; i++)
502 int *v =
elements[i]->GetVertices();
503 int nv =
elements[i]->GetNVertices();
504 for (
int j = 0; j < nv; j++)
506 if (pts_dof[v[j]] == -1) { pts_dof[v[j]] = 0; }
515 for (
int i = 0; i < np; i++)
517 if (pts_dof[i] != -1)
525 int *v =
elements[i]->GetVertices();
526 int nv =
elements[i]->GetNVertices();
527 for (
int j = 0; j < nv; j++)
529 v[j] = pts_dof[v[j]];
534 for (
int i = 0; i < np; i++)
568 switch (
elements[i]->GetGeometryType())
586 int offset = (i == 0) ? 0 : cell_offsets[i-1];
587 for (
int j = 0; j < dofs.
Size(); j++)
589 if (pts_dof[cell_data[offset+j]] == -1)
591 pts_dof[cell_data[offset+j]] = dofs[vtk_mfem[j]];
595 if (pts_dof[cell_data[offset+j]] != dofs[vtk_mfem[j]])
597 MFEM_ABORT(
"VTK mesh: inconsistent quadratic mesh!");
613 std::map<Geometry::Type,Array<int>> vtk_inv_maps;
614 std::map<Geometry::Type,const Array<int>*> lex_orderings;
623 if (vtk_inv_map.
Size() == 0)
628 for (
int j=0; j<vtk_map.
Size(); ++j)
630 vtk_inv_map[vtk_map[j]] = j;
633 const Array<int> *&lex_ordering = lex_orderings[geom];
639 MFEM_ASSERT(nodal_fe != NULL,
"Unsupported element type");
643 for (
int lex_idx = 0; lex_idx < dofs.
Size(); lex_idx++)
645 int mfem_idx = (*lex_ordering)[lex_idx];
646 int vtk_idx = vtk_inv_map[lex_idx];
647 int pt_idx = cell_data[n + vtk_idx];
648 if (pts_dof[pt_idx] == -1)
650 pts_dof[pt_idx] = dofs[mfem_idx];
654 if (pts_dof[pt_idx] != dofs[mfem_idx])
656 MFEM_ABORT(
"VTK mesh: inconsistent Lagrange mesh!");
665 for (
int i = 0; i < np; i++)
668 if (pts_dof[i] != -1)
670 dofs[0] = pts_dof[i];
672 for (
int d = 0; d < dofs.
Size(); d++)
674 (*Nodes)(dofs[d]) = points(3*i+d);
685using namespace tinyxml2;
691 if (s1 == NULL || s2 == NULL) {
return false; }
692 return strcmp(s1, s2) == 0;
700struct BufferReaderBase
702 enum HeaderType { UINT32_HEADER, UINT64_HEADER };
703 virtual void ReadBinary(
const char *buf,
void *dest,
int n)
const = 0;
704 virtual void ReadBase64(
const char *txt,
void *dest,
int n)
const = 0;
705 virtual ~BufferReaderBase() { }
718template <
typename T,
typename F>
719struct BufferReader : BufferReaderBase
722 HeaderType header_type;
723 BufferReader(
bool compressed_, HeaderType header_type_)
724 : compressed(compressed_), header_type(header_type_) { }
727 size_t HeaderEntrySize()
const
729 return header_type == UINT64_HEADER ?
sizeof(uint64_t) : sizeof(uint32_t);
735 uint64_t ReadHeaderEntry(
const char *header_buf)
const
738 : bin_io::
read<uint32_t>(header_buf);
747 int NumHeaderBytes(
const char *header_buf)
const
749 if (!compressed) {
return static_cast<int>(HeaderEntrySize()); }
750 return (3 + ReadHeaderEntry(header_buf))*HeaderEntrySize();
758 void ReadBinaryWithHeader(
const char *header_buf,
const char *buf,
759 void *dest_void,
int n)
const
761 std::vector<char> uncompressed_data;
762 T *dest =
static_cast<T*
>(dest_void);
772 int header_entry_size = HeaderEntrySize();
773 int nblocks = ReadHeaderEntry(header_buf);
774 header_buf += header_entry_size;
775 std::vector<size_t> header(nblocks + 2);
776 for (
int i=0; i<nblocks+2; ++i)
778 header[i] = ReadHeaderEntry(header_buf);
779 header_buf += header_entry_size;
781 uncompressed_data.resize((nblocks-1)*header[0] + header[1]);
782 Bytef *dest_ptr = (Bytef *)uncompressed_data.data();
783 Bytef *dest_start = dest_ptr;
784 const Bytef *source_ptr = (
const Bytef *)buf;
785 for (
int i=0; i<nblocks; ++i)
787 uLongf source_len = header[i+2];
788 uLong dest_len = (i == nblocks-1) ? header[1] : header[0];
789 int res = uncompress(dest_ptr, &dest_len, source_ptr, source_len);
790 MFEM_VERIFY(res == Z_OK,
"Error uncompressing");
791 dest_ptr += dest_len;
792 source_ptr += source_len;
794 MFEM_VERIFY(
size_t(
sizeof(F)*n) ==
size_t(dest_ptr - dest_start),
795 "AppendedData: wrong data size");
796 buf = uncompressed_data.data();
798 MFEM_ABORT(
"MFEM must be compiled with zlib enabled to uncompress.")
805 MFEM_VERIFY(
sizeof(F)*n == ReadHeaderEntry(header_buf),
806 "AppendedData: wrong data size");
809 if (std::is_same_v<T, F>)
812 memcpy(dest, buf,
sizeof(T)*n);
816 for (
int i=0; i<n; ++i)
827 void ReadBinary(
const char *buf,
void *dest,
int n)
const override
829 ReadBinaryWithHeader(buf, buf + NumHeaderBytes(buf), dest, n);
836 void ReadBase64(
const char *txt,
void *dest,
int n)
const override
841 if (*txt !=
' ' && *txt !=
'\n') {
break; }
848 std::vector<char> nblocks_buf;
851 std::vector<char> data, header;
855 nblocks_buf.data())));
859 ReadBinaryWithHeader(header.data(), data.data(), dest, n);
863 std::vector<char> data;
865 ReadBinary(data.data(), dest, n);
876 const char *appended_data, *byte_order, *compressor;
877 enum AppendedDataEncoding { RAW, BASE64 };
878 map<string,BufferReaderBase*> type_map;
879 AppendedDataEncoding encoding;
885 XMLDataReader(
const XMLElement *vtk,
const XMLElement *vtu)
888 BufferReaderBase::HeaderType htype;
891 htype = BufferReaderBase::UINT64_HEADER;
895 htype = BufferReaderBase::UINT32_HEADER;
899 byte_order = vtk->Attribute(
"byte_order");
903 compressor = vtk->Attribute(
"compressor");
904 bool compressed = (compressor != NULL);
907 appended_data = NULL;
908 for (
const XMLElement *xml_elem = vtu->NextSiblingElement();
910 xml_elem = xml_elem->NextSiblingElement())
914 const char *encoding_str = xml_elem->Attribute(
"encoding");
917 appended_data = xml_elem->GetAppendedData();
922 appended_data = xml_elem->GetText();
925 MFEM_VERIFY(appended_data != NULL,
"Invalid AppendedData");
927 bool found_leading_underscore =
false;
928 while (*appended_data)
931 if (*appended_data ==
'_')
933 found_leading_underscore =
true;
938 MFEM_VERIFY(found_leading_underscore,
"Invalid AppendedData");
943 type_map[
"Int8"] =
new BufferReader<int, int8_t>(compressed, htype);
944 type_map[
"Int16"] =
new BufferReader<int, int16_t>(compressed, htype);
945 type_map[
"Int32"] =
new BufferReader<int, int32_t>(compressed, htype);
946 type_map[
"Int64"] =
new BufferReader<int, int64_t>(compressed, htype);
947 type_map[
"UInt8"] =
new BufferReader<int, uint8_t>(compressed, htype);
948 type_map[
"UInt16"] =
new BufferReader<int, uint16_t>(compressed, htype);
949 type_map[
"UInt32"] =
new BufferReader<int, uint32_t>(compressed, htype);
950 type_map[
"UInt64"] =
new BufferReader<int, uint64_t>(compressed, htype);
951 type_map[
"Float32"] =
new BufferReader<double, float>(compressed, htype);
952 type_map[
"Float64"] =
new BufferReader<double, double>(compressed, htype);
958 template <
typename T>
959 void Read(
const XMLElement *xml_elem, T *dest,
int n)
961 static const char *erstr =
"Error reading XML DataArray";
962 MFEM_VERIFY(
StringCompare(xml_elem->Name(),
"DataArray"), erstr);
963 const char *format = xml_elem->Attribute(
"format");
966 const char *txt = xml_elem->GetText();
967 MFEM_VERIFY(txt != NULL, erstr);
968 std::istringstream data_stream(txt);
969 for (
int i=0; i<n; ++i) { data_stream >> dest[i]; }
973 VerifyBinaryOptions();
974 int offset = xml_elem->IntAttribute(
"offset");
975 const char *
type = xml_elem->Attribute(
"type");
976 MFEM_VERIFY(type != NULL, erstr);
977 BufferReaderBase *reader = type_map[
type];
978 MFEM_VERIFY(reader != NULL, erstr);
979 MFEM_VERIFY(appended_data != NULL,
"No AppendedData found");
982 reader->ReadBinary(appended_data + offset, dest, n);
986 reader->ReadBase64(appended_data + offset, dest, n);
991 VerifyBinaryOptions();
992 const char *txt = xml_elem->GetText();
993 MFEM_VERIFY(txt != NULL, erstr);
994 const char *
type = xml_elem->Attribute(
"type");
995 if (type == NULL) { MFEM_ABORT(erstr); }
996 BufferReaderBase *reader = type_map[
type];
997 if (reader == NULL) { MFEM_ABORT(erstr); }
998 reader->ReadBase64(txt, dest, n);
1002 MFEM_ABORT(
"Invalid XML VTK DataArray format");
1010 void VerifyByteOrder()
const
1015 MFEM_ABORT(
"Converting between different byte orders is unsupported.");
1022 void VerifyCompressor()
const
1024 if (compressor && !
StringCompare(compressor,
"vtkZLibDataCompressor"))
1026 MFEM_ABORT(
"Unsupported compressor. Only zlib is supported.")
1028#ifndef MFEM_USE_ZLIB
1029 MFEM_VERIFY(compressor == NULL,
"MFEM must be compiled with zlib enabled "
1030 "to support reading compressed data.");
1036 void VerifyBinaryOptions()
const
1044 for (
auto &x : type_map) {
delete x.second; }
1051 bool &finalize_topo,
const std::string &xml_prefix)
1053 using namespace vtk_xml;
1055 static const char *erstr =
"XML parsing error";
1058 std::vector<char> buf(xml_prefix.begin(), xml_prefix.end());
1059 std::istreambuf_iterator<char> eos;
1060 buf.insert(buf.end(), std::istreambuf_iterator<char>(input), eos);
1061 buf.push_back(
'\0');
1064 xml.Parse(buf.data(), buf.size());
1065 if (xml.ErrorID() != XML_SUCCESS)
1067 MFEM_ABORT(
"Error parsing XML VTK file.\n" << xml.ErrorStr());
1070 const XMLElement *vtkfile = xml.FirstChildElement();
1071 MFEM_VERIFY(vtkfile, erstr);
1072 MFEM_VERIFY(StringCompare(vtkfile->Name(),
"VTKFile"), erstr);
1073 const XMLElement *vtu = vtkfile->FirstChildElement();
1074 MFEM_VERIFY(vtu, erstr);
1075 MFEM_VERIFY(StringCompare(vtu->Name(),
"UnstructuredGrid"), erstr);
1077 XMLDataReader data_reader(vtkfile, vtu);
1080 const XMLElement *piece = vtu->FirstChildElement();
1081 MFEM_VERIFY(StringCompare(piece->Name(),
"Piece"), erstr);
1082 MFEM_VERIFY(piece->NextSiblingElement() == NULL,
1083 "XML VTK meshes with more than one Piece are not supported");
1084 int npts = piece->IntAttribute(
"NumberOfPoints");
1085 int ncells = piece->IntAttribute(
"NumberOfCells");
1089 const XMLElement *pts_xml;
1090 for (pts_xml = piece->FirstChildElement();
1092 pts_xml = pts_xml->NextSiblingElement())
1094 if (StringCompare(pts_xml->Name(),
"Points"))
1096 const XMLElement *pts_data = pts_xml->FirstChildElement();
1097 MFEM_VERIFY(pts_data->IntAttribute(
"NumberOfComponents") == 3,
1098 "XML VTK Points DataArray must have 3 components");
1099 data_reader.Read(pts_data, points.
GetData(), points.
Size());
1103 if (pts_xml == NULL) { MFEM_ABORT(erstr); }
1106 Array<int> cell_data, cell_offsets(ncells), cell_types(ncells);
1107 const XMLElement *cells_xml;
1108 for (cells_xml = piece->FirstChildElement();
1110 cells_xml = cells_xml->NextSiblingElement())
1112 if (StringCompare(cells_xml->Name(),
"Cells"))
1114 const XMLElement *cell_data_xml = NULL;
1115 for (
const XMLElement *data_xml = cells_xml->FirstChildElement();
1117 data_xml = data_xml->NextSiblingElement())
1119 const char *data_name = data_xml->Attribute(
"Name");
1120 if (StringCompare(data_name,
"offsets"))
1122 data_reader.Read(data_xml, cell_offsets.GetData(), ncells);
1124 else if (StringCompare(data_name,
"types"))
1126 data_reader.Read(data_xml, cell_types.
GetData(), ncells);
1128 else if (StringCompare(data_name,
"connectivity"))
1134 cell_data_xml = data_xml;
1137 MFEM_VERIFY(cell_data_xml != NULL, erstr);
1138 int cell_data_size = cell_offsets.Last();
1139 cell_data.
SetSize(cell_data_size);
1140 data_reader.Read(cell_data_xml, cell_data.
GetData(), cell_data_size);
1144 if (cells_xml == NULL) { MFEM_ABORT(erstr); }
1150 bool found_attributes =
false;
1151 for (
const XMLElement *cell_data_xml = piece->FirstChildElement();
1152 cell_data_xml != NULL;
1153 cell_data_xml = cell_data_xml->NextSiblingElement())
1155 const bool is_cell_data =
1156 StringCompare(cell_data_xml->Name(),
"CellData");
1157 const bool is_material =
1158 StringCompare(cell_data_xml->Attribute(
"Scalars"),
"material");
1159 const bool is_attribute =
1160 StringCompare(cell_data_xml->Attribute(
"Scalars"),
"attribute");
1161 if (is_cell_data && (is_material || (is_attribute && !found_attributes)))
1163 found_attributes =
true;
1164 const XMLElement *data_xml = cell_data_xml->FirstChildElement();
1165 if (data_xml != NULL && StringCompare(data_xml->Name(),
"DataArray"))
1167 cell_attributes.
SetSize(ncells);
1168 data_reader.Read(data_xml, cell_attributes.
GetData(), ncells);
1173 CreateVTKMesh(points, cell_data, cell_offsets, cell_types, cell_attributes,
1174 curved, read_gf, finalize_topo);
1178 bool &finalize_topo)
1187 getline(input, buff);
1188 getline(input, buff);
1190 if (buff !=
"ASCII")
1192 MFEM_ABORT(
"VTK mesh is not in ASCII format!");
1197 getline(input, buff);
1199 if (!input.good()) { MFEM_ABORT(
"VTK mesh is not UNSTRUCTURED_GRID!"); }
1201 while (buff !=
"DATASET UNSTRUCTURED_GRID");
1210 MFEM_ABORT(
"VTK mesh does not have POINTS data!");
1213 while (buff !=
"POINTS");
1218 getline(input, buff);
1219 points.
Load(input, 3*np);
1234 MFEM_ABORT(
"VTK mesh does not have CELLS data!");
1237 while (buff !=
"CELLS");
1241 if (buff ==
"CELLS")
1244 input >> ncells >> n >> ws;
1246 cell_data.
SetSize(n - ncells);
1248 for (
int i=0; i<ncells; ++i)
1252 cell_offsets[i] = offset + nv;
1253 for (
int j=0; j<nv; ++j)
1255 input >> cell_data[offset + j];
1262 input >> ws >> buff;
1265 MFEM_VERIFY(buff ==
"CELL_TYPES",
"CELL_TYPES not provided in VTK mesh.")
1267 cell_types.
Load(ncells, input);
1269 while ((input.good()) && (buff !=
"CELL_DATA"))
1273 getline(input, buff);
1278 bool found_attributes =
false;
1279 while ((input.good()))
1281 getline(input, buff);
1282 if (buff.rfind(
"POINT_DATA") == 0)
1286 else if (buff.rfind(
"SCALARS material") == 0 ||
1287 (buff.rfind(
"SCALARS attribute") == 0 && !found_attributes))
1289 found_attributes =
true;
1290 getline(input, buff);
1291 if (buff.rfind(
"LOOKUP_TABLE default") != 0)
1293 MFEM_ABORT(
"Invalid LOOKUP_TABLE for material array in VTK file.");
1295 cell_attributes.
Load(ncells, input);
1307 CreateVTKMesh(points, cell_data, cell_offsets, cell_types, cell_attributes,
1308 curved, read_gf, finalize_topo);
1312 bool spacing,
bool nc)
1383 MFEM_VERIFY(input.get() ==
'=',
1384 "Inline mesh expected '=' after keyword " << name);
1391 else if (name ==
"ny")
1395 else if (name ==
"nz")
1399 else if (name ==
"sx")
1403 else if (name ==
"sy")
1407 else if (name ==
"sz")
1411 else if (name ==
"type")
1415 if (eltype ==
"segment")
1419 else if (eltype ==
"quad")
1423 else if (eltype ==
"tri")
1427 else if (eltype ==
"hex")
1431 else if (eltype ==
"wedge")
1435 else if (eltype ==
"pyramid")
1439 else if (eltype ==
"tet")
1445 MFEM_ABORT(
"unrecognized element type (read '" << eltype
1446 <<
"') in inline mesh format. "
1447 "Allowed: segment, tri, quad, tet, hex, wedge");
1452 MFEM_ABORT(
"unrecognized keyword (" << name
1453 <<
") in inline mesh format. "
1454 "Allowed: nx, ny, nz, type, sx, sy, sz");
1459 if (input.peek() ==
';')
1474 MFEM_VERIFY(nx > 0 && sx > 0.0,
1475 "invalid 1D inline mesh format, all values must be "
1477 <<
" nx = " << nx <<
"\n"
1478 <<
" sx = " << sx <<
"\n");
1483 MFEM_VERIFY(nx > 0 && ny > 0 && sx > 0.0 && sy > 0.0,
1484 "invalid 2D inline mesh format, all values must be "
1486 <<
" nx = " << nx <<
"\n"
1487 <<
" ny = " << ny <<
"\n"
1488 <<
" sx = " << sx <<
"\n"
1489 <<
" sy = " << sy <<
"\n");
1490 Make2D(nx, ny, type, sx, sy, generate_edges,
true);
1495 MFEM_VERIFY(nx > 0 && ny > 0 && nz > 0 &&
1496 sx > 0.0 && sy > 0.0 && sz > 0.0,
1497 "invalid 3D inline mesh format, all values must be "
1499 <<
" nx = " << nx <<
"\n"
1500 <<
" ny = " << ny <<
"\n"
1501 <<
" nz = " << nz <<
"\n"
1502 <<
" sx = " << sx <<
"\n"
1503 <<
" sy = " << sy <<
"\n"
1504 <<
" sz = " << sz <<
"\n");
1505 Make3D(nx, ny, nz, type, sx, sy, sz,
true);
1510 MFEM_ABORT(
"For inline mesh, must specify an element type ="
1511 " [segment, tri, quad, tet, hex, wedge]");
1515#ifdef MFEM_USE_NETCDF
1523 1,2,3,4,5,7,8,6,9,10
1529 1,2,3,4,5,6,7,8,9,10,11,
1532 12,17,18,19,20,13,14,15,
1535 16,22,26,25,27,24,23,21
1540 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
1545 1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 14, 15, 10, 11, 12, 16, 17, 18
1646 CubitElement() =
delete;
1649 ~CubitElement() =
default;
1658 inline size_t GetNumFaces()
const {
return _num_faces; }
1661 inline size_t GetNumVertices()
const {
return _num_vertices; }
1664 inline size_t GetNumNodes()
const {
return _num_nodes; }
1667 size_t GetNumFaceVertices(
size_t iface = 1)
const;
1670 inline uint8_t GetOrder()
const {
return _order; }
1673 Element * BuildElement(Mesh & mesh,
const int * vertex_ids,
1674 const int block_id)
const;
1677 Element * BuildBoundaryElement(Mesh & mesh,
const int iface,
1678 const int * vertex_ids,
const int sideset_id)
const;
1691 Element * NewElement(Mesh & mesh,
Geometry::Type geom,
const int *vertices,
1692 const int attribute)
const;
1699 size_t _num_vertices;
1706 _element_type = element_type;
1708 switch (element_type)
1783 MFEM_ABORT(
"Unsupported Cubit element type " << element_type <<
".");
1809 MFEM_ABORT(
"Unsupported 3D element with " << num_nodes <<
" nodes.");
1826 MFEM_ABORT(
"Unsupported 2D element with " << num_nodes <<
" nodes.");
1835 return Get2DElementType(num_nodes);
1839 return Get3DElementType(num_nodes);
1843 MFEM_ABORT(
"Unsupported Cubit dimension " <<
dimension <<
".");
1847CubitFaceType CubitElement::GetFaceType(
size_t side_id)
const
1850 bool valid_id = (side_id >= 1 &&
1851 side_id <= GetNumFaces());
1854 MFEM_ABORT(
"Encountered invalid side ID: " << side_id <<
".");
1857 switch (_element_type)
1884 MFEM_ABORT(
"Unknown element type: " << _element_type <<
".");
1889size_t CubitElement::GetNumFaceVertices(
size_t side_id)
const
1891 switch (GetFaceType(side_id))
1903 MFEM_ABORT(
"Unrecognized Cubit face type " << GetFaceType(side_id) <<
".");
1909 const int *vertices,
1910 const int attribute)
const
1912 Element *new_element = mesh.NewElement(geom);
1914 new_element->SetAttribute(attribute);
1920 const int *vertex_ids,
1921 const int block_id)
const
1923 switch (GetElementType())
1944 MFEM_ABORT(
"Unsupported Cubit element type encountered.");
1949mfem::Element * CubitElement::BuildBoundaryElement(Mesh &mesh,
1951 const int *vertex_ids,
1952 const int sideset_id)
const
1954 switch (GetFaceType(face_id))
1966 MFEM_ABORT(
"Unsupported Cubit face type encountered.");
1979 CubitBlock() =
delete;
1980 ~CubitBlock() =
default;
1990 const CubitElement & GetBlockElement(
int block_id)
const;
2000 uint8_t GetOrder()
const;
2001 inline uint8_t GetDimension()
const {
return _dimension; }
2003 inline size_t GetNumBlocks()
const {
return BlockIDs().size(); }
2004 inline bool HasBlocks()
const {
return !BlockIDs().empty(); }
2011 void CheckElementBlockIsCompatible(
const CubitElement & new_block_element)
2017 void ClearBlockElements();
2022 inline const std::set<int> & BlockIDs()
const {
return _block_ids; }
2024 bool HasBlockID(
int block_id)
const;
2025 bool ValidBlockID(
int block_id)
const;
2026 bool ValidDimension(
int dimension)
const;
2032 std::set<int> _block_ids;
2037 std::map<int, CubitElement> _block_element_for_block_id;
2050 MFEM_ABORT(
"Invalid dimension '" <<
dimension <<
"' specified.");
2055 ClearBlockElements();
2061 if (HasBlockID(block_id))
2063 MFEM_ABORT(
"Block with ID '" << block_id <<
"' has already been added.");
2065 else if (!ValidBlockID(block_id))
2067 MFEM_ABORT(
"Illegal block ID '" << block_id <<
"'.");
2070 CubitElement block_element = CubitElement(element_type);
2075 CheckElementBlockIsCompatible(block_element);
2079 _order = block_element.GetOrder();
2082 _block_ids.insert(block_id);
2083 _block_element_for_block_id.emplace(block_id,
2088CubitBlock::GetOrder()
const
2092 MFEM_ABORT(
"No elements have been added.");
2099CubitBlock::ClearBlockElements()
2103 _block_element_for_block_id.clear();
2107CubitBlock::HasBlockID(
int block_id)
const
2109 return (_block_ids.count(block_id) > 0);
2113CubitBlock::ValidBlockID(
int block_id)
const
2115 return (block_id > 0);
2119CubitBlock::ValidDimension(
int dimension)
const
2125CubitBlock::GetBlockElement(
int block_id)
const
2127 if (!HasBlockID(block_id))
2129 MFEM_ABORT(
"No element info for block ID '" << block_id <<
"'.");
2132 return _block_element_for_block_id.at(block_id);
2136CubitBlock::CheckElementBlockIsCompatible(
const CubitElement &
2137 new_block_element)
const
2145 if (GetOrder() != new_block_element.GetOrder())
2147 MFEM_ABORT(
"All block elements must be of the same order.");
2157 NetCDFReader() =
delete;
2158 NetCDFReader(
const std::string fname);
2163 bool HasVariable(
const char * name);
2166 void ReadVariable(
const char * name,
int * data);
2169 void ReadVariable(
const char * name,
double * data);
2172 bool HasDimension(
const char * name);
2175 void ReadDimension(
const char * name,
size_t *
dimension);
2178 void BuildIDToNameMap(
const vector<int> & ids,
2179 unordered_map<int, string> & ids_to_names,
2180 const string & quantity_name);
2184 void CheckForNetCDFError();
2187 int ReadVariableID(
const char * name);
2190 int ReadDimensionID(
const char * name);
2194 void HandleNetCDFError(
const int error_code);
2196 int _netcdf_status{NC_NOERR};
2197 int _netcdf_descriptor;
2200 char *_name_buffer{NULL};
2204NetCDFReader::NetCDFReader(
const std::string fname)
2206 _netcdf_status = nc_open(fname.c_str(), NC_NOWRITE, &_netcdf_descriptor);
2207 CheckForNetCDFError();
2210 _name_buffer =
new char[NC_MAX_NAME + 1];
2213NetCDFReader::~NetCDFReader()
2215 _netcdf_status = nc_close(_netcdf_descriptor);
2216 CheckForNetCDFError();
2220 delete[] _name_buffer;
2224void NetCDFReader::CheckForNetCDFError()
2226 if (_netcdf_status != NC_NOERR)
2228 HandleNetCDFError(_netcdf_status);
2232void NetCDFReader::HandleNetCDFError(
const int error_code)
2234 MFEM_ABORT(
"Fatal NetCDF error: " << nc_strerror(error_code));
2237int NetCDFReader::ReadVariableID(
const char * var_name)
2241 _netcdf_status = nc_inq_varid(_netcdf_descriptor, var_name,
2243 CheckForNetCDFError();
2248int NetCDFReader::ReadDimensionID(
const char * name)
2252 _netcdf_status = nc_inq_dimid(_netcdf_descriptor, name, &dim_id);
2253 CheckForNetCDFError();
2258void NetCDFReader::ReadDimension(
const char * name,
size_t *
dimension)
2260 const int dimension_id = ReadDimensionID(name);
2263 _netcdf_status = nc_inq_dim(_netcdf_descriptor, dimension_id, _name_buffer,
2265 CheckForNetCDFError();
2268bool NetCDFReader::HasVariable(
const char * name)
2271 const int status = nc_inq_varid(_netcdf_descriptor, name, &var_id);
2280 HandleNetCDFError(status);
2285bool NetCDFReader::HasDimension(
const char * name)
2288 const int status = nc_inq_dimid(_netcdf_descriptor, name, &dim_id);
2297 HandleNetCDFError(status);
2302void NetCDFReader::ReadVariable(
const char * name,
int * data)
2304 const int variable_id = ReadVariableID(name);
2306 _netcdf_status = nc_get_var_int(_netcdf_descriptor, variable_id, data);
2307 CheckForNetCDFError();
2311void NetCDFReader::ReadVariable(
const char * name,
double * data)
2313 const int variable_id = ReadVariableID(name);
2315 _netcdf_status = nc_get_var_double(_netcdf_descriptor, variable_id, data);
2316 CheckForNetCDFError();
2320void NetCDFReader::BuildIDToNameMap(
const vector<int> & ids,
2321 unordered_map<int, string> & ids_to_names,
2322 const string & quantity_name)
2327 _netcdf_status = nc_inq_varid(_netcdf_descriptor, quantity_name.c_str(),
2331 if (_netcdf_status == NC_ENOTVAR)
2337 CheckForNetCDFError();
2342 _netcdf_status = nc_inq_vartype(_netcdf_descriptor, varid_names,
2344 CheckForNetCDFError();
2346 if (var_type == NC_CHAR)
2348 int dimids_names[2], names_ndim;
2349 size_t num_names, name_len;
2351 _netcdf_status = nc_inq_varndims(_netcdf_descriptor, varid_names,
2353 CheckForNetCDFError();
2354 MFEM_ASSERT(names_ndim == 2,
"This variable should have two dimensions");
2356 _netcdf_status = nc_inq_vardimid(_netcdf_descriptor, varid_names,
2358 CheckForNetCDFError();
2360 _netcdf_status = nc_inq_dimlen(_netcdf_descriptor, dimids_names[0], &num_names);
2361 CheckForNetCDFError();
2362 MFEM_ASSERT(num_names == ids.size(),
2363 "The block id and block name lengths don't match");
2365 _netcdf_status = nc_inq_dimlen(_netcdf_descriptor, dimids_names[1], &name_len);
2366 CheckForNetCDFError();
2369 vector<char> names(ids.size() * name_len);
2370 _netcdf_status = nc_get_var_text(_netcdf_descriptor, varid_names,
2372 CheckForNetCDFError();
2374 for (
size_t i = 0; i < ids.size(); ++i)
2376 string name(&names[i * name_len], name_len);
2378 name.resize(name.find(
'\0'));
2379 ids_to_names[ids[i]] = name;
2384 mfem_error(
"Unexpected netcdf variable type");
2390static void ReadCubitNodeCoordinates(NetCDFReader & cubit_reader,
2395 cubit_reader.ReadVariable(
"coordx", coordx);
2396 cubit_reader.ReadVariable(
"coordy", coordy);
2400 cubit_reader.ReadVariable(
"coordz", coordz);
2406static void ReadCubitNumElementsInBlock(NetCDFReader & cubit_reader,
2407 const vector<int> & block_ids,
2408 map<int, size_t> &num_elements_for_block_id)
2410 num_elements_for_block_id.clear();
2413 const int buffer_size = NC_MAX_NAME + 1;
2414 char string_buffer[buffer_size];
2417 for (
const auto block_id : block_ids)
2420 snprintf(string_buffer, buffer_size,
"num_el_in_blk%d", iblock++);
2422 size_t num_elements_for_block = 0;
2423 cubit_reader.ReadDimension(string_buffer, &num_elements_for_block);
2425 num_elements_for_block_id[block_id] = num_elements_for_block;
2431static void BuildElementIDsForBlockID(
2432 const vector<int> & block_ids,
2433 const map<int, size_t> & num_elements_for_block_id,
2434 map<
int, vector<int>> & element_ids_for_block_id,
2435 map<int, int> & block_id_for_element_id)
2437 element_ids_for_block_id.clear();
2438 block_id_for_element_id.clear();
2443 for (
int block_id : block_ids)
2445 const int num_elements_for_block = num_elements_for_block_id.at(block_id);
2447 vector<int> element_ids(num_elements_for_block);
2449 for (
int i = 0; i < num_elements_for_block; i++, element_id++)
2451 element_ids[i] = element_id;
2452 block_id_for_element_id[element_id] = block_id;
2455 element_ids_for_block_id[block_id] = std::move(element_ids);
2460static void ReadCubitBlocks(NetCDFReader & cubit_reader,
2461 const vector<int> block_ids,
2462 CubitBlock & cubit_blocks)
2464 const int buffer_size = NC_MAX_NAME + 1;
2465 char string_buffer[buffer_size];
2467 size_t num_nodes_per_element;
2470 for (
int block_id : block_ids)
2473 snprintf(string_buffer, buffer_size,
"num_nod_per_el%d", iblock++);
2475 cubit_reader.ReadDimension(string_buffer, &num_nodes_per_element);
2479 num_nodes_per_element, cubit_blocks.GetDimension());
2480 cubit_blocks.AddBlockElement(block_id, element_type);
2486static void ReadCubitDimensions(NetCDFReader & cubit_reader,
2491 size_t &num_side_sets)
2493 cubit_reader.ReadDimension(
"num_dim", &num_dim);
2494 cubit_reader.ReadDimension(
"num_nodes", &num_nodes);
2495 cubit_reader.ReadDimension(
"num_elem", &num_elem);
2496 cubit_reader.ReadDimension(
"num_el_blk", &num_el_blk);
2499 if (cubit_reader.HasDimension(
"num_side_sets"))
2501 cubit_reader.ReadDimension(
"num_side_sets", &num_side_sets);
2511static void ReadCubitBoundaries(NetCDFReader & cubit_reader,
2512 const vector<int> & boundary_ids,
2513 map<
int, vector<int>> & element_ids_for_boundary_id,
2514 map<
int, vector<int>> & side_ids_for_boundary_id)
2516 const int buffer_size = NC_MAX_NAME + 1;
2517 char string_buffer[buffer_size];
2520 for (
int boundary_id : boundary_ids)
2523 size_t num_sides = 0;
2525 snprintf(string_buffer, buffer_size,
"num_side_ss%d", ibdr);
2526 cubit_reader.ReadDimension(string_buffer, &num_sides);
2529 vector<int> boundary_element_ids(num_sides);
2530 vector<int> boundary_side_ids(num_sides);
2533 snprintf(string_buffer, buffer_size,
"elem_ss%d", ibdr);
2534 cubit_reader.ReadVariable(string_buffer, boundary_element_ids.data());
2537 snprintf(string_buffer, buffer_size,
"side_ss%d", ibdr++);
2538 cubit_reader.ReadVariable(string_buffer, boundary_side_ids.data());
2541 element_ids_for_boundary_id[boundary_id] = std::move(boundary_element_ids);
2542 side_ids_for_boundary_id[boundary_id] = std::move(boundary_side_ids);
2547static void BuildCubitBlockIDs(NetCDFReader & cubit_reader,
2548 const int num_element_blocks,
2549 vector<int> & block_ids)
2551 block_ids.resize(num_element_blocks);
2552 cubit_reader.ReadVariable(
"eb_prop1", block_ids.data());
2556static void ReadCubitBoundaryIDs(NetCDFReader & cubit_reader,
2557 const int num_boundaries, vector<int> & boundary_ids)
2559 boundary_ids.clear();
2561 if (num_boundaries < 1) {
return; }
2563 boundary_ids.resize(num_boundaries);
2564 cubit_reader.ReadVariable(
"ss_prop1", boundary_ids.data());
2568static void ReadCubitElementBlocks(NetCDFReader & cubit_reader,
2569 const CubitBlock & cubit_blocks,
2570 const vector<int> & block_ids,
2571 const map<
int, vector<int>> & element_ids_for_block_id,
2572 map<
int, vector<int>> &node_ids_for_element_id)
2574 const int buffer_size = NC_MAX_NAME + 1;
2575 char string_buffer[buffer_size];
2578 for (
const int block_id : block_ids)
2580 const CubitElement & block_element = cubit_blocks.GetBlockElement(block_id);
2582 const vector<int> & block_element_ids = element_ids_for_block_id.at(block_id);
2584 const size_t num_nodes_for_block = block_element_ids.size() *
2585 block_element.GetNumNodes();
2587 vector<int> node_ids_for_block(num_nodes_for_block);
2590 snprintf(string_buffer, buffer_size,
"connect%d", iblock++);
2592 cubit_reader.ReadVariable(string_buffer, node_ids_for_block.data());
2596 for (
int element_id : block_element_ids)
2598 vector<int> element_node_ids(block_element.GetNumNodes());
2600 for (
int i = 0; i < (int)block_element.GetNumNodes(); i++)
2602 element_node_ids[i] = node_ids_for_block[ielement * block_element.GetNumNodes()
2608 node_ids_for_element_id[element_id] = std::move(element_node_ids);
2614static void BuildBoundaryNodeIDs(
const vector<int> & boundary_ids,
2615 const CubitBlock & blocks,
2616 const map<
int, vector<int>> & node_ids_for_element_id,
2617 const map<
int, vector<int>> & element_ids_for_boundary_id,
2618 const map<
int, vector<int>> & side_ids_for_boundary_id,
2619 const map<int, int> & block_id_for_element_id,
2620 map<
int, vector<vector<int>>> & node_ids_for_boundary_id)
2622 for (
int boundary_id : boundary_ids)
2625 auto & boundary_element_ids = element_ids_for_boundary_id.at(
2627 auto & boundary_element_sides = side_ids_for_boundary_id.at(
2631 vector<vector<int>> boundary_node_ids(
2632 boundary_element_ids.size());
2635 for (
int jelement = 0; jelement < (int)boundary_element_ids.size(); jelement++)
2638 const int boundary_element_global_id = boundary_element_ids[jelement];
2639 const int boundary_side = boundary_element_sides[jelement];
2642 const int block_id = block_id_for_element_id.at(boundary_element_global_id);
2643 const CubitElement & block_element = blocks.GetBlockElement(block_id);
2645 const int num_face_vertices = block_element.GetNumFaceVertices(boundary_side);
2646 vector<int> nodes_of_element_on_side(num_face_vertices);
2649 const vector<int> & element_node_ids =
2650 node_ids_for_element_id.at(boundary_element_global_id);
2654 for (
int knode = 0; knode < num_face_vertices; knode++)
2658 switch (block_element.GetElementType())
2685 MFEM_ABORT(
"Unsupported element type encountered.\n");
2689 nodes_of_element_on_side[knode] = element_node_ids[inode - 1];
2692 boundary_node_ids[jelement] = std::move(nodes_of_element_on_side);
2696 node_ids_for_boundary_id[boundary_id] = std::move(boundary_node_ids);
2701static void BuildUniqueVertexIDs(
const vector<int> & unique_block_ids,
2702 const CubitBlock & blocks,
2703 const map<
int, vector<int>> & element_ids_for_block_id,
2704 const map<
int, vector<int>> & node_ids_for_element_id,
2705 vector<int> & unique_vertex_ids)
2708 for (
int block_id : unique_block_ids)
2710 auto & element_ids = element_ids_for_block_id.at(block_id);
2712 auto & block_element = blocks.GetBlockElement(block_id);
2714 for (
int element_id : element_ids)
2716 auto & node_ids = node_ids_for_element_id.at(element_id);
2718 for (
size_t knode = 0; knode < block_element.GetNumVertices(); knode++)
2720 unique_vertex_ids.push_back(node_ids[knode]);
2726 std::sort(unique_vertex_ids.begin(), unique_vertex_ids.end());
2728 auto new_end = std::unique(unique_vertex_ids.begin(), unique_vertex_ids.end());
2730 unique_vertex_ids.resize(std::distance(unique_vertex_ids.begin(), new_end));
2736static void BuildCubitToMFEMVertexMap(
const vector<int> & unique_vertex_ids,
2737 map<int, int> & cubit_to_mfem_vertex_map)
2739 cubit_to_mfem_vertex_map.clear();
2742 for (
int vertex_id : unique_vertex_ids)
2744 cubit_to_mfem_vertex_map[vertex_id] = ivertex++;
2752static void FinalizeCubitSecondOrderMesh(Mesh &mesh,
2753 const vector<int> & unique_block_ids,
2754 const CubitBlock & blocks,
2755 const map<
int, vector<int>> & element_ids_for_block_id,
2756 const map<
int, vector<int>> & node_ids_for_element_id,
2757 const double *coordx,
2758 const double *coordy,
2759 const double *coordz)
2761 mesh.FinalizeTopology();
2764 const int Dim = mesh.Dimension();
2765 FiniteElementCollection *fec =
new H1_FECollection(2, Dim);
2766 FiniteElementSpace *fes =
new FiniteElementSpace(&mesh, fec, Dim,
2768 GridFunction *Nodes =
new GridFunction(fes);
2769 Nodes->MakeOwner(fec);
2770 mesh.SetNodalGridFunction(Nodes,
true);
2772 for (
int block_id : unique_block_ids)
2774 const CubitElement & block_element = blocks.GetBlockElement(block_id);
2776 int *mfem_to_genesis_map = NULL;
2778 switch (block_element.GetElementType())
2799 MFEM_ABORT(
"Something went wrong. Linear elements detected when order is 2.");
2802 auto & element_ids = element_ids_for_block_id.at(block_id);
2804 for (
int element_id : element_ids)
2808 fes->GetElementDofs(element_id - 1, dofs);
2810 Array<int> vdofs = dofs;
2811 fes->DofsToVDofs(vdofs);
2813 const vector<int> & element_node_ids = node_ids_for_element_id.at(element_id);
2815 for (
int jnode = 0; jnode < dofs.Size(); jnode++)
2817 const int node_index = element_node_ids[mfem_to_genesis_map[jnode] - 1] - 1;
2819 (*Nodes)(vdofs[jnode]) = coordx[node_index];
2820 (*Nodes)(vdofs[jnode] + 1) = coordy[node_index];
2824 (*Nodes)(vdofs[jnode] + 2) = coordz[node_index];
2835 const vector<double> & coordx,
2836 const vector<double> & coordy,
2837 const vector<double> & coordz)
2844 const int original_1based_id = unique_vertex_ids[ivertex];
2846 vertices[ivertex](0) = coordx[original_1based_id - 1];
2847 vertices[ivertex](1) = coordy[original_1based_id - 1];
2851 vertices[ivertex](2) = coordz[original_1based_id - 1];
2858 const cubit::CubitBlock * blocks,
2859 const vector<int> & block_ids,
2860 const map<
int, vector<int>> & element_ids_for_block_id,
2861 const map<
int, vector<int>> & node_ids_for_element_id,
2862 const map<int, int> & cubit_to_mfem_vertex_map)
2864 using namespace cubit;
2869 int element_counter = 0;
2872 for (
int block_id : block_ids)
2874 const CubitElement & block_element = blocks->GetBlockElement(block_id);
2876 vector<int> renumbered_vertex_ids(block_element.GetNumVertices());
2878 const vector<int> &block_element_ids = element_ids_for_block_id.at(block_id);
2881 for (
int element_id : block_element_ids)
2883 const vector<int> & element_node_ids = node_ids_for_element_id.at(element_id);
2886 for (
size_t knode = 0; knode < block_element.GetNumVertices(); knode++)
2888 const int node_id = element_node_ids[knode];
2891 renumbered_vertex_ids[knode] = cubit_to_mfem_vertex_map.at(node_id) - 1;
2895 elements[element_counter++] = block_element.BuildElement(*
this,
2896 renumbered_vertex_ids.data(),
2904 const cubit::CubitBlock * blocks,
2905 const vector<int> & boundary_ids,
2906 const map<
int, vector<int>> & element_ids_for_boundary_id,
2907 const map<
int, vector<vector<int>>> & node_ids_for_boundary_id,
2908 const map<
int, vector<int>> & side_ids_for_boundary_id,
2909 const map<int, int> & block_id_for_element_id,
2910 const map<int, int> & cubit_to_mfem_vertex_map)
2912 using namespace cubit;
2915 for (
int boundary_id : boundary_ids)
2922 array<int, 8> renumbered_vertex_ids;
2925 int boundary_counter = 0;
2926 for (
int boundary_id : boundary_ids)
2928 const vector<int> &elements_on_boundary = element_ids_for_boundary_id.at(
2931 const vector<vector<int>> &nodes_on_boundary = node_ids_for_boundary_id.at(
2935 for (
int side_id : side_ids_for_boundary_id.at(boundary_id))
2938 const int element_id = elements_on_boundary.at(jelement);
2939 const int element_block = block_id_for_element_id.at(element_id);
2940 const CubitElement & block_element = blocks->GetBlockElement(element_block);
2942 const vector<int> & element_nodes_on_side = nodes_on_boundary.at(jelement);
2945 for (
size_t knode = 0; knode < element_nodes_on_side.size(); knode++)
2947 const int node_id = element_nodes_on_side[knode];
2950 renumbered_vertex_ids[knode] = cubit_to_mfem_vertex_map.at(node_id) - 1;
2954 boundary[boundary_counter++] = block_element.BuildBoundaryElement(*
this,
2956 renumbered_vertex_ids.data(),
2966 using namespace cubit;
2974 NetCDFReader cubit_reader(filename);
2979 size_t num_dimensions, num_nodes, num_elements, num_element_blocks,
2982 ReadCubitDimensions(cubit_reader, num_dimensions, num_nodes, num_elements,
2983 num_element_blocks, num_boundaries);
2985 Dim = num_dimensions;
2990 vector<int> block_ids;
2991 BuildCubitBlockIDs(cubit_reader, num_element_blocks, block_ids);
2992 unordered_map<int, string> blk_ids_to_names;
2993 cubit_reader.BuildIDToNameMap(block_ids, blk_ids_to_names,
"eb_names");
2994 for (
const auto & pr : blk_ids_to_names)
2996 const auto blk_id = pr.first;
2997 const auto & blk_name = pr.second;
2998 if (!blk_name.empty())
3008 map<int, size_t> num_elements_for_block_id;
3009 ReadCubitNumElementsInBlock(cubit_reader, block_ids,
3010 num_elements_for_block_id);
3012 map<int, vector<int>> element_ids_for_block_id;
3013 map<int, int> block_id_for_element_id;
3014 BuildElementIDsForBlockID(
3015 block_ids, num_elements_for_block_id, element_ids_for_block_id,
3016 block_id_for_element_id);
3020 CubitBlock blocks(num_dimensions);
3021 ReadCubitBlocks(cubit_reader, block_ids, blocks);
3024 map<int, vector<int>> node_ids_for_element_id;
3025 ReadCubitElementBlocks(cubit_reader,
3028 element_ids_for_block_id,
3029 node_ids_for_element_id);
3034 vector<int> boundary_ids;
3035 ReadCubitBoundaryIDs(cubit_reader, num_boundaries, boundary_ids);
3036 unordered_map<int, string> bnd_ids_to_names;
3037 cubit_reader.BuildIDToNameMap(boundary_ids, bnd_ids_to_names,
"ss_names");
3038 for (
const auto & pr : bnd_ids_to_names)
3040 const auto bnd_id = pr.first;
3041 const auto & bnd_name = pr.second;
3042 if (!bnd_name.empty())
3056 map<int, vector<int>> element_ids_for_boundary_id;
3057 map<int, vector<int>> side_ids_for_boundary_id;
3059 ReadCubitBoundaries(cubit_reader, boundary_ids,
3060 element_ids_for_boundary_id, side_ids_for_boundary_id);
3062 map<int, vector<vector<int>>> node_ids_for_boundary_id;
3064 BuildBoundaryNodeIDs(boundary_ids, blocks, node_ids_for_element_id,
3065 element_ids_for_boundary_id, side_ids_for_boundary_id,
3066 block_id_for_element_id,
3067 node_ids_for_boundary_id);
3072 vector<double> coordx(num_nodes);
3073 vector<double> coordy(num_nodes);
3074 vector<double> coordz(num_dimensions == 3 ? num_nodes : 0);
3076 ReadCubitNodeCoordinates(cubit_reader, coordx.data(), coordy.data(),
3082 vector<int> unique_vertex_ids;
3083 BuildUniqueVertexIDs(block_ids, blocks, element_ids_for_block_id,
3084 node_ids_for_element_id, unique_vertex_ids);
3092 map<int, int> cubit_to_mfem_vertex_map;
3093 BuildCubitToMFEMVertexMap(unique_vertex_ids, cubit_to_mfem_vertex_map);
3104 element_ids_for_block_id,
3105 node_ids_for_element_id, cubit_to_mfem_vertex_map);
3111 element_ids_for_boundary_id, node_ids_for_boundary_id, side_ids_for_boundary_id,
3112 block_id_for_element_id,
3113 cubit_to_mfem_vertex_map);
3118 if (blocks.GetOrder() == 2)
3122 FinalizeCubitSecondOrderMesh(*
this,
3125 element_ids_for_block_id,
3126 node_ids_for_element_id,
void Load(std::istream &in, int fmt=0)
Read an Array from the stream in using format fmt. The format fmt can be:
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Size() const
Return the logical size of the array.
T * GetData()
Returns the data.
void SortAll()
Sort each named array in the container.
void UniqueAll()
Remove duplicates from each, previously sorted, named array.
void Load(std::istream &in)
Load the contents of the container from an input stream.
bool AttributeSetExists(const std::string &name) const
Return true if the named attribute set is present.
void AddToAttributeSet(const std::string &set_name, int attr)
Add a single entry to an existing attribute set.
ArraysByName< int > attr_sets
Named sets of attributes.
Array< int > & CreateAttributeSet(const std::string &set_name)
Create an empty named attribute set.
@ ClosedUniform
Nodes: x_i = i/(n-1), i=0,...,n-1.
Abstract data type element.
void SetAttribute(const int attr)
Set element's attribute.
Type
Constants for the classes derived from Element.
virtual void SetVertices(const Array< int > &v)=0
Set the indices defining the vertices.
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Compute the full set of vdofs corresponding to each entry in dofs.
DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element 'elem'. The returned indices are offsets into an ldo...
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
Abstract class for all finite elements.
static const int Dimension[NumGeom]
Class for grid function - Vector with associated FE space.
void MakeOwner(FiniteElementCollection *fec_)
Make the GridFunction the owner of fec_owned and fes.
int VectorDim() const
Shortcut for calling FiniteElementSpace::GetVectorDim() on the underlying fes.
void GetNodalValues(int i, Array< real_t > &nval, int vdim=1) const
Returns the values at the vertices of element i for the 1-based dimension vdim.
Arbitrary order H1-conforming (continuous) finite elements.
Data type hexahedron element.
int CheckElementOrientation(bool fix_it=true)
Check (and optionally attempt to fix) the orientation of the elements.
Element * NewElement(int geom)
friend class NCNURBSExtension
void BuildCubitElements(const int num_elements, const cubit::CubitBlock *blocks, const std::vector< int > &block_ids, const std::map< int, std::vector< int > > &element_ids_for_block_id, const std::map< int, std::vector< int > > &node_ids_for_element_id, const std::map< int, int > &cubit_to_mfem_vertex_map)
Called internally in ReadCubit. This method builds the mesh elements.
MemAlloc< Tetrahedron, 1024 > TetMemory
NURBSExtension * NURBSext
Optional NURBS mesh extension.
void ReadTrueGridMesh(std::istream &input)
static const int vtk_quadratic_tet[10]
void ReadNetgen3DMesh(std::istream &input)
void ReadInlineMesh(std::istream &input, bool generate_edges=false)
void ReadLineMesh(std::istream &input)
static const int vtk_quadratic_wedge[18]
AttributeSets bdr_attribute_sets
Named sets of boundary element attributes.
void Make1D(int n, real_t sx=1.0)
void FinalizeTopology(bool generate_bdr=true)
Finalize the construction of the secondary topology (connectivity) data of a Mesh.
void ReadXML_VTKMesh(std::istream &input, int &curved, int &read_gf, bool &finalize_topo, const std::string &xml_prefix="")
void Make3D(int nx, int ny, int nz, Element::Type type, real_t sx, real_t sy, real_t sz, bool sfc_ordering)
Creates a mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz], divided into nx*ny*nz hexahedra if type =...
friend class NURBSExtension
static bool remove_unused_vertices
void ReadCubit(const std::string &filename, int &curved, int &read_gf)
Load a mesh from a Genesis file.
static const int vtk_quadratic_pyramid[13]
AttributeSets attribute_sets
Named sets of element attributes.
void ReadVTKMesh(std::istream &input, int &curved, int &read_gf, bool &finalize_topo)
static const int vtk_quadratic_hex[27]
void ReadMFEMMesh(std::istream &input, int version, int &curved)
void CreateVTKMesh(const Vector &points, const Array< int > &cell_data, const Array< int > &cell_offsets, const Array< int > &cell_types, const Array< int > &cell_attributes, int &curved, int &read_gf, bool &finalize_topo)
void BuildCubitBoundaries(const cubit::CubitBlock *blocks, const std::vector< int > &boundary_ids, const std::map< int, std::vector< int > > &element_ids_for_boundary_id, const std::map< int, std::vector< std::vector< int > > > &node_ids_for_boundary_id, const std::map< int, std::vector< int > > &side_ids_for_boundary_id, const std::map< int, int > &block_id_for_element_id, const std::map< int, int > &cubit_to_mfem_vertex_map)
Called internally in ReadCubit. This method adds the mesh boundary elements.
Array< Element * > boundary
void ReadNURBSMesh(std::istream &input, int &curved, int &read_gf, bool spacing=false, bool nc=false)
void Make2D(int nx, int ny, Element::Type type, real_t sx, real_t sy, bool generate_edges, bool sfc_ordering)
Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny quadrilaterals if type = QUADRILATER...
Element * ReadElement(std::istream &input)
Geometry::Type GetElementBaseGeometry(int i) const
void BuildCubitVertices(const std::vector< int > &unique_vertex_ids, const std::vector< double > &coordx, const std::vector< double > &coordy, const std::vector< double > &coordz)
Called internally in ReadCubit. This method creates the vertices.
void ReadNetgen2DMesh(std::istream &input, int &curved)
Array< Element * > elements
void RemoveUnusedVertices()
Remove unused vertices and rebuild mesh connectivity.
int GetNBE() const
Return the number of active boundary elements.
int GetPatchSpaceDimension() const
Return the physical dimension of the NURBS geometry.
void SetCoordsFromPatches(Vector &Nodes, int vdim)
Set FE coordinates in Nodes, using data from patches, with physical vector dimension vdim,...
void GetElementTopo(Array< Element * > &elements) const
Generate the active mesh elements and return them in elements.
bool HavePatches() const
Return true if at least 1 patch is defined, false otherwise.
void GetBdrElementTopo(Array< Element * > &boundary) const
Generate the active mesh boundary elements and return them in boundary.
int GetOrder() const
If all KnotVector orders are identical, return that number. Otherwise, return NURBSFECollection::Vari...
int GetNV() const
Return the local number of active vertices.
int Dimension() const
Return the dimension of the reference space (not physical space).
int GetNE() const
Return the number of active elements.
Arbitrary order non-uniform rational B-splines (NURBS) finite elements.
Class for standard nodal finite elements.
const Array< int > & GetLexicographicOrdering() const
Get an Array<int> that maps lexicographically ordered indices to the indices of the respective nodes/...
Piecewise-(bi)quadratic continuous finite elements.
Data type quadrilateral element.
Data type line segment element.
Data type tetrahedron element.
void SetVertices(const Array< int > &v) override
Set the indices defining the vertices.
Data type triangle element.
void Load(std::istream **in, int np, int *dim)
Reads a vector from multiple files.
int Size() const
Returns the size of the vector.
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
constexpr int dimension
This example only works in 3D. Kernels for 2D are not implemented.
void DecodeBase64(const char *src, size_t len, std::vector< char > &buf)
Decode len base-64 encoded characters in the buffer src, and store the resulting decoded data in buf....
size_t NumBase64Chars(size_t nbytes)
Return the number of characters needed to encode nbytes in base-64.
T read(std::istream &is)
Read a value from the stream and return it.
const int mfem_to_genesis_tri6[6]
const int mfem_to_genesis_pyramid14[14]
const int cubit_side_map_tri3[3][2]
const int mfem_to_genesis_wedge18[18]
const int cubit_side_map_hex8[6][4]
const int cubit_side_map_quad4[4][2]
const int mfem_to_genesis_quad9[9]
const int cubit_side_map_tet4[4][3]
const int cubit_side_map_wedge6[5][4]
const int mfem_to_genesis_hex27[27]
const int cubit_side_map_pyramid5[5][4]
const int mfem_to_genesis_tet10[10]
MFEM_HOST_DEVICE constexpr auto type(const tuple< T... > &t)
a function intended to be used for extracting the ith type from a tuple.
bool StringCompare(const char *s1, const char *s2)
void mfem_error(const char *msg)
void filter_dos(std::string &line)
Check for, and remove, a trailing '\r' from and std::string.
const char * VTKByteOrder()
Determine the byte order and return either "BigEndian" or "LittleEndian".
void CreateVTKElementConnectivity(Array< int > &con, Geometry::Type geom, int ref)
Create the VTK element connectivity array for a given element geometry and refinement level.
void skip_comment_lines(std::istream &is, const char comment_char)
Check if the stream starts with comment_char. If so skip it.
static const int LAGRANGE_PRISM
static const int PrismMap[6]
Permutation from MFEM's prism ordering to VTK's prism ordering.
static bool IsLagrange(int vtk_geom)
Does the given VTK geometry type describe an arbitrary-order Lagrange element?
static Geometry::Type GetMFEMGeometry(int vtk_geom)
Given a VTK geometry type, return the corresponding MFEM Geometry::Type.
static int GetOrder(int vtk_geom, int npoints)
For the given VTK geometry type and number of points, return the order of the element.