2133 lines
63 KiB
C++
2133 lines
63 KiB
C++
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
|
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
|
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
|
//
|
|
// This file is part of the MFEM library. For more information and source code
|
|
// availability visit https://mfem.org.
|
|
//
|
|
// MFEM is free software; you can redistribute it and/or modify it under the
|
|
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
|
// CONTRIBUTING.md for details.
|
|
|
|
#include "mesh_headers.hpp"
|
|
#include "../fem/fem.hpp"
|
|
#include "../general/text.hpp"
|
|
|
|
#include <iostream>
|
|
#include <cstdio>
|
|
|
|
#ifdef MFEM_USE_NETCDF
|
|
#include "netcdf.h"
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
namespace mfem
|
|
{
|
|
|
|
bool Mesh::remove_unused_vertices = true;
|
|
|
|
void Mesh::ReadMFEMMesh(std::istream &input, bool mfem_v11, int &curved)
|
|
{
|
|
// Read MFEM mesh v1.0 format
|
|
string ident;
|
|
|
|
// read lines beginning with '#' (comments)
|
|
skip_comment_lines(input, '#');
|
|
input >> ident; // 'dimension'
|
|
|
|
MFEM_VERIFY(ident == "dimension", "invalid mesh file");
|
|
input >> Dim;
|
|
|
|
skip_comment_lines(input, '#');
|
|
input >> ident; // 'elements'
|
|
|
|
MFEM_VERIFY(ident == "elements", "invalid mesh file");
|
|
input >> NumOfElements;
|
|
elements.SetSize(NumOfElements);
|
|
for (int j = 0; j < NumOfElements; j++)
|
|
{
|
|
elements[j] = ReadElement(input);
|
|
}
|
|
|
|
skip_comment_lines(input, '#');
|
|
input >> ident; // 'boundary'
|
|
|
|
MFEM_VERIFY(ident == "boundary", "invalid mesh file");
|
|
input >> NumOfBdrElements;
|
|
boundary.SetSize(NumOfBdrElements);
|
|
for (int j = 0; j < NumOfBdrElements; j++)
|
|
{
|
|
boundary[j] = ReadElement(input);
|
|
}
|
|
|
|
skip_comment_lines(input, '#');
|
|
input >> ident;
|
|
|
|
if (mfem_v11 && ident == "vertex_parents")
|
|
{
|
|
ncmesh = new NCMesh(this, &input);
|
|
// NOTE: the constructor above will call LoadVertexParents
|
|
|
|
skip_comment_lines(input, '#');
|
|
input >> ident;
|
|
|
|
if (ident == "coarse_elements")
|
|
{
|
|
ncmesh->LoadCoarseElements(input);
|
|
|
|
skip_comment_lines(input, '#');
|
|
input >> ident;
|
|
}
|
|
}
|
|
|
|
MFEM_VERIFY(ident == "vertices", "invalid mesh file");
|
|
input >> NumOfVertices;
|
|
vertices.SetSize(NumOfVertices);
|
|
|
|
input >> ws >> ident;
|
|
if (ident != "nodes")
|
|
{
|
|
// read the vertices
|
|
spaceDim = atoi(ident.c_str());
|
|
for (int j = 0; j < NumOfVertices; j++)
|
|
{
|
|
for (int i = 0; i < spaceDim; i++)
|
|
{
|
|
input >> vertices[j](i);
|
|
}
|
|
}
|
|
|
|
// initialize vertex positions in NCMesh
|
|
if (ncmesh) { ncmesh->SetVertexPositions(vertices); }
|
|
}
|
|
else
|
|
{
|
|
// prepare to read the nodes
|
|
input >> ws;
|
|
curved = 1;
|
|
}
|
|
|
|
// When visualizing solutions on non-conforming grids, PETSc
|
|
// may dump additional vertices
|
|
if (remove_unused_vertices) { RemoveUnusedVertices(); }
|
|
}
|
|
|
|
void Mesh::ReadLineMesh(std::istream &input)
|
|
{
|
|
int j,p1,p2,a;
|
|
|
|
Dim = 1;
|
|
|
|
input >> NumOfVertices;
|
|
vertices.SetSize(NumOfVertices);
|
|
// Sets vertices and the corresponding coordinates
|
|
for (j = 0; j < NumOfVertices; j++)
|
|
{
|
|
input >> vertices[j](0);
|
|
}
|
|
|
|
input >> NumOfElements;
|
|
elements.SetSize(NumOfElements);
|
|
// Sets elements and the corresponding indices of vertices
|
|
for (j = 0; j < NumOfElements; j++)
|
|
{
|
|
input >> a >> p1 >> p2;
|
|
elements[j] = new Segment(p1-1, p2-1, a);
|
|
}
|
|
|
|
int ind[1];
|
|
input >> NumOfBdrElements;
|
|
boundary.SetSize(NumOfBdrElements);
|
|
for (j = 0; j < NumOfBdrElements; j++)
|
|
{
|
|
input >> a >> ind[0];
|
|
ind[0]--;
|
|
boundary[j] = new Point(ind,a);
|
|
}
|
|
}
|
|
|
|
void Mesh::ReadNetgen2DMesh(std::istream &input, int &curved)
|
|
{
|
|
int ints[32], attr, n;
|
|
|
|
// Read planar mesh in Netgen format.
|
|
Dim = 2;
|
|
|
|
// Read the boundary elements.
|
|
input >> NumOfBdrElements;
|
|
boundary.SetSize(NumOfBdrElements);
|
|
for (int i = 0; i < NumOfBdrElements; i++)
|
|
{
|
|
input >> attr
|
|
>> ints[0] >> ints[1];
|
|
ints[0]--; ints[1]--;
|
|
boundary[i] = new Segment(ints, attr);
|
|
}
|
|
|
|
// Read the elements.
|
|
input >> NumOfElements;
|
|
elements.SetSize(NumOfElements);
|
|
for (int i = 0; i < NumOfElements; i++)
|
|
{
|
|
input >> attr >> n;
|
|
for (int j = 0; j < n; j++)
|
|
{
|
|
input >> ints[j];
|
|
ints[j]--;
|
|
}
|
|
switch (n)
|
|
{
|
|
case 2:
|
|
elements[i] = new Segment(ints, attr);
|
|
break;
|
|
case 3:
|
|
elements[i] = new Triangle(ints, attr);
|
|
break;
|
|
case 4:
|
|
elements[i] = new Quadrilateral(ints, attr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!curved)
|
|
{
|
|
// Read the vertices.
|
|
input >> NumOfVertices;
|
|
vertices.SetSize(NumOfVertices);
|
|
for (int i = 0; i < NumOfVertices; i++)
|
|
for (int j = 0; j < Dim; j++)
|
|
{
|
|
input >> vertices[i](j);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
input >> NumOfVertices;
|
|
vertices.SetSize(NumOfVertices);
|
|
input >> ws;
|
|
}
|
|
}
|
|
|
|
void Mesh::ReadNetgen3DMesh(std::istream &input)
|
|
{
|
|
int ints[32], attr;
|
|
|
|
// Read a Netgen format mesh of tetrahedra.
|
|
Dim = 3;
|
|
|
|
// Read the vertices
|
|
input >> NumOfVertices;
|
|
|
|
vertices.SetSize(NumOfVertices);
|
|
for (int i = 0; i < NumOfVertices; i++)
|
|
for (int j = 0; j < Dim; j++)
|
|
{
|
|
input >> vertices[i](j);
|
|
}
|
|
|
|
// Read the elements
|
|
input >> NumOfElements;
|
|
elements.SetSize(NumOfElements);
|
|
for (int i = 0; i < NumOfElements; i++)
|
|
{
|
|
input >> attr;
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
input >> ints[j];
|
|
ints[j]--;
|
|
}
|
|
#ifdef MFEM_USE_MEMALLOC
|
|
Tetrahedron *tet;
|
|
tet = TetMemory.Alloc();
|
|
tet->SetVertices(ints);
|
|
tet->SetAttribute(attr);
|
|
elements[i] = tet;
|
|
#else
|
|
elements[i] = new Tetrahedron(ints, attr);
|
|
#endif
|
|
}
|
|
|
|
// Read the boundary information.
|
|
input >> NumOfBdrElements;
|
|
boundary.SetSize(NumOfBdrElements);
|
|
for (int i = 0; i < NumOfBdrElements; i++)
|
|
{
|
|
input >> attr;
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
input >> ints[j];
|
|
ints[j]--;
|
|
}
|
|
boundary[i] = new Triangle(ints, attr);
|
|
}
|
|
}
|
|
|
|
void Mesh::ReadTrueGridMesh(std::istream &input)
|
|
{
|
|
int i, j, ints[32], attr;
|
|
const int buflen = 1024;
|
|
char buf[buflen];
|
|
|
|
// TODO: find the actual dimension
|
|
Dim = 3;
|
|
|
|
if (Dim == 2)
|
|
{
|
|
int vari;
|
|
double varf;
|
|
|
|
input >> vari >> NumOfVertices >> vari >> vari >> NumOfElements;
|
|
input.getline(buf, buflen);
|
|
input.getline(buf, buflen);
|
|
input >> vari;
|
|
input.getline(buf, buflen);
|
|
input.getline(buf, buflen);
|
|
input.getline(buf, buflen);
|
|
|
|
// Read the vertices.
|
|
vertices.SetSize(NumOfVertices);
|
|
for (i = 0; i < NumOfVertices; i++)
|
|
{
|
|
input >> vari >> varf >> vertices[i](0) >> vertices[i](1);
|
|
input.getline(buf, buflen);
|
|
}
|
|
|
|
// Read the elements.
|
|
elements.SetSize(NumOfElements);
|
|
for (i = 0; i < NumOfElements; i++)
|
|
{
|
|
input >> vari >> attr;
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
input >> ints[j];
|
|
ints[j]--;
|
|
}
|
|
input.getline(buf, buflen);
|
|
input.getline(buf, buflen);
|
|
elements[i] = new Quadrilateral(ints, attr);
|
|
}
|
|
}
|
|
else if (Dim == 3)
|
|
{
|
|
int vari;
|
|
double varf;
|
|
input >> vari >> NumOfVertices >> NumOfElements;
|
|
input.getline(buf, buflen);
|
|
input.getline(buf, buflen);
|
|
input >> vari >> vari >> NumOfBdrElements;
|
|
input.getline(buf, buflen);
|
|
input.getline(buf, buflen);
|
|
input.getline(buf, buflen);
|
|
// Read the vertices.
|
|
vertices.SetSize(NumOfVertices);
|
|
for (i = 0; i < NumOfVertices; i++)
|
|
{
|
|
input >> vari >> varf >> vertices[i](0) >> vertices[i](1)
|
|
>> vertices[i](2);
|
|
input.getline(buf, buflen);
|
|
}
|
|
// Read the elements.
|
|
elements.SetSize(NumOfElements);
|
|
for (i = 0; i < NumOfElements; i++)
|
|
{
|
|
input >> vari >> attr;
|
|
for (j = 0; j < 8; j++)
|
|
{
|
|
input >> ints[j];
|
|
ints[j]--;
|
|
}
|
|
input.getline(buf, buflen);
|
|
elements[i] = new Hexahedron(ints, attr);
|
|
}
|
|
// Read the boundary elements.
|
|
boundary.SetSize(NumOfBdrElements);
|
|
for (i = 0; i < NumOfBdrElements; i++)
|
|
{
|
|
input >> attr;
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
input >> ints[j];
|
|
ints[j]--;
|
|
}
|
|
input.getline(buf, buflen);
|
|
boundary[i] = new Quadrilateral(ints, attr);
|
|
}
|
|
}
|
|
}
|
|
|
|
// see Tetrahedron::edges
|
|
const int Mesh::vtk_quadratic_tet[10] =
|
|
{ 0, 1, 2, 3, 4, 7, 5, 6, 8, 9 };
|
|
|
|
// see Wedge::edges & Mesh::GenerateFaces
|
|
// https://www.vtk.org/doc/nightly/html/classvtkBiQuadraticQuadraticWedge.html
|
|
const int Mesh::vtk_quadratic_wedge[18] =
|
|
{ 0, 2, 1, 3, 5, 4, 8, 7, 6, 11, 10, 9, 12, 14, 13, 17, 16, 15};
|
|
|
|
// see Hexahedron::edges & Mesh::GenerateFaces
|
|
const int Mesh::vtk_quadratic_hex[27] =
|
|
{
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
|
24, 22, 21, 23, 20, 25, 26
|
|
};
|
|
|
|
void Mesh::ReadVTKMesh(std::istream &input, int &curved, int &read_gf,
|
|
bool &finalize_topo)
|
|
{
|
|
// VTK resources:
|
|
// * https://www.vtk.org/doc/nightly/html/vtkCellType_8h_source.html
|
|
// * https://www.vtk.org/doc/nightly/html/classvtkCell.html
|
|
// * https://lorensen.github.io/VTKExamples/site/VTKFileFormats
|
|
// * https://www.kitware.com/products/books/VTKUsersGuide.pdf
|
|
|
|
int i, j, n, attr;
|
|
|
|
string buff;
|
|
getline(input, buff); // comment line
|
|
getline(input, buff);
|
|
filter_dos(buff);
|
|
if (buff != "ASCII")
|
|
{
|
|
MFEM_ABORT("VTK mesh is not in ASCII format!");
|
|
return;
|
|
}
|
|
getline(input, buff);
|
|
filter_dos(buff);
|
|
if (buff != "DATASET UNSTRUCTURED_GRID")
|
|
{
|
|
MFEM_ABORT("VTK mesh is not UNSTRUCTURED_GRID!");
|
|
return;
|
|
}
|
|
|
|
// Read the points, skipping optional sections such as the FIELD data from
|
|
// VisIt's VTK export (or from Mesh::PrintVTK with field_data==1).
|
|
do
|
|
{
|
|
input >> buff;
|
|
if (!input.good())
|
|
{
|
|
MFEM_ABORT("VTK mesh does not have POINTS data!");
|
|
}
|
|
}
|
|
while (buff != "POINTS");
|
|
int np = 0;
|
|
Vector points;
|
|
{
|
|
input >> np >> ws;
|
|
points.SetSize(3*np);
|
|
getline(input, buff); // "double"
|
|
for (i = 0; i < points.Size(); i++)
|
|
{
|
|
input >> points(i);
|
|
}
|
|
}
|
|
|
|
// Read the cells
|
|
NumOfElements = n = 0;
|
|
Array<int> cells_data;
|
|
input >> ws >> buff;
|
|
if (buff == "CELLS")
|
|
{
|
|
input >> NumOfElements >> n >> ws;
|
|
cells_data.SetSize(n);
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
input >> cells_data[i];
|
|
}
|
|
}
|
|
|
|
// Read the cell types
|
|
Dim = -1;
|
|
int order = -1;
|
|
input >> ws >> buff;
|
|
if (buff == "CELL_TYPES")
|
|
{
|
|
input >> NumOfElements;
|
|
elements.SetSize(NumOfElements);
|
|
for (j = i = 0; i < NumOfElements; i++)
|
|
{
|
|
int ct, elem_dim, elem_order = 1;
|
|
input >> ct;
|
|
switch (ct)
|
|
{
|
|
case 5: // triangle
|
|
elem_dim = 2;
|
|
elements[i] = new Triangle(&cells_data[j+1]);
|
|
break;
|
|
case 9: // quadrilateral
|
|
elem_dim = 2;
|
|
elements[i] = new Quadrilateral(&cells_data[j+1]);
|
|
break;
|
|
case 10: // tetrahedron
|
|
elem_dim = 3;
|
|
#ifdef MFEM_USE_MEMALLOC
|
|
elements[i] = TetMemory.Alloc();
|
|
elements[i]->SetVertices(&cells_data[j+1]);
|
|
#else
|
|
elements[i] = new Tetrahedron(&cells_data[j+1]);
|
|
#endif
|
|
break;
|
|
case 12: // hexahedron
|
|
elem_dim = 3;
|
|
elements[i] = new Hexahedron(&cells_data[j+1]);
|
|
break;
|
|
case 13: // wedge
|
|
elem_dim = 3;
|
|
// switch between vtk vertex ordering and mfem vertex ordering:
|
|
// swap vertices (1,2) and (4,5)
|
|
elements[i] =
|
|
new Wedge(cells_data[j+1], cells_data[j+3], cells_data[j+2],
|
|
cells_data[j+4], cells_data[j+6], cells_data[j+5]);
|
|
break;
|
|
|
|
case 22: // quadratic triangle
|
|
elem_dim = 2;
|
|
elem_order = 2;
|
|
elements[i] = new Triangle(&cells_data[j+1]);
|
|
break;
|
|
case 28: // biquadratic quadrilateral
|
|
elem_dim = 2;
|
|
elem_order = 2;
|
|
elements[i] = new Quadrilateral(&cells_data[j+1]);
|
|
break;
|
|
case 24: // quadratic tetrahedron
|
|
elem_dim = 3;
|
|
elem_order = 2;
|
|
#ifdef MFEM_USE_MEMALLOC
|
|
elements[i] = TetMemory.Alloc();
|
|
elements[i]->SetVertices(&cells_data[j+1]);
|
|
#else
|
|
elements[i] = new Tetrahedron(&cells_data[j+1]);
|
|
#endif
|
|
break;
|
|
case 32: // biquadratic-quadratic wedge
|
|
elem_dim = 3;
|
|
elem_order = 2;
|
|
// switch between vtk vertex ordering and mfem vertex ordering:
|
|
// swap vertices (1,2) and (4,5)
|
|
elements[i] =
|
|
new Wedge(cells_data[j+1], cells_data[j+3], cells_data[j+2],
|
|
cells_data[j+4], cells_data[j+6], cells_data[j+5]);
|
|
break;
|
|
case 29: // triquadratic hexahedron
|
|
elem_dim = 3;
|
|
elem_order = 2;
|
|
elements[i] = new Hexahedron(&cells_data[j+1]);
|
|
break;
|
|
default:
|
|
MFEM_ABORT("VTK mesh : cell type " << ct << " is not supported!");
|
|
return;
|
|
}
|
|
MFEM_VERIFY(Dim == -1 || Dim == elem_dim,
|
|
"elements with different dimensions are not supported");
|
|
MFEM_VERIFY(order == -1 || order == elem_order,
|
|
"elements with different orders are not supported");
|
|
Dim = elem_dim;
|
|
order = elem_order;
|
|
j += cells_data[j] + 1;
|
|
}
|
|
}
|
|
|
|
// Read attributes
|
|
streampos sp = input.tellg();
|
|
input >> ws >> buff;
|
|
if (buff == "CELL_DATA")
|
|
{
|
|
input >> n >> ws;
|
|
getline(input, buff);
|
|
filter_dos(buff);
|
|
// "SCALARS material dataType numComp"
|
|
if (!strncmp(buff.c_str(), "SCALARS material", 16))
|
|
{
|
|
getline(input, buff); // "LOOKUP_TABLE default"
|
|
for (i = 0; i < NumOfElements; i++)
|
|
{
|
|
input >> attr;
|
|
elements[i]->SetAttribute(attr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
input.seekg(sp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
input.seekg(sp);
|
|
}
|
|
|
|
if (order == 1)
|
|
{
|
|
cells_data.DeleteAll();
|
|
NumOfVertices = np;
|
|
vertices.SetSize(np);
|
|
for (i = 0; i < np; i++)
|
|
{
|
|
vertices[i](0) = points(3*i+0);
|
|
vertices[i](1) = points(3*i+1);
|
|
vertices[i](2) = points(3*i+2);
|
|
}
|
|
points.Destroy();
|
|
|
|
// No boundary is defined in a VTK mesh
|
|
NumOfBdrElements = 0;
|
|
}
|
|
else if (order == 2)
|
|
{
|
|
curved = 1;
|
|
|
|
// generate new enumeration for the vertices
|
|
Array<int> pts_dof(np);
|
|
pts_dof = -1;
|
|
for (n = i = 0; i < NumOfElements; i++)
|
|
{
|
|
int *v = elements[i]->GetVertices();
|
|
int nv = elements[i]->GetNVertices();
|
|
for (j = 0; j < nv; j++)
|
|
if (pts_dof[v[j]] == -1)
|
|
{
|
|
pts_dof[v[j]] = n++;
|
|
}
|
|
}
|
|
// keep the original ordering of the vertices
|
|
for (n = i = 0; i < np; i++)
|
|
if (pts_dof[i] != -1)
|
|
{
|
|
pts_dof[i] = n++;
|
|
}
|
|
// update the element vertices
|
|
for (i = 0; i < NumOfElements; i++)
|
|
{
|
|
int *v = elements[i]->GetVertices();
|
|
int nv = elements[i]->GetNVertices();
|
|
for (j = 0; j < nv; j++)
|
|
{
|
|
v[j] = pts_dof[v[j]];
|
|
}
|
|
}
|
|
// Define the 'vertices' from the 'points' through the 'pts_dof' map
|
|
NumOfVertices = n;
|
|
vertices.SetSize(n);
|
|
for (i = 0; i < np; i++)
|
|
{
|
|
if ((j = pts_dof[i]) != -1)
|
|
{
|
|
vertices[j](0) = points(3*i+0);
|
|
vertices[j](1) = points(3*i+1);
|
|
vertices[j](2) = points(3*i+2);
|
|
}
|
|
}
|
|
|
|
// No boundary is defined in a VTK mesh
|
|
NumOfBdrElements = 0;
|
|
|
|
// Generate faces and edges so that we can define quadratic
|
|
// FE space on the mesh
|
|
FinalizeTopology();
|
|
finalize_topo = false;
|
|
|
|
// Define quadratic FE space
|
|
FiniteElementCollection *fec = new QuadraticFECollection;
|
|
FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim);
|
|
Nodes = new GridFunction(fes);
|
|
Nodes->MakeOwner(fec); // Nodes will destroy 'fec' and 'fes'
|
|
own_nodes = 1;
|
|
|
|
// Map vtk points to edge/face/element dofs
|
|
Array<int> dofs;
|
|
for (n = i = 0; i < NumOfElements; i++)
|
|
{
|
|
fes->GetElementDofs(i, dofs);
|
|
const int *vtk_mfem;
|
|
switch (elements[i]->GetGeometryType())
|
|
{
|
|
case Geometry::TRIANGLE:
|
|
case Geometry::SQUARE:
|
|
vtk_mfem = vtk_quadratic_hex; break; // identity map
|
|
case Geometry::TETRAHEDRON:
|
|
vtk_mfem = vtk_quadratic_tet; break;
|
|
case Geometry::CUBE:
|
|
vtk_mfem = vtk_quadratic_hex; break;
|
|
case Geometry::PRISM:
|
|
vtk_mfem = vtk_quadratic_wedge; break;
|
|
default:
|
|
vtk_mfem = NULL; // suppress a warning
|
|
break;
|
|
}
|
|
|
|
for (n++, j = 0; j < dofs.Size(); j++, n++)
|
|
{
|
|
if (pts_dof[cells_data[n]] == -1)
|
|
{
|
|
pts_dof[cells_data[n]] = dofs[vtk_mfem[j]];
|
|
}
|
|
else
|
|
{
|
|
if (pts_dof[cells_data[n]] != dofs[vtk_mfem[j]])
|
|
{
|
|
MFEM_ABORT("VTK mesh : inconsistent quadratic mesh!");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Define the 'Nodes' from the 'points' through the 'pts_dof' map
|
|
for (i = 0; i < np; i++)
|
|
{
|
|
dofs.SetSize(1);
|
|
if ((dofs[0] = pts_dof[i]) != -1)
|
|
{
|
|
fes->DofsToVDofs(dofs);
|
|
for (j = 0; j < dofs.Size(); j++)
|
|
{
|
|
(*Nodes)(dofs[j]) = points(3*i+j);
|
|
}
|
|
}
|
|
}
|
|
|
|
read_gf = 0;
|
|
}
|
|
}
|
|
|
|
void Mesh::ReadNURBSMesh(std::istream &input, int &curved, int &read_gf)
|
|
{
|
|
NURBSext = new NURBSExtension(input);
|
|
|
|
Dim = NURBSext->Dimension();
|
|
NumOfVertices = NURBSext->GetNV();
|
|
NumOfElements = NURBSext->GetNE();
|
|
NumOfBdrElements = NURBSext->GetNBE();
|
|
|
|
NURBSext->GetElementTopo(elements);
|
|
NURBSext->GetBdrElementTopo(boundary);
|
|
|
|
vertices.SetSize(NumOfVertices);
|
|
curved = 1;
|
|
if (NURBSext->HavePatches())
|
|
{
|
|
NURBSFECollection *fec = new NURBSFECollection(NURBSext->GetOrder());
|
|
FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim,
|
|
Ordering::byVDIM);
|
|
Nodes = new GridFunction(fes);
|
|
Nodes->MakeOwner(fec);
|
|
NURBSext->SetCoordsFromPatches(*Nodes);
|
|
own_nodes = 1;
|
|
read_gf = 0;
|
|
int vd = Nodes->VectorDim();
|
|
for (int i = 0; i < vd; i++)
|
|
{
|
|
Vector vert_val;
|
|
Nodes->GetNodalValues(vert_val, i+1);
|
|
for (int j = 0; j < NumOfVertices; j++)
|
|
{
|
|
vertices[j](i) = vert_val(j);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
read_gf = 1;
|
|
}
|
|
}
|
|
|
|
void Mesh::ReadInlineMesh(std::istream &input, bool generate_edges)
|
|
{
|
|
// Initialize to negative numbers so that we know if they've been set. We're
|
|
// using Element::POINT as our flag, since we're not going to make a 0D mesh,
|
|
// ever.
|
|
int nx = -1;
|
|
int ny = -1;
|
|
int nz = -1;
|
|
double sx = -1.0;
|
|
double sy = -1.0;
|
|
double sz = -1.0;
|
|
Element::Type type = Element::POINT;
|
|
|
|
while (true)
|
|
{
|
|
skip_comment_lines(input, '#');
|
|
// Break out if we reached the end of the file after gobbling up the
|
|
// whitespace and comments after the last keyword.
|
|
if (!input.good())
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Read the next keyword
|
|
std::string name;
|
|
input >> name;
|
|
input >> std::ws;
|
|
// Make sure there's an equal sign
|
|
MFEM_VERIFY(input.get() == '=',
|
|
"Inline mesh expected '=' after keyword " << name);
|
|
input >> std::ws;
|
|
|
|
if (name == "nx")
|
|
{
|
|
input >> nx;
|
|
}
|
|
else if (name == "ny")
|
|
{
|
|
input >> ny;
|
|
}
|
|
else if (name == "nz")
|
|
{
|
|
input >> nz;
|
|
}
|
|
else if (name == "sx")
|
|
{
|
|
input >> sx;
|
|
}
|
|
else if (name == "sy")
|
|
{
|
|
input >> sy;
|
|
}
|
|
else if (name == "sz")
|
|
{
|
|
input >> sz;
|
|
}
|
|
else if (name == "type")
|
|
{
|
|
std::string eltype;
|
|
input >> eltype;
|
|
if (eltype == "segment")
|
|
{
|
|
type = Element::SEGMENT;
|
|
}
|
|
else if (eltype == "quad")
|
|
{
|
|
type = Element::QUADRILATERAL;
|
|
}
|
|
else if (eltype == "tri")
|
|
{
|
|
type = Element::TRIANGLE;
|
|
}
|
|
else if (eltype == "hex")
|
|
{
|
|
type = Element::HEXAHEDRON;
|
|
}
|
|
else if (eltype == "wedge")
|
|
{
|
|
type = Element::WEDGE;
|
|
}
|
|
else if (eltype == "tet")
|
|
{
|
|
type = Element::TETRAHEDRON;
|
|
}
|
|
else
|
|
{
|
|
MFEM_ABORT("unrecognized element type (read '" << eltype
|
|
<< "') in inline mesh format. "
|
|
"Allowed: segment, tri, quad, tet, hex, wedge");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MFEM_ABORT("unrecognized keyword (" << name
|
|
<< ") in inline mesh format. "
|
|
"Allowed: nx, ny, nz, type, sx, sy, sz");
|
|
}
|
|
|
|
input >> std::ws;
|
|
// Allow an optional semi-colon at the end of each line.
|
|
if (input.peek() == ';')
|
|
{
|
|
input.get();
|
|
}
|
|
|
|
// Done reading file
|
|
if (!input)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Now make the mesh.
|
|
if (type == Element::SEGMENT)
|
|
{
|
|
MFEM_VERIFY(nx > 0 && sx > 0.0,
|
|
"invalid 1D inline mesh format, all values must be "
|
|
"positive\n"
|
|
<< " nx = " << nx << "\n"
|
|
<< " sx = " << sx << "\n");
|
|
Make1D(nx, sx);
|
|
}
|
|
else if (type == Element::TRIANGLE || type == Element::QUADRILATERAL)
|
|
{
|
|
MFEM_VERIFY(nx > 0 && ny > 0 && sx > 0.0 && sy > 0.0,
|
|
"invalid 2D inline mesh format, all values must be "
|
|
"positive\n"
|
|
<< " nx = " << nx << "\n"
|
|
<< " ny = " << ny << "\n"
|
|
<< " sx = " << sx << "\n"
|
|
<< " sy = " << sy << "\n");
|
|
Make2D(nx, ny, type, sx, sy, generate_edges, true);
|
|
}
|
|
else if (type == Element::TETRAHEDRON || type == Element::WEDGE ||
|
|
type == Element::HEXAHEDRON)
|
|
{
|
|
MFEM_VERIFY(nx > 0 && ny > 0 && nz > 0 &&
|
|
sx > 0.0 && sy > 0.0 && sz > 0.0,
|
|
"invalid 3D inline mesh format, all values must be "
|
|
"positive\n"
|
|
<< " nx = " << nx << "\n"
|
|
<< " ny = " << ny << "\n"
|
|
<< " nz = " << nz << "\n"
|
|
<< " sx = " << sx << "\n"
|
|
<< " sy = " << sy << "\n"
|
|
<< " sz = " << sz << "\n");
|
|
Make3D(nx, ny, nz, type, sx, sy, sz, true);
|
|
// TODO: maybe have an option in the file to control ordering?
|
|
}
|
|
else
|
|
{
|
|
MFEM_ABORT("For inline mesh, must specify an element type ="
|
|
" [segment, tri, quad, tet, hex, wedge]");
|
|
}
|
|
}
|
|
|
|
void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
|
{
|
|
string buff;
|
|
double version;
|
|
int binary, dsize;
|
|
input >> version >> binary >> dsize;
|
|
if (version < 2.2)
|
|
{
|
|
MFEM_ABORT("Gmsh file version < 2.2");
|
|
}
|
|
if (dsize != sizeof(double))
|
|
{
|
|
MFEM_ABORT("Gmsh file : dsize != sizeof(double)");
|
|
}
|
|
getline(input, buff);
|
|
// There is a number 1 in binary format
|
|
if (binary)
|
|
{
|
|
int one;
|
|
input.read(reinterpret_cast<char*>(&one), sizeof(one));
|
|
if (one != 1)
|
|
{
|
|
MFEM_ABORT("Gmsh file : wrong binary format");
|
|
}
|
|
}
|
|
|
|
// A map between a serial number of the vertex and its number in the file
|
|
// (there may be gaps in the numbering, and also Gmsh enumerates vertices
|
|
// starting from 1, not 0)
|
|
map<int, int> vertices_map;
|
|
// Read the lines of the mesh file. If we face specific keyword, we'll treat
|
|
// the section.
|
|
while (input >> buff)
|
|
{
|
|
if (buff == "$Nodes") // reading mesh vertices
|
|
{
|
|
input >> NumOfVertices;
|
|
getline(input, buff);
|
|
vertices.SetSize(NumOfVertices);
|
|
int serial_number;
|
|
const int gmsh_dim = 3; // Gmsh always outputs 3 coordinates
|
|
double coord[gmsh_dim];
|
|
for (int ver = 0; ver < NumOfVertices; ++ver)
|
|
{
|
|
if (binary)
|
|
{
|
|
input.read(reinterpret_cast<char*>(&serial_number), sizeof(int));
|
|
input.read(reinterpret_cast<char*>(coord), gmsh_dim*sizeof(double));
|
|
}
|
|
else // ASCII
|
|
{
|
|
input >> serial_number;
|
|
for (int ci = 0; ci < gmsh_dim; ++ci)
|
|
{
|
|
input >> coord[ci];
|
|
}
|
|
}
|
|
vertices[ver] = Vertex(coord, gmsh_dim);
|
|
vertices_map[serial_number] = ver;
|
|
}
|
|
if (static_cast<int>(vertices_map.size()) != NumOfVertices)
|
|
{
|
|
MFEM_ABORT("Gmsh file : vertices indices are not unique");
|
|
}
|
|
} // section '$Nodes'
|
|
else if (buff == "$Elements") // reading mesh elements
|
|
{
|
|
int num_of_all_elements;
|
|
input >> num_of_all_elements;
|
|
// = NumOfElements + NumOfBdrElements + (maybe, PhysicalPoints)
|
|
getline(input, buff);
|
|
|
|
int serial_number; // serial number of an element
|
|
int type_of_element; // ID describing a type of a mesh element
|
|
int n_tags; // number of different tags describing an element
|
|
int phys_domain; // element's attribute
|
|
int elem_domain; // another element's attribute (rarely used)
|
|
int n_partitions; // number of partitions where an element takes place
|
|
|
|
// number of nodes for each type of Gmsh elements, type is the index of
|
|
// the array + 1
|
|
int nodes_of_gmsh_element[] =
|
|
{
|
|
2, // 2-node line.
|
|
3, // 3-node triangle.
|
|
4, // 4-node quadrangle.
|
|
4, // 4-node tetrahedron.
|
|
8, // 8-node hexahedron.
|
|
6, // 6-node prism.
|
|
5, // 5-node pyramid.
|
|
3, /* 3-node second order line (2 nodes associated with the vertices
|
|
and 1 with the edge). */
|
|
6, /* 6-node second order triangle (3 nodes associated with the
|
|
vertices and 3 with the edges). */
|
|
9, /* 9-node second order quadrangle (4 nodes associated with the
|
|
vertices, 4 with the edges and 1 with the face). */
|
|
10,/* 10-node second order tetrahedron (4 nodes associated with the
|
|
vertices and 6 with the edges). */
|
|
27,/* 27-node second order hexahedron (8 nodes associated with the
|
|
vertices, 12 with the edges, 6 with the faces and 1 with
|
|
the volume). */
|
|
18,/* 18-node second order prism (6 nodes associated with the
|
|
vertices, 9 with the edges and 3 with the quadrangular
|
|
faces). */
|
|
14,/* 14-node second order pyramid (5 nodes associated with the
|
|
vertices, 8 with the edges and 1 with the quadrangular
|
|
face). */
|
|
1, // 1-node point.
|
|
8, /* 8-node second order quadrangle (4 nodes associated with the
|
|
vertices and 4 with the edges). */
|
|
20,/* 20-node second order hexahedron (8 nodes associated with the
|
|
vertices and 12 with the edges). */
|
|
15,/* 15-node second order prism (6 nodes associated with the
|
|
vertices and 9 with the edges). */
|
|
13,/* 13-node second order pyramid (5 nodes associated with the
|
|
vertices and 8 with the edges). */
|
|
9, /* 9-node third order incomplete triangle (3 nodes associated
|
|
with the vertices, 6 with the edges) */
|
|
10,/* 10-node third order triangle (3 nodes associated with the
|
|
vertices, 6 with the edges, 1 with the face) */
|
|
12,/* 12-node fourth order incomplete triangle (3 nodes associated
|
|
with the vertices, 9 with the edges) */
|
|
15,/* 15-node fourth order triangle (3 nodes associated with the
|
|
vertices, 9 with the edges, 3 with the face) */
|
|
15,/* 15-node fifth order incomplete triangle (3 nodes associated
|
|
with the vertices, 12 with the edges) */
|
|
21,/* 21-node fifth order complete triangle (3 nodes associated with
|
|
the vertices, 12 with the edges, 6 with the face) */
|
|
4, /* 4-node third order edge (2 nodes associated with the vertices,
|
|
2 internal to the edge) */
|
|
5, /* 5-node fourth order edge (2 nodes associated with the
|
|
vertices, 3 internal to the edge) */
|
|
6, /* 6-node fifth order edge (2 nodes associated with the vertices,
|
|
4 internal to the edge) */
|
|
20 /* 20-node third order tetrahedron (4 nodes associated with the
|
|
vertices, 12 with the edges, 4 with the faces) */
|
|
};
|
|
|
|
vector<Element*> elements_0D, elements_1D, elements_2D, elements_3D;
|
|
elements_0D.reserve(num_of_all_elements);
|
|
elements_1D.reserve(num_of_all_elements);
|
|
elements_2D.reserve(num_of_all_elements);
|
|
elements_3D.reserve(num_of_all_elements);
|
|
|
|
if (binary)
|
|
{
|
|
int n_elem_part = 0; // partial sum of elements that are read
|
|
const int header_size = 3;
|
|
// header consists of 3 numbers: type of the element, number of
|
|
// elements of this type, and number of tags
|
|
int header[header_size];
|
|
int n_elem_one_type; // number of elements of a specific type
|
|
|
|
while (n_elem_part < num_of_all_elements)
|
|
{
|
|
input.read(reinterpret_cast<char*>(header),
|
|
header_size*sizeof(int));
|
|
type_of_element = header[0];
|
|
n_elem_one_type = header[1];
|
|
n_tags = header[2];
|
|
|
|
n_elem_part += n_elem_one_type;
|
|
|
|
const int n_elem_nodes = nodes_of_gmsh_element[type_of_element-1];
|
|
vector<int> data(1+n_tags+n_elem_nodes);
|
|
for (int el = 0; el < n_elem_one_type; ++el)
|
|
{
|
|
input.read(reinterpret_cast<char*>(&data[0]),
|
|
data.size()*sizeof(int));
|
|
int dd = 0; // index for data array
|
|
serial_number = data[dd++];
|
|
// physical domain - the most important value (to distinguish
|
|
// materials with different properties)
|
|
phys_domain = (n_tags > 0) ? data[dd++] : 1;
|
|
// elementary domain - to distinguish different geometrical
|
|
// domains (typically, it's used rarely)
|
|
elem_domain = (n_tags > 1) ? data[dd++] : 0;
|
|
// the number of tags is bigger than 2 if there are some
|
|
// partitions (domain decompositions)
|
|
n_partitions = (n_tags > 2) ? data[dd++] : 0;
|
|
// we currently just skip the partitions if they exist, and go
|
|
// directly to vertices describing the mesh element
|
|
vector<int> vert_indices(n_elem_nodes);
|
|
for (int vi = 0; vi < n_elem_nodes; ++vi)
|
|
{
|
|
map<int, int>::const_iterator it =
|
|
vertices_map.find(data[1+n_tags+vi]);
|
|
if (it == vertices_map.end())
|
|
{
|
|
MFEM_ABORT("Gmsh file : vertex index doesn't exist");
|
|
}
|
|
vert_indices[vi] = it->second;
|
|
}
|
|
|
|
// non-positive attributes are not allowed in MFEM
|
|
if (phys_domain <= 0)
|
|
{
|
|
MFEM_ABORT("Non-positive element attribute in Gmsh mesh!");
|
|
}
|
|
|
|
// initialize the mesh element
|
|
switch (type_of_element)
|
|
{
|
|
case 1: // 2-node line
|
|
{
|
|
elements_1D.push_back(
|
|
new Segment(&vert_indices[0], phys_domain));
|
|
break;
|
|
}
|
|
case 2: // 3-node triangle
|
|
{
|
|
elements_2D.push_back(
|
|
new Triangle(&vert_indices[0], phys_domain));
|
|
break;
|
|
}
|
|
case 3: // 4-node quadrangle
|
|
{
|
|
elements_2D.push_back(
|
|
new Quadrilateral(&vert_indices[0], phys_domain));
|
|
break;
|
|
}
|
|
case 4: // 4-node tetrahedron
|
|
{
|
|
#ifdef MFEM_USE_MEMALLOC
|
|
elements_3D.push_back(TetMemory.Alloc());
|
|
elements_3D.back()->SetVertices(&vert_indices[0]);
|
|
elements_3D.back()->SetAttribute(phys_domain);
|
|
#else
|
|
elements_3D.push_back(
|
|
new Tetrahedron(&vert_indices[0], phys_domain));
|
|
#endif
|
|
break;
|
|
}
|
|
case 5: // 8-node hexahedron
|
|
{
|
|
elements_3D.push_back(
|
|
new Hexahedron(&vert_indices[0], phys_domain));
|
|
break;
|
|
}
|
|
case 15: // 1-node point
|
|
{
|
|
elements_0D.push_back(
|
|
new Point(&vert_indices[0], phys_domain));
|
|
break;
|
|
}
|
|
default: // any other element
|
|
MFEM_WARNING("Unsupported Gmsh element type.");
|
|
break;
|
|
|
|
} // switch (type_of_element)
|
|
} // el (elements of one type)
|
|
} // all elements
|
|
} // if binary
|
|
else // ASCII
|
|
{
|
|
for (int el = 0; el < num_of_all_elements; ++el)
|
|
{
|
|
input >> serial_number >> type_of_element >> n_tags;
|
|
vector<int> data(n_tags);
|
|
for (int i = 0; i < n_tags; ++i) { input >> data[i]; }
|
|
// physical domain - the most important value (to distinguish
|
|
// materials with different properties)
|
|
phys_domain = (n_tags > 0) ? data[0] : 1;
|
|
// elementary domain - to distinguish different geometrical
|
|
// domains (typically, it's used rarely)
|
|
elem_domain = (n_tags > 1) ? data[1] : 0;
|
|
// the number of tags is bigger than 2 if there are some
|
|
// partitions (domain decompositions)
|
|
n_partitions = (n_tags > 2) ? data[2] : 0;
|
|
// we currently just skip the partitions if they exist, and go
|
|
// directly to vertices describing the mesh element
|
|
const int n_elem_nodes = nodes_of_gmsh_element[type_of_element-1];
|
|
vector<int> vert_indices(n_elem_nodes);
|
|
int index;
|
|
for (int vi = 0; vi < n_elem_nodes; ++vi)
|
|
{
|
|
input >> index;
|
|
map<int, int>::const_iterator it = vertices_map.find(index);
|
|
if (it == vertices_map.end())
|
|
{
|
|
MFEM_ABORT("Gmsh file : vertex index doesn't exist");
|
|
}
|
|
vert_indices[vi] = it->second;
|
|
}
|
|
|
|
// non-positive attributes are not allowed in MFEM
|
|
if (phys_domain <= 0)
|
|
{
|
|
MFEM_ABORT("Non-positive element attribute in Gmsh mesh!");
|
|
}
|
|
|
|
// initialize the mesh element
|
|
switch (type_of_element)
|
|
{
|
|
case 1: // 2-node line
|
|
{
|
|
elements_1D.push_back(
|
|
new Segment(&vert_indices[0], phys_domain));
|
|
break;
|
|
}
|
|
case 2: // 3-node triangle
|
|
{
|
|
elements_2D.push_back(
|
|
new Triangle(&vert_indices[0], phys_domain));
|
|
break;
|
|
}
|
|
case 3: // 4-node quadrangle
|
|
{
|
|
elements_2D.push_back(
|
|
new Quadrilateral(&vert_indices[0], phys_domain));
|
|
break;
|
|
}
|
|
case 4: // 4-node tetrahedron
|
|
{
|
|
#ifdef MFEM_USE_MEMALLOC
|
|
elements_3D.push_back(TetMemory.Alloc());
|
|
elements_3D.back()->SetVertices(&vert_indices[0]);
|
|
elements_3D.back()->SetAttribute(phys_domain);
|
|
#else
|
|
elements_3D.push_back(
|
|
new Tetrahedron(&vert_indices[0], phys_domain));
|
|
#endif
|
|
break;
|
|
}
|
|
case 5: // 8-node hexahedron
|
|
{
|
|
elements_3D.push_back(
|
|
new Hexahedron(&vert_indices[0], phys_domain));
|
|
break;
|
|
}
|
|
case 15: // 1-node point
|
|
{
|
|
elements_0D.push_back(
|
|
new Point(&vert_indices[0], phys_domain));
|
|
break;
|
|
}
|
|
default: // any other element
|
|
MFEM_WARNING("Unsupported Gmsh element type.");
|
|
break;
|
|
|
|
} // switch (type_of_element)
|
|
} // el (all elements)
|
|
} // if ASCII
|
|
|
|
if (!elements_3D.empty())
|
|
{
|
|
Dim = 3;
|
|
NumOfElements = elements_3D.size();
|
|
elements.SetSize(NumOfElements);
|
|
for (int el = 0; el < NumOfElements; ++el)
|
|
{
|
|
elements[el] = elements_3D[el];
|
|
}
|
|
NumOfBdrElements = elements_2D.size();
|
|
boundary.SetSize(NumOfBdrElements);
|
|
for (int el = 0; el < NumOfBdrElements; ++el)
|
|
{
|
|
boundary[el] = elements_2D[el];
|
|
}
|
|
// discard other elements
|
|
for (size_t el = 0; el < elements_1D.size(); ++el)
|
|
{
|
|
delete elements_1D[el];
|
|
}
|
|
for (size_t el = 0; el < elements_0D.size(); ++el)
|
|
{
|
|
delete elements_0D[el];
|
|
}
|
|
}
|
|
else if (!elements_2D.empty())
|
|
{
|
|
Dim = 2;
|
|
NumOfElements = elements_2D.size();
|
|
elements.SetSize(NumOfElements);
|
|
for (int el = 0; el < NumOfElements; ++el)
|
|
{
|
|
elements[el] = elements_2D[el];
|
|
}
|
|
NumOfBdrElements = elements_1D.size();
|
|
boundary.SetSize(NumOfBdrElements);
|
|
for (int el = 0; el < NumOfBdrElements; ++el)
|
|
{
|
|
boundary[el] = elements_1D[el];
|
|
}
|
|
// discard other elements
|
|
for (size_t el = 0; el < elements_0D.size(); ++el)
|
|
{
|
|
delete elements_0D[el];
|
|
}
|
|
}
|
|
else if (!elements_1D.empty())
|
|
{
|
|
Dim = 1;
|
|
NumOfElements = elements_1D.size();
|
|
elements.SetSize(NumOfElements);
|
|
for (int el = 0; el < NumOfElements; ++el)
|
|
{
|
|
elements[el] = elements_1D[el];
|
|
}
|
|
NumOfBdrElements = elements_0D.size();
|
|
boundary.SetSize(NumOfBdrElements);
|
|
for (int el = 0; el < NumOfBdrElements; ++el)
|
|
{
|
|
boundary[el] = elements_0D[el];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MFEM_ABORT("Gmsh file : no elements found");
|
|
return;
|
|
}
|
|
|
|
MFEM_CONTRACT_VAR(n_partitions);
|
|
MFEM_CONTRACT_VAR(elem_domain);
|
|
|
|
} // section '$Elements'
|
|
else if (buff == "$Periodic") // Reading master/slave node pairs
|
|
{
|
|
curved = 1;
|
|
read_gf = 0;
|
|
spaceDim = 3;
|
|
|
|
Array<int> v2v(NumOfVertices);
|
|
for (int i = 0; i < v2v.Size(); i++)
|
|
{
|
|
v2v[i] = i;
|
|
}
|
|
int num_per_ent;
|
|
int num_nodes;
|
|
int slave, master;
|
|
input >> num_per_ent;
|
|
getline(input, buff); // Read end-of-line
|
|
for (int i = 0; i < num_per_ent; i++)
|
|
{
|
|
getline(input, buff); // Read and ignore entity dimension and tags
|
|
getline(input, buff); // Read and ignore affine mapping
|
|
// Read master/slave vertex pairs
|
|
input >> num_nodes;
|
|
for (int j=0; j<num_nodes; j++)
|
|
{
|
|
input >> slave >> master;
|
|
v2v[slave - 1] = master - 1;
|
|
}
|
|
getline(input, buff); // Read end-of-line
|
|
}
|
|
|
|
// Convert nodes to discontinuous GridFunction
|
|
this->SetCurvature(1, true, Dim, Ordering::byVDIM);
|
|
|
|
// Replace "slave" vertex indices in the element connectivity
|
|
// with their corresponding "master" vertex indices.
|
|
for (int i = 0; i < this->GetNE(); i++)
|
|
{
|
|
Element *el = this->GetElement(i);
|
|
int *v = el->GetVertices();
|
|
int nv = el->GetNVertices();
|
|
for (int j = 0; j < nv; j++)
|
|
{
|
|
v[j] = v2v[v[j]];
|
|
}
|
|
}
|
|
// Replace "slave" vertex indices in the boundary element connectivity
|
|
// with their corresponding "master" vertex indices.
|
|
for (int i = 0; i < this->GetNBE(); i++)
|
|
{
|
|
Element *el = this->GetBdrElement(i);
|
|
int *v = el->GetVertices();
|
|
int nv = el->GetNVertices();
|
|
for (int j = 0; j < nv; j++)
|
|
{
|
|
v[j] = v2v[v[j]];
|
|
}
|
|
}
|
|
this->RemoveUnusedVertices();
|
|
this->RemoveInternalBoundaries();
|
|
}
|
|
} // we reach the end of the file
|
|
}
|
|
|
|
|
|
#ifdef MFEM_USE_NETCDF
|
|
void Mesh::ReadCubit(const char *filename, int &curved, int &read_gf)
|
|
{
|
|
read_gf = 0;
|
|
|
|
// curved set to zero will change if mesh is indeed curved
|
|
curved = 0;
|
|
|
|
const int sideMapTri3[3][2] =
|
|
{
|
|
{1,2},
|
|
{2,3},
|
|
{3,1},
|
|
};
|
|
|
|
const int sideMapQuad4[4][2] =
|
|
{
|
|
{1,2},
|
|
{2,3},
|
|
{3,4},
|
|
{4,1},
|
|
};
|
|
|
|
const int sideMapTri6[3][3] =
|
|
{
|
|
{1,2,4},
|
|
{2,3,5},
|
|
{3,1,6},
|
|
};
|
|
|
|
const int sideMapQuad9[4][3] =
|
|
{
|
|
{1,2,5},
|
|
{2,3,6},
|
|
{3,4,7},
|
|
{4,1,8},
|
|
};
|
|
|
|
const int sideMapTet4[4][3] =
|
|
{
|
|
{1,2,4},
|
|
{2,3,4},
|
|
{1,4,3},
|
|
{1,3,2}
|
|
};
|
|
|
|
const int sideMapTet10[4][6] =
|
|
{
|
|
{1,2,4,5,9,8},
|
|
{2,3,4,6,10,9},
|
|
{1,4,3,8,10,7},
|
|
{1,3,2,7,6,5}
|
|
};
|
|
|
|
const int sideMapHex8[6][4] =
|
|
{
|
|
{1,2,6,5},
|
|
{2,3,7,6},
|
|
{4,3,7,8},
|
|
{1,4,8,5},
|
|
{1,4,3,2},
|
|
{5,8,7,6}
|
|
};
|
|
|
|
const int sideMapHex27[6][9] =
|
|
{
|
|
{1,2,6,5,9,14,17,13,26},
|
|
{2,3,7,6,10,15,18,14,25},
|
|
{4,3,7,8,11,15,19,16,27},
|
|
{1,4,8,5,12,16,20,13,24},
|
|
{1,4,3,2,12,11,10,9,22},
|
|
{5,8,7,6,20,19,18,17,23}
|
|
};
|
|
|
|
|
|
// 1,2,3,4,5,6,7,8,9,10
|
|
const int mfemToGenesisTet10[10] = {1,2,3,4,5,7,8,6,9,10};
|
|
|
|
// 1,2,3,4,5,6,7,8,9,10,11,
|
|
const int mfemToGenesisHex27[27] = {1,2,3,4,5,6,7,8,9,10,11,
|
|
// 12,13,14,15,16,17,18,19
|
|
12,17,18,19,20,13,14,15,
|
|
// 20,21,22,23,24,25,26,27
|
|
16,22,26,25,27,24,23,21
|
|
};
|
|
|
|
const int mfemToGenesisTri6[6] = {1,2,3,4,5,6};
|
|
const int mfemToGenesisQuad9[9] = {1,2,3,4,5,6,7,8,9};
|
|
|
|
|
|
// error handling.
|
|
int retval;
|
|
|
|
// dummy string
|
|
char str_dummy[256];
|
|
|
|
char temp_str[256];
|
|
int temp_id;
|
|
|
|
// open the file.
|
|
int ncid;
|
|
if ((retval = nc_open(filename, NC_NOWRITE, &ncid)))
|
|
{
|
|
MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
|
|
}
|
|
|
|
// read important dimensions
|
|
|
|
int id;
|
|
size_t num_dim=0, num_nodes=0, num_elem=0, num_el_blk=0, num_side_sets=0;
|
|
|
|
if ((retval = nc_inq_dimid(ncid, "num_dim", &id)) ||
|
|
(retval = nc_inq_dim(ncid, id, str_dummy, &num_dim)) ||
|
|
|
|
(retval = nc_inq_dimid(ncid, "num_nodes", &id)) ||
|
|
(retval = nc_inq_dim(ncid, id, str_dummy, &num_nodes)) ||
|
|
|
|
(retval = nc_inq_dimid(ncid, "num_elem", &id)) ||
|
|
(retval = nc_inq_dim(ncid, id, str_dummy, &num_elem)) ||
|
|
|
|
(retval = nc_inq_dimid(ncid, "num_el_blk", &id)) ||
|
|
(retval = nc_inq_dim(ncid, id, str_dummy, &num_el_blk)))
|
|
{
|
|
MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
|
|
}
|
|
if ((retval = nc_inq_dimid(ncid, "num_side_sets", &id)) ||
|
|
(retval = nc_inq_dim(ncid, id, str_dummy, &num_side_sets)))
|
|
{
|
|
num_side_sets = 0;
|
|
}
|
|
|
|
Dim = num_dim;
|
|
|
|
// create arrays for element blocks
|
|
size_t *num_el_in_blk = new size_t[num_el_blk];
|
|
size_t num_node_per_el;
|
|
|
|
int previous_num_node_per_el = 0;
|
|
for (int i = 0; i < (int) num_el_blk; i++)
|
|
{
|
|
sprintf(temp_str, "num_el_in_blk%d", i+1);
|
|
if ((retval = nc_inq_dimid(ncid, temp_str, &temp_id)) ||
|
|
(retval = nc_inq_dim(ncid, temp_id, str_dummy, &num_el_in_blk[i])))
|
|
{
|
|
MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
|
|
}
|
|
|
|
sprintf(temp_str, "num_nod_per_el%d", i+1);
|
|
if ((retval = nc_inq_dimid(ncid, temp_str, &temp_id)) ||
|
|
(retval = nc_inq_dim(ncid, temp_id, str_dummy, &num_node_per_el)))
|
|
{
|
|
MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
|
|
}
|
|
|
|
// check for different element types in each block
|
|
// which is not currently supported
|
|
if (i != 0)
|
|
{
|
|
if ((int) num_node_per_el != previous_num_node_per_el)
|
|
{
|
|
MFEM_ABORT("Element blocks of different element types not supported");
|
|
}
|
|
}
|
|
previous_num_node_per_el = num_node_per_el;
|
|
}
|
|
|
|
// Determine CUBIT element and face type
|
|
enum CubitElementType
|
|
{
|
|
ELEMENT_TRI3,
|
|
ELEMENT_TRI6,
|
|
ELEMENT_QUAD4,
|
|
ELEMENT_QUAD9,
|
|
ELEMENT_TET4,
|
|
ELEMENT_TET10,
|
|
ELEMENT_HEX8,
|
|
ELEMENT_HEX27
|
|
};
|
|
|
|
enum CubitFaceType
|
|
{
|
|
FACE_EDGE2,
|
|
FACE_EDGE3,
|
|
FACE_TRI3,
|
|
FACE_TRI6,
|
|
FACE_QUAD4,
|
|
FACE_QUAD9
|
|
};
|
|
|
|
CubitElementType cubit_element_type = ELEMENT_TRI3; // suppress a warning
|
|
CubitFaceType cubit_face_type = FACE_EDGE2; // suppress a warning
|
|
int num_element_linear_nodes = 0; // initialize to suppress a warning
|
|
|
|
if (num_dim == 2)
|
|
{
|
|
switch (num_node_per_el)
|
|
{
|
|
case (3) :
|
|
{
|
|
cubit_element_type = ELEMENT_TRI3;
|
|
cubit_face_type = FACE_EDGE2;
|
|
num_element_linear_nodes = 3;
|
|
break;
|
|
}
|
|
case (6) :
|
|
{
|
|
cubit_element_type = ELEMENT_TRI6;
|
|
cubit_face_type = FACE_EDGE3;
|
|
num_element_linear_nodes = 3;
|
|
break;
|
|
}
|
|
case (4) :
|
|
{
|
|
cubit_element_type = ELEMENT_QUAD4;
|
|
cubit_face_type = FACE_EDGE2;
|
|
num_element_linear_nodes = 4;
|
|
break;
|
|
}
|
|
case (9) :
|
|
{
|
|
cubit_element_type = ELEMENT_QUAD9;
|
|
cubit_face_type = FACE_EDGE3;
|
|
num_element_linear_nodes = 4;
|
|
break;
|
|
}
|
|
default :
|
|
{
|
|
MFEM_ABORT("Don't know what to do with a " << num_node_per_el <<
|
|
" node 2D element\n");
|
|
}
|
|
}
|
|
}
|
|
else if (num_dim == 3)
|
|
{
|
|
switch (num_node_per_el)
|
|
{
|
|
case (4) :
|
|
{
|
|
cubit_element_type = ELEMENT_TET4;
|
|
cubit_face_type = FACE_TRI3;
|
|
num_element_linear_nodes = 4;
|
|
break;
|
|
}
|
|
case (10) :
|
|
{
|
|
cubit_element_type = ELEMENT_TET10;
|
|
cubit_face_type = FACE_TRI6;
|
|
num_element_linear_nodes = 4;
|
|
break;
|
|
}
|
|
case (8) :
|
|
{
|
|
cubit_element_type = ELEMENT_HEX8;
|
|
cubit_face_type = FACE_QUAD4;
|
|
num_element_linear_nodes = 8;
|
|
break;
|
|
}
|
|
case (27) :
|
|
{
|
|
cubit_element_type = ELEMENT_HEX27;
|
|
cubit_face_type = FACE_QUAD9;
|
|
num_element_linear_nodes = 8;
|
|
break;
|
|
}
|
|
default :
|
|
{
|
|
MFEM_ABORT("Don't know what to do with a " << num_node_per_el <<
|
|
" node 3D element\n");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MFEM_ABORT("Invalid dimension: num_dim = " << num_dim);
|
|
}
|
|
|
|
// Determine order of elements
|
|
int order = 0;
|
|
if (cubit_element_type == ELEMENT_TRI3 || cubit_element_type == ELEMENT_QUAD4 ||
|
|
cubit_element_type == ELEMENT_TET4 || cubit_element_type == ELEMENT_HEX8)
|
|
{
|
|
order = 1;
|
|
}
|
|
else if (cubit_element_type == ELEMENT_TRI6 ||
|
|
cubit_element_type == ELEMENT_QUAD9 ||
|
|
cubit_element_type == ELEMENT_TET10 || cubit_element_type == ELEMENT_HEX27)
|
|
{
|
|
order = 2;
|
|
}
|
|
|
|
// create array for number of sides in side sets
|
|
size_t *num_side_in_ss = new size_t[num_side_sets];
|
|
for (int i = 0; i < (int) num_side_sets; i++)
|
|
{
|
|
sprintf(temp_str, "num_side_ss%d", i+1);
|
|
if ((retval = nc_inq_dimid(ncid, temp_str, &temp_id)) ||
|
|
(retval = nc_inq_dim(ncid, temp_id, str_dummy, &num_side_in_ss[i])))
|
|
{
|
|
MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
|
|
}
|
|
}
|
|
|
|
// read the coordinates
|
|
double *coordx = new double[num_nodes];
|
|
double *coordy = new double[num_nodes];
|
|
double *coordz = new double[num_nodes];
|
|
|
|
if ((retval = nc_inq_varid(ncid, "coordx", &id)) ||
|
|
(retval = nc_get_var_double(ncid, id, coordx)) ||
|
|
(retval = nc_inq_varid(ncid, "coordy", &id)) ||
|
|
(retval = nc_get_var_double(ncid, id, coordy)))
|
|
{
|
|
MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
|
|
}
|
|
|
|
if (num_dim == 3)
|
|
{
|
|
if ((retval = nc_inq_varid(ncid, "coordz", &id)) ||
|
|
(retval = nc_get_var_double(ncid, id, coordz)))
|
|
{
|
|
MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
|
|
}
|
|
}
|
|
|
|
// read the element blocks
|
|
int **elem_blk = new int*[num_el_blk];
|
|
for (int i = 0; i < (int) num_el_blk; i++)
|
|
{
|
|
elem_blk[i] = new int[num_el_in_blk[i] * num_node_per_el];
|
|
sprintf(temp_str, "connect%d", i+1);
|
|
if ((retval = nc_inq_varid(ncid, temp_str, &temp_id)) ||
|
|
(retval = nc_get_var_int(ncid, temp_id, elem_blk[i])))
|
|
{
|
|
MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
|
|
}
|
|
}
|
|
int *ebprop = new int[num_el_blk];
|
|
if ((retval = nc_inq_varid(ncid, "eb_prop1", &id)) ||
|
|
(retval = nc_get_var_int(ncid, id, ebprop)))
|
|
{
|
|
MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
|
|
}
|
|
|
|
// read the side sets, a side is is given by (element, face) pairs
|
|
|
|
int **elem_ss = new int*[num_side_sets];
|
|
int **side_ss = new int*[num_side_sets];
|
|
|
|
for (int i = 0; i < (int) num_side_sets; i++)
|
|
{
|
|
elem_ss[i] = new int[num_side_in_ss[i]];
|
|
side_ss[i] = new int[num_side_in_ss[i]];
|
|
|
|
sprintf(temp_str, "elem_ss%d", i+1);
|
|
if ((retval = nc_inq_varid(ncid, temp_str, &temp_id)) ||
|
|
(retval = nc_get_var_int(ncid, temp_id, elem_ss[i])))
|
|
{
|
|
MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
|
|
}
|
|
|
|
sprintf(temp_str,"side_ss%d",i+1);
|
|
if ((retval = nc_inq_varid(ncid, temp_str, &temp_id)) ||
|
|
(retval = nc_get_var_int(ncid, temp_id, side_ss[i])))
|
|
{
|
|
MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
|
|
}
|
|
}
|
|
|
|
int *ssprop = new int[num_side_sets];
|
|
if ((num_side_sets > 0) &&
|
|
((retval = nc_inq_varid(ncid, "ss_prop1", &id)) ||
|
|
(retval = nc_get_var_int(ncid, id, ssprop))))
|
|
{
|
|
MFEM_ABORT("Fatal NetCDF error: " << nc_strerror(retval));
|
|
}
|
|
|
|
// convert (elem,side) pairs to 2D elements
|
|
|
|
|
|
int num_face_nodes = 0;
|
|
int num_face_linear_nodes = 0;
|
|
|
|
switch (cubit_face_type)
|
|
{
|
|
case (FACE_EDGE2):
|
|
{
|
|
num_face_nodes = 2;
|
|
num_face_linear_nodes = 2;
|
|
break;
|
|
}
|
|
case (FACE_EDGE3):
|
|
{
|
|
num_face_nodes = 3;
|
|
num_face_linear_nodes = 2;
|
|
break;
|
|
}
|
|
case (FACE_TRI3):
|
|
{
|
|
num_face_nodes = 3;
|
|
num_face_linear_nodes = 3;
|
|
break;
|
|
}
|
|
case (FACE_TRI6):
|
|
{
|
|
num_face_nodes = 6;
|
|
num_face_linear_nodes = 3;
|
|
break;
|
|
}
|
|
case (FACE_QUAD4):
|
|
{
|
|
num_face_nodes = 4;
|
|
num_face_linear_nodes = 4;
|
|
break;
|
|
}
|
|
case (FACE_QUAD9):
|
|
{
|
|
num_face_nodes = 9;
|
|
num_face_linear_nodes = 4;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// given a global element number, determine the element block and local
|
|
// element number
|
|
int *start_of_block = new int[num_el_blk+1];
|
|
start_of_block[0] = 0;
|
|
for (int i = 1; i < (int) num_el_blk+1; i++)
|
|
{
|
|
start_of_block[i] = start_of_block[i-1] + num_el_in_blk[i-1];
|
|
}
|
|
|
|
int **ss_node_id = new int*[num_side_sets];
|
|
|
|
for (int i = 0; i < (int) num_side_sets; i++)
|
|
{
|
|
ss_node_id[i] = new int[num_side_in_ss[i]*num_face_nodes];
|
|
for (int j = 0; j < (int) num_side_in_ss[i]; j++)
|
|
{
|
|
int glob_ind = elem_ss[i][j]-1;
|
|
int iblk = 0;
|
|
int loc_ind;
|
|
while (iblk < (int) num_el_blk && glob_ind >= start_of_block[iblk+1])
|
|
{
|
|
iblk++;
|
|
}
|
|
if (iblk >= (int) num_el_blk)
|
|
{
|
|
MFEM_ABORT("Sideset element does not exist");
|
|
}
|
|
loc_ind = glob_ind - start_of_block[iblk];
|
|
int this_side = side_ss[i][j];
|
|
int ielem = loc_ind*num_node_per_el;
|
|
|
|
for (int k = 0; k < num_face_nodes; k++)
|
|
{
|
|
int inode;
|
|
switch (cubit_element_type)
|
|
{
|
|
case (ELEMENT_TRI3):
|
|
{
|
|
inode = sideMapTri3[this_side-1][k];
|
|
break;
|
|
}
|
|
case (ELEMENT_TRI6):
|
|
{
|
|
inode = sideMapTri6[this_side-1][k];
|
|
break;
|
|
}
|
|
case (ELEMENT_QUAD4):
|
|
{
|
|
inode = sideMapQuad4[this_side-1][k];
|
|
break;
|
|
}
|
|
case (ELEMENT_QUAD9):
|
|
{
|
|
inode = sideMapQuad9[this_side-1][k];
|
|
break;
|
|
}
|
|
case (ELEMENT_TET4):
|
|
{
|
|
inode = sideMapTet4[this_side-1][k];
|
|
break;
|
|
}
|
|
case (ELEMENT_TET10):
|
|
{
|
|
inode = sideMapTet10[this_side-1][k];
|
|
break;
|
|
}
|
|
case (ELEMENT_HEX8):
|
|
{
|
|
inode = sideMapHex8[this_side-1][k];
|
|
break;
|
|
}
|
|
case (ELEMENT_HEX27):
|
|
{
|
|
inode = sideMapHex27[this_side-1][k];
|
|
break;
|
|
}
|
|
}
|
|
ss_node_id[i][j*num_face_nodes+k] =
|
|
elem_blk[iblk][ielem + inode - 1];
|
|
}
|
|
}
|
|
}
|
|
|
|
// we need another node ID mapping since MFEM needs contiguous vertex IDs
|
|
std::vector<int> uniqueVertexID;
|
|
|
|
for (int iblk = 0; iblk < (int) num_el_blk; iblk++)
|
|
{
|
|
for (int i = 0; i < (int) num_el_in_blk[iblk]; i++)
|
|
{
|
|
for (int j = 0; j < num_element_linear_nodes; j++)
|
|
{
|
|
uniqueVertexID.push_back(elem_blk[iblk][i*num_node_per_el + j]);
|
|
}
|
|
}
|
|
}
|
|
std::sort(uniqueVertexID.begin(), uniqueVertexID.end());
|
|
std::vector<int>::iterator newEnd;
|
|
newEnd = std::unique(uniqueVertexID.begin(), uniqueVertexID.end());
|
|
uniqueVertexID.resize(std::distance(uniqueVertexID.begin(), newEnd));
|
|
|
|
// OK at this point uniqueVertexID contains a list of all the nodes that are
|
|
// actually used by the mesh, 1-based, and sorted. We need to invert this
|
|
// list, the inverse is a map
|
|
|
|
std::map<int,int> cubitToMFEMVertMap;
|
|
for (int i = 0; i < (int) uniqueVertexID.size(); i++)
|
|
{
|
|
cubitToMFEMVertMap[uniqueVertexID[i]] = i+1;
|
|
}
|
|
MFEM_ASSERT(cubitToMFEMVertMap.size() == uniqueVertexID.size(),
|
|
"This should never happen\n");
|
|
|
|
// OK now load up the MFEM mesh structures
|
|
|
|
// load up the vertices
|
|
|
|
NumOfVertices = uniqueVertexID.size();
|
|
vertices.SetSize(NumOfVertices);
|
|
for (int i = 0; i < (int) uniqueVertexID.size(); i++)
|
|
{
|
|
vertices[i](0) = coordx[uniqueVertexID[i] - 1];
|
|
vertices[i](1) = coordy[uniqueVertexID[i] - 1];
|
|
if (Dim == 3)
|
|
{
|
|
vertices[i](2) = coordz[uniqueVertexID[i] - 1];
|
|
}
|
|
}
|
|
|
|
NumOfElements = num_elem;
|
|
elements.SetSize(num_elem);
|
|
int elcount = 0;
|
|
int renumberedVertID[8];
|
|
for (int iblk = 0; iblk < (int) num_el_blk; iblk++)
|
|
{
|
|
int NumNodePerEl = num_node_per_el;
|
|
for (int i = 0; i < (int) num_el_in_blk[iblk]; i++)
|
|
{
|
|
for (int j = 0; j < num_element_linear_nodes; j++)
|
|
{
|
|
renumberedVertID[j] =
|
|
cubitToMFEMVertMap[elem_blk[iblk][i*NumNodePerEl+j]]-1;
|
|
}
|
|
|
|
switch (cubit_element_type)
|
|
{
|
|
case (ELEMENT_TRI3):
|
|
case (ELEMENT_TRI6):
|
|
{
|
|
elements[elcount] = new Triangle(renumberedVertID,ebprop[iblk]);
|
|
break;
|
|
}
|
|
case (ELEMENT_QUAD4):
|
|
case (ELEMENT_QUAD9):
|
|
{
|
|
elements[elcount] = new Quadrilateral(renumberedVertID,ebprop[iblk]);
|
|
break;
|
|
}
|
|
case (ELEMENT_TET4):
|
|
case (ELEMENT_TET10):
|
|
{
|
|
#ifdef MFEM_USE_MEMALLOC
|
|
elements[elcount] = TetMemory.Alloc();
|
|
elements[elcount]->SetVertices(renumberedVertID);
|
|
elements[elcount]->SetAttribute(ebprop[iblk]);
|
|
#else
|
|
elements[elcount] = new Tetrahedron(renumberedVertID,
|
|
ebprop[iblk]);
|
|
#endif
|
|
break;
|
|
}
|
|
case (ELEMENT_HEX8):
|
|
case (ELEMENT_HEX27):
|
|
{
|
|
elements[elcount] = new Hexahedron(renumberedVertID,ebprop[iblk]);
|
|
break;
|
|
}
|
|
}
|
|
elcount++;
|
|
}
|
|
}
|
|
|
|
// load up the boundary elements
|
|
|
|
NumOfBdrElements = 0;
|
|
for (int iss = 0; iss < (int) num_side_sets; iss++)
|
|
{
|
|
NumOfBdrElements += num_side_in_ss[iss];
|
|
}
|
|
boundary.SetSize(NumOfBdrElements);
|
|
int sidecount = 0;
|
|
for (int iss = 0; iss < (int) num_side_sets; iss++)
|
|
{
|
|
for (int i = 0; i < (int) num_side_in_ss[iss]; i++)
|
|
{
|
|
for (int j = 0; j < num_face_linear_nodes; j++)
|
|
{
|
|
renumberedVertID[j] =
|
|
cubitToMFEMVertMap[ss_node_id[iss][i*num_face_nodes+j]] - 1;
|
|
}
|
|
switch (cubit_face_type)
|
|
{
|
|
case (FACE_EDGE2):
|
|
case (FACE_EDGE3):
|
|
{
|
|
boundary[sidecount] = new Segment(renumberedVertID,ssprop[iss]);
|
|
break;
|
|
}
|
|
case (FACE_TRI3):
|
|
case (FACE_TRI6):
|
|
{
|
|
boundary[sidecount] = new Triangle(renumberedVertID,ssprop[iss]);
|
|
break;
|
|
}
|
|
case (FACE_QUAD4):
|
|
case (FACE_QUAD9):
|
|
{
|
|
boundary[sidecount] = new Quadrilateral(renumberedVertID,ssprop[iss]);
|
|
break;
|
|
}
|
|
}
|
|
sidecount++;
|
|
}
|
|
}
|
|
|
|
if (order == 2)
|
|
{
|
|
curved = 1;
|
|
int *mymap = NULL;
|
|
|
|
switch (cubit_element_type)
|
|
{
|
|
case (ELEMENT_TRI6):
|
|
{
|
|
mymap = (int *) mfemToGenesisTri6;
|
|
break;
|
|
}
|
|
case (ELEMENT_QUAD9):
|
|
{
|
|
mymap = (int *) mfemToGenesisQuad9;
|
|
break;
|
|
}
|
|
case (ELEMENT_TET10):
|
|
{
|
|
mymap = (int *) mfemToGenesisTet10;
|
|
break;
|
|
}
|
|
case (ELEMENT_HEX27):
|
|
{
|
|
mymap = (int *) mfemToGenesisHex27;
|
|
break;
|
|
}
|
|
case (ELEMENT_TRI3):
|
|
case (ELEMENT_QUAD4):
|
|
case (ELEMENT_TET4):
|
|
case (ELEMENT_HEX8):
|
|
{
|
|
MFEM_ABORT("Something went wrong. Linear elements detected when order is 2.");
|
|
break;
|
|
}
|
|
}
|
|
|
|
FinalizeTopology();
|
|
|
|
// Define quadratic FE space
|
|
FiniteElementCollection *fec = new H1_FECollection(2,3);
|
|
FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim,
|
|
Ordering::byVDIM);
|
|
Nodes = new GridFunction(fes);
|
|
Nodes->MakeOwner(fec); // Nodes will destroy 'fec' and 'fes'
|
|
own_nodes = 1;
|
|
|
|
// int nTotDofs = fes->GetNDofs();
|
|
// int nTotVDofs = fes->GetVSize();
|
|
// mfem::out << endl << "nTotDofs = " << nTotDofs << " nTotVDofs "
|
|
// << nTotVDofs << endl << endl;
|
|
|
|
for (int i = 0; i < NumOfElements; i++)
|
|
{
|
|
Array<int> dofs;
|
|
|
|
fes->GetElementDofs(i, dofs);
|
|
Array<int> vdofs;
|
|
vdofs.SetSize(dofs.Size());
|
|
for (int l = 0; l < dofs.Size(); l++) { vdofs[l] = dofs[l]; }
|
|
fes->DofsToVDofs(vdofs);
|
|
int iblk = 0;
|
|
int loc_ind;
|
|
while (iblk < (int) num_el_blk && i >= start_of_block[iblk+1]) { iblk++; }
|
|
loc_ind = i - start_of_block[iblk];
|
|
for (int j = 0; j < dofs.Size(); j++)
|
|
{
|
|
int point_id = elem_blk[iblk][loc_ind*num_node_per_el + mymap[j] - 1] - 1;
|
|
(*Nodes)(vdofs[j]) = coordx[point_id];
|
|
(*Nodes)(vdofs[j]+1) = coordy[point_id];
|
|
if (Dim == 3)
|
|
{
|
|
(*Nodes)(vdofs[j]+2) = coordz[point_id];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// clean up all netcdf stuff
|
|
|
|
nc_close(ncid);
|
|
|
|
for (int i = 0; i < (int) num_side_sets; i++)
|
|
{
|
|
delete [] elem_ss[i];
|
|
delete [] side_ss[i];
|
|
}
|
|
|
|
delete [] elem_ss;
|
|
delete [] side_ss;
|
|
delete [] num_el_in_blk;
|
|
delete [] num_side_in_ss;
|
|
delete [] coordx;
|
|
delete [] coordy;
|
|
delete [] coordz;
|
|
|
|
for (int i = 0; i < (int) num_el_blk; i++)
|
|
{
|
|
delete [] elem_blk[i];
|
|
}
|
|
|
|
delete [] elem_blk;
|
|
delete [] start_of_block;
|
|
|
|
for (int i = 0; i < (int) num_side_sets; i++)
|
|
{
|
|
delete [] ss_node_id[i];
|
|
}
|
|
delete [] ss_node_id;
|
|
delete [] ebprop;
|
|
delete [] ssprop;
|
|
|
|
}
|
|
#endif // #ifdef MFEM_USE_NETCDF
|
|
|
|
} // namespace mfem
|