Created
June 3, 2016 21:49
-
-
Save ibaned/92aaf9a2984e412515cfaac7274e4097 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <apf.h> | |
#include <gmi_null.h> | |
#include <apfMDS.h> | |
#include <apfMesh2.h> | |
#include <PCU.h> | |
#include <apfNumbering.h> | |
#include <apfShape.h> | |
#include <iostream> | |
#include <stdbool.h> | |
#include <limits.h> | |
//#include "funcs1.h" | |
//#include "apfSBPShape.h" | |
//#include "apfSBPShape3.h" | |
struct _Sizes { | |
int numElx; | |
int numEly; | |
int numElz; | |
}; | |
typedef struct _Sizes Sizes; | |
struct _Geom { | |
int model_tag; | |
int model_dim; | |
}; | |
typedef struct _Geom Geom; | |
struct _VertIdx { | |
int i; | |
int j; | |
int k; | |
}; | |
typedef struct _VertIdx VertIdx; | |
// addition on VertIdx | |
VertIdx add(const VertIdx v1, const VertIdx v2); | |
VertIdx add(const VertIdx v1, const int arr[3]); | |
#define NTETS 6 | |
#define NEDGES 19 | |
#define NFACES 18 | |
int tets[NTETS][4][3]; // define vertices used for constructing tetrahedrons | |
int edges[NEDGES][2][3]; // describe vertices defining each edge of the tets | |
int faces[NFACES][3][3]; // describe the vertices defining each face of hte tets | |
#define NREAREDGES 12 | |
int rear_edge_idx[NREAREDGES]; // indices of the rear edges in the edges list | |
bool create_edge[NREAREDGES]; // whether or not to create the edge | |
int rear_face_idx[6]; // indices of rear faces in the faces list | |
bool create_face[6]; // whether or not to create the faces | |
// declare the verts used to break the cube into tetrahedra | |
void declareTets(); | |
// get the classification of vertices at indices (i, j, k) in the array of vertices | |
Geom getVertClassification(int i, int j, int k, Sizes sizes); | |
Geom getVertClassification(VertIdx v, Sizes sizes); | |
// populate the global variable edges by inspecting tets | |
void extractEdges(); | |
// determine if the edge defined by the two vertices is already in the edges list | |
bool checkEdges(int vert1[3], int vert2[3], int nedges); | |
// determine if the face defined by the 3 vertices is already in the faces list | |
bool checkFace(int vert1[3], int vert2[3], int vert3[3], int nfaces); | |
// check of an entry in either edges or faces contains the vertex | |
bool contains(int list_entry[][3], const int dim1, int vert1[3]); | |
// populate the faces global variable by inspecting the tets variable | |
void extractFaces(); | |
// populate the rear_edge_idx and create_edge arrays | |
void extractRearEdges(); | |
// identiry which edges need to be created for a given element | |
void identifyEdges(VertIdx start); | |
// populate rear_face_idx and create_face arrays | |
void extractRearFaces(); | |
// populate create_face | |
void identifyFaces(VertIdx start); | |
// create the edges on a brick | |
void createEdges(apf::Mesh2* m, Sizes sizes, VertIdx start, apf::MeshEntity**** verts); | |
// create a single edge | |
void createEdge(apf::Mesh2* m, apf::MeshEntity* edge_verts[2], apf::ModelEntity* model_entity); | |
// create all the faces on a cube | |
void createFaces(apf::Mesh2* m, Sizes sizes, VertIdx start, apf::MeshEntity**** verts); | |
// create a single face | |
void createFace(apf::Mesh2* m, apf::MeshEntity* edge_verts[3], apf::ModelEntity* model_entity); | |
// get the model entity given the geometric classification of the vertices | |
apf::ModelEntity* getModelEntity(apf::Mesh* m, Geom g_class[], const int ng); | |
// get a vert from the array of all vertices | |
apf::MeshEntity* getVert(VertIdx pos, apf::MeshEntity**** verts); | |
// get the vertices of a tet | |
void getTetVerts(VertIdx start, int tet[4][3], apf::MeshEntity**** verts_all, apf::MeshEntity* verts[4]); | |
// copy array of length 3 | |
void copyArray(int src[3], int dest[3]); | |
// print array to stdout | |
void printArray(int vals[3]); | |
// print edges array | |
void printEdges(int nedges); | |
// translate binary offsets into integer | |
int getVertNum(int vert[3]); | |
// find index of entry in array | |
int contains(int vals[], const int len, int val); | |
// print the verts array | |
void printVerts(apf::MeshEntity**** verts, Sizes sizes); | |
void calcCentroid(apf::Mesh* m, apf::MeshEntity** verts, double centroid[3]); | |
void checkMesh(apf::Mesh* m); | |
void checkMeshFaces(apf::Mesh* m); | |
class FaceCallback : public apf::BuildCallback | |
{ | |
public: | |
apf::Mesh2* m_closure; | |
void call(apf::MeshEntity* e) | |
{ | |
int type = m_closure->getType(e); | |
const char* tname = apf::Mesh::typeName[type]; | |
int dim = apf::Mesh::typeDimension[type]; | |
std::cout << "FaceCallback entity of type " << tname << " (dimension " << dim << ") created" << std::endl; | |
if (dim == 2) { | |
apf::Downward es; | |
m_closure -> getDownward(e, 1, es); | |
std::cout << "face edges = " << es[0] << ", " << es[1] << ", "; | |
std::cout << es[2] << std::endl; | |
std::cout << "face ptr " << e << std::endl; | |
} | |
} | |
}; | |
class RegionCallback : public apf::BuildCallback | |
{ | |
public: | |
apf::Mesh2* m_closure; | |
void call(apf::MeshEntity* e) | |
{ | |
int type = m_closure->getType(e); | |
const char* tname = apf::Mesh::typeName[type]; | |
int dim = apf::Mesh::typeDimension[type]; | |
if (dim == 2) | |
{ | |
apf::Downward down; | |
m_closure -> getDownward(e, 0, down); | |
double centroid[3]; | |
calcCentroid(m_closure, down, centroid); | |
std::cout << "created unexpected triangles with centroid = " << centroid[0]; | |
std::cout << ", " << centroid[1] << ", " << centroid[2] << std::endl; | |
std::cout << "face vertices = " << down[0] << ", " << down[1] << ", "; | |
std::cout << down[2] << std::endl; | |
apf::Downward es; | |
m_closure -> getDownward(e, 1, es); | |
std::cout << "face edges = " << es[0] << ", " << es[1] << ", "; | |
std::cout << es[2] << std::endl; | |
std::cout << "face ptr " << e << std::endl; | |
} else | |
{ | |
std::cout << "RegionCallback entity of type " << tname << " (dimension " << dim << ") created" << std::endl; | |
} | |
} | |
}; | |
// the program creates a cartesian mesh composed to triangles. | |
// The mesh is created by subdividing each rectangle into two triangles | |
// Arguments: | |
// 1: number of rectangles in x direction | |
// 2: number of rectangles in y direction | |
// 3: whether or not to perturb the node locations | |
// | |
// Conventions: | |
// This mesh generator correctly classifies mesh entities onto geometric | |
// entities. The geometric entities are number starting from 0 in the | |
// bottom left corner, going counterclockwise. | |
// | |
int main(int argc, char** argv) | |
{ | |
MPI_Init(&argc,&argv); | |
PCU_Comm_Init(); | |
gmi_register_null(); | |
gmi_model* g = gmi_load(".null"); | |
apf::Mesh2* m = apf::makeEmptyMdsMesh(g, 3, false); | |
/* | |
apf::FieldShape* m_shape = m->getShape(); | |
const char shape_name[] = m_shape->getName(); | |
std::cout << "shape name = " << shape_name << std::endl; | |
*/ | |
if (argc < 3 || argc > 5) | |
{ | |
std::cerr << "Error: wrong number of arguments" << std::endl; | |
return 1; | |
} | |
// Problem 3 | |
std::cout << "Problem 3 output: " << std::endl; | |
int numElx = 0; // number of elements in x direction | |
sscanf(argv[1], "%d", &numElx); | |
int numEly = 0; // number of elements in y direction | |
sscanf(argv[2], "%d", &numEly); | |
int numElz = 0; // number of elements in the z direction | |
sscanf(argv[3], "%d", &numElz); | |
int apply_pert = 0; | |
if (argc == 5) | |
{ | |
sscanf(argv[4], "%d", &apply_pert); | |
} | |
Sizes sizes = {numElx, numEly, numElz}; | |
declareTets(); | |
extractEdges(); | |
extractFaces(); | |
extractRearEdges(); | |
extractRearFaces(); | |
// TODO: fix this | |
long numElx_l = numElx; | |
long numEly_l = numEly; | |
long nvert = (numElx_l+1)*(numEly_l+1); | |
long nedges = numElx_l*(numEly_l+1) + numEly_l*(numElx_l+1) + numElx_l*numEly_l; | |
long nel = numElx_l*numEly_l + 1; | |
std::cout << "expected entity counts: " << std::endl; | |
std::cout << " Vertices: " << nvert << std::endl; | |
std::cout << " Edges: " << nedges << std::endl; | |
std::cout << " Elements: " << nel << std::endl; | |
if (nvert > INT_MAX) | |
{ | |
std::cerr << "Error: number of vertices will overflow 32-bit integer" << std::endl; | |
return 1; | |
} | |
if (nedges > INT_MAX) | |
{ | |
std::cerr << "Error: number of edges will overflow 32-bit integer" << std::endl; | |
return 1; | |
} | |
if (nel > INT_MAX) | |
{ | |
std::cerr << "Error: number of elements will overflow 32-bit integer" << std::endl; | |
return 1; | |
} | |
double xmin = 1.0; | |
double ymin = 1.0; | |
double zmin = 1.0; | |
double xdist = 2; // xmax - xmin | |
double ydist = 2; // ymax - ymin | |
double zdist = 2; | |
double x_spacing = xdist/numElx; // spacing of el | |
double y_spacing = ydist/numEly; | |
double z_spacing = zdist/numElz; | |
double x_0 = xmin; // x coordinate of lower left corner of current element | |
double y_0 = ymin ; // y coordinate of lower left corner of current element | |
double z_0 = zmin; | |
/* nominal locations of current point */ | |
double x_i = x_0; | |
double y_i = y_0; | |
double z_i = z_0; | |
/* possibly perturbed locations of current point */ | |
double x_inner = x_i; | |
double y_inner = y_i; | |
double z_inner = z_i; | |
double pert_fac = 10*M_PI; | |
double pert_mag = 0.1; | |
std::cout << "SIZE_MAX = " << SIZE_MAX << std::endl; | |
std::cout << "about to allocate memory" << std::endl; | |
apf::MeshEntity**** vertices = (apf::MeshEntity****) calloc(numElx+1, sizeof(apf::MeshEntity***)); | |
for (int i = 0; i < (numElx+1); ++i) | |
{ | |
vertices[i] = (apf::MeshEntity***) calloc(numEly+1, sizeof(apf::MeshEntity**)); | |
for (int j = 0; j < (numEly+1); ++j) | |
{ | |
vertices[i][j] = (apf::MeshEntity**) calloc(numElz+1, sizeof(apf::MeshEntity*)); | |
} | |
} | |
// apf::MeshEntity* vertices[numElx+1][numEly+1]; // hold pointers to all vertices | |
std::cout << "finished allocating memory" << std::endl; | |
apf::Vector3 coords_i(0.0,0.0,0.0); // hold coordinates of each point | |
Geom geo; | |
apf::ModelEntity* model_entity; // the model entity itself | |
std::cout << "Creating " << numElx << " by " << numEly << "by " << numElz; | |
std::cout << " mesh" << std::endl; | |
// create all vertices | |
for (int k = 0; k < (numElz+1); ++k) | |
{ | |
for (int j = 0; j < (numEly+1); ++j) // loop up columns (bottom to top) | |
{ | |
for (int i = 0; i < (numElx+1); ++i) // loop over rows (left to right) | |
{ | |
std::cout << "creating point at x = " << x_inner << " , y = " << y_inner << " , z = " << z_inner << std::endl; | |
coords_i[0] = x_inner; | |
coords_i[1] = y_inner; | |
coords_i[2] = z_inner; | |
geo = getVertClassification(i, j, k, sizes); | |
std::cout << "model_dim = " << geo.model_dim << std::endl; | |
std::cout << "model_tag = " << geo.model_tag << std::endl; | |
model_entity = m->findModelEntity(geo.model_dim, geo.model_tag); | |
std::cout << "model entity = " << model_entity << std::endl; | |
vertices[i][j][k] = m->createVert(model_entity); | |
std::cout << "vertex = " << vertices[i][j][k] << std::endl; | |
m->setPoint(vertices[i][j][k], 0, coords_i); | |
x_inner = x_inner + x_spacing + pert_mag*sin(apply_pert*pert_fac*x_inner); | |
y_inner = y_i + pert_mag*sin(apply_pert*pert_fac*x_inner); | |
z_inner = z_i + pert_mag*sin(apply_pert*pert_fac*y_inner); | |
} | |
y_i = y_i + y_spacing; // increment y_i | |
x_i = x_0; // reset x_i to beginning of row | |
y_inner = y_i;// + pert_mag*sin(apply_pert*pert_fac*y_i); | |
x_inner = x_i; // + pert_mag*sin(apply_pert*pert_fac*x_i); | |
z_inner = z_i; | |
} | |
z_i = z_i + z_spacing; | |
x_i = x_0; // reset to beginning of row | |
y_i = y_0; // reset to beginning of row | |
y_inner = y_i; | |
x_inner = x_i; | |
z_inner = z_i; | |
} | |
printVerts(vertices, sizes); | |
RegionCallback cb; | |
cb.m_closure = m; | |
// classify all MeshEntities on geometric face | |
int model_dim = 3; | |
int model_tag = 0; | |
model_entity = m->findModelEntity(model_dim, model_tag); | |
VertIdx start; | |
apf::MeshEntity* vertices_i[4]; // hold vertices for a particular element | |
// build element from verticies | |
for (int k = 0; k < numElz; ++k) | |
{ | |
for (int j = 0; j < numEly; ++j) | |
{ | |
for (int i = 0; i < numElx; ++i) | |
{ | |
std::cout << "\ncreating element " << i << ", " << j << ", " << k << std::endl; | |
// int el_num = i + numElx*j; | |
// std::cout << "creating element i = " << i << " , j = " << j << std::endl; | |
start.i = i; start.j = j; start.k = k; | |
identifyEdges(start); | |
createEdges(m, sizes, start, vertices); | |
identifyFaces(start); | |
createFaces(m, sizes, start, vertices); | |
for (int v = 0; v < 6; ++v) | |
{ | |
std::cout << "\ncreating tet " << v << std::endl; | |
getTetVerts(start, tets[v], vertices, vertices_i); | |
apf::buildElement(m, model_entity, apf::Mesh::TET, vertices_i, &cb); | |
} | |
} | |
} | |
} | |
// build, verify mesh | |
/* | |
std::cout << "deriving model" << std::endl; | |
apf::deriveMdsModel(m); | |
std::cout << "finished deriving model" << std::endl; | |
*/ | |
m->acceptChanges(); | |
std::cout << "accepted changes" << std::endl; | |
checkMeshFaces(m); | |
// THIS IS WHERE IT FAILS | |
m->verify(); | |
std::cout << "verified" << std::endl; | |
// for quadratic meshes | |
// apf::FieldShape* linear2 = apf::getSerendipity(); | |
// apf::FieldShape* linear2 = apf::getSBP3Shape(1); | |
apf::FieldShape* linear2 = apf::getLagrange(1); | |
apf::changeMeshShape(m, linear2, true); // last argument should be true for second order | |
std::cout << "changed mesh shape" << std::endl; | |
apf::FieldShape* m_shape = m->getShape(); | |
// const char shape_name[] = m_shape->getName(); | |
std::cout << "mesh shape name = " << m_shape->getName() << std::endl; | |
// apf::EntityShape* m_entity_quad = m_shape->getEntityShape(apf::Mesh::QUAD); | |
/* | |
// get values | |
apf::Vector3 xi(-0.25, -0.25, 0); | |
apf::NewArray<double> vals; | |
m_entity_quad->getValues(xi, vals); | |
std::cout << "values at (-0.25. -0.25, 0) = " << vals[0] << " , " << vals[1] << " , " << vals[2] << " , " << vals[3] << std::endl; | |
// get gradients | |
apf::NewArray<apf::Vector3> vals2; | |
m_entity_quad->getLocalGradients(xi, vals2); | |
std::cout << "gradients at (-0.25. -0.25, 0) = " << vals2[0] << " , " << vals2[1] << " , " << vals2[2] << " , " << vals2[3] << std::endl; | |
*/ | |
// count nodes | |
// int numNodes = m_entity_quad->countNodes(); | |
// std::cout << "number of nodes = " << numNodes << std::endl; | |
/* | |
// check number of nodes for each type of entity | |
bool nodecnt[4]; | |
nodecnt[0] = m_shape->countNodesOn(apf::Mesh::VERTEX); | |
nodecnt[1] = m_shape->countNodesOn(apf::Mesh::EDGE); | |
nodecnt[2] = m_shape->countNodesOn(apf::Mesh::TRIANGLE); | |
nodecnt[3] = m_shape->countNodesOn(apf::Mesh::TET); | |
// nodecnt[3] = m_shape->countNodesOn(apf::Mesh::QUAD); | |
std::cout << "nodecounts: " << nodecnt[0] << " , " << nodecnt[1] << " , " << nodecnt[2] << " , " << nodecnt[3] << std::endl; | |
*/ | |
// write output and clean up | |
apf::writeVtkFiles("outTet", m); | |
m->writeNative("./meshfiles/abc.smb"); | |
/* | |
apf::MeshIterator* it = m->begin(2); | |
apf::MeshEntity* e = m->iterate(it); | |
apf::MeshElement* e_el = apf::createMeshElement(m, e); | |
int numI = apf::countIntPoints(e_el, 5); | |
std::cout << numI << " integration points required" << std::endl; | |
*/ | |
m->destroyNative(); | |
apf::destroyMesh(m); | |
PCU_Comm_Free(); | |
MPI_Finalize(); | |
} | |
// check that the number of downward and upward adjacencies is correct | |
void checkMesh(apf::Mesh* m) | |
{ | |
// check verts -> edges | |
apf::MeshIterator* it = m->begin(0); | |
apf::MeshEntity* e; | |
// apf::Up ups; // upward adjacencies | |
apf::Adjacent adj; // multi level upward adjacencies | |
apf::Downward down; | |
int cnt = 0; // current entity number | |
int cnt_i = 0; // number of adjacent entities | |
while ( (e = m->iterate(it)) ) | |
{ | |
// check verts -> edges | |
cnt_i = m->countUpward(e); | |
if (cnt_i < 2) | |
{ | |
std::cerr << "vertex " << cnt << " has too few edges" << std::endl; | |
} else | |
{ | |
// std::cout << "vertex -> edge pass " << std::endl; | |
} | |
// check vert -> face | |
m->getAdjacent(e, 2, adj); | |
if (adj.size() > 6) | |
{ | |
std::cerr << "vertex " << cnt << " has too many faces" << std::endl; | |
} else | |
{ | |
// std::cout << "vertex -> face pass " << std::endl; | |
} | |
++cnt; | |
} | |
it = m->begin(1); | |
cnt = 0; | |
while ( (e = m->iterate(it)) ) | |
{ | |
// check edge -> verts | |
cnt_i = m->getDownward(e, 0, down); | |
if ( cnt_i != 2) | |
{ | |
std::cerr << "edge " << cnt << " has too few verts" << std::endl; | |
} else | |
{ | |
// std::cout << "edge -> vert pass" << std::endl; | |
} | |
// check edge -> face | |
m->getAdjacent(e, 2, adj); | |
if (adj.size() > 2) | |
{ | |
std::cerr << "edge " << cnt << " has too many faces" << std::endl; | |
} else | |
{ | |
// std::cout << "edge -> face pass" << std::endl; | |
} | |
++cnt; | |
} | |
it = m->begin(2); | |
cnt = 0; | |
while ( (e = m->iterate(it)) ) | |
{ | |
// check face -> edges | |
cnt_i = m->getDownward(e, 1, down); | |
if ( cnt_i != 3) | |
{ | |
std::cerr << "face " << cnt << " has incorrect number of edges" << std::endl; | |
} else | |
{ | |
// std::cout << "face -> edge pass" << std::endl; | |
} | |
// check face -> verts | |
cnt_i = m->getDownward(e, 0, down); | |
if (cnt_i != 3) | |
{ | |
std::cerr << "face " << cnt << " has incorrect number of vertices" << std::endl; | |
} else | |
{ | |
// std::cout << "face -> vert pass" << std::endl; | |
} | |
++cnt; | |
} | |
} // end function | |
void calcCentroid(apf::Mesh* m, apf::MeshEntity* e, double centroid[3]) | |
{ | |
apf::Downward verts; | |
m->getDownward(e, 0, verts); | |
calcCentroid(m, verts, centroid); | |
} | |
void calcCentroid(apf::Mesh* m, apf::MeshEntity** verts, double centroid[3]) | |
{ | |
apf::Vector3 p1; | |
apf::Vector3 p2; | |
apf::Vector3 p3; | |
m->getPoint(verts[0], 0, p1); | |
m->getPoint(verts[1], 0, p2); | |
m->getPoint(verts[2], 0, p3); | |
for (int i =0; i < 3; ++i) | |
{ | |
centroid[i] = (p1[i] + p2[i] + p3[i])/3; | |
} | |
} | |
void checkMeshFaces(apf::Mesh* m) | |
{ | |
apf::MeshEntity* e; | |
apf::Up up; | |
apf::ModelEntity* me; | |
int model_dim; | |
int model_tag; | |
double centroid[3]; | |
int facenum = 0; | |
apf::MeshIterator* it = m->begin(2); | |
while ( (e = m->iterate(it)) ) | |
{ | |
me = m->toModel(e); | |
model_dim = m->getModelType(me); | |
model_tag = m->getModelTag(me); | |
m->getUp(e, up); | |
if (model_dim == 2) // equal order classification | |
{ | |
calcCentroid(m, e, centroid); | |
if (up.n != 1) | |
{ | |
std::cout << "face " << facenum << " has " << up.n; | |
std::cout << " adjacent regions, expected 1"; | |
std::cout << ", centroid = " << centroid[0] << ", " << centroid[1]; | |
std::cout << ", " << centroid[2] << std::endl; | |
std::cout << "model_dim = " << model_dim << ", model_tag = " << model_tag << std::endl; | |
std::cout << "model entity = " << me << std::endl; | |
} | |
} else if (model_dim == 3) | |
{ | |
if (up.n != 2) | |
{ | |
std::cout << "face " << facenum << " has " << up.n; | |
std::cout << " adjacent regions, expected 2"; | |
std::cout << ", centroid = " << centroid[0] << ", " << centroid[1]; | |
std::cout << ", " << centroid[2] << std::endl; | |
std::cout << "model_dim = " << model_dim << ", model_tag = " << model_tag << std::endl; | |
std::cout << "model entity = " << me << std::endl; | |
} | |
} | |
++facenum; | |
} | |
} | |
void declareTets() | |
{ | |
int vals[] = {0, 0, 0}; copyArray(vals, tets[0][0]); | |
int vals2[] = {1, 0, 0}; copyArray(vals2, tets[0][1]); | |
int vals3[] = {1, 1, 1}; copyArray(vals3, tets[0][2]); | |
int vals4[] = {1, 0, 1}; copyArray(vals4, tets[0][3]); | |
int vals5[] = {1, 1, 1}; copyArray(vals5, tets[1][0]); | |
int vals6[] = {0, 0, 0}; copyArray(vals6, tets[1][1]); | |
int vals7[] = {1, 0, 1}; copyArray(vals7, tets[1][2]); | |
int vals8[] = {0, 0, 1}; copyArray(vals8, tets[1][3]); | |
int vals9[] = {0, 0, 0}; copyArray(vals9, tets[2][0]); | |
int vals10[] = {1, 0, 0}; copyArray(vals10, tets[2][1]); | |
int vals11[] = {1, 1, 0}; copyArray(vals11, tets[2][2]); | |
int vals12[] = {1, 1, 1}; copyArray(vals12, tets[2][3]); | |
int vals13[] = {0, 1, 0}; copyArray(vals13, tets[3][0]); | |
int vals14[] = {0, 0, 0}; copyArray(vals14, tets[3][1]); | |
int vals15[] = {1, 1, 0}; copyArray(vals15, tets[3][2]); | |
int vals16[] = {1, 1, 1}; copyArray(vals16, tets[3][3]); | |
int vals17[] = {0, 1, 0}; copyArray(vals17, tets[4][0]); | |
int vals18[] = {0, 0, 0}; copyArray(vals18, tets[4][1]); | |
int vals19[] = {1, 1, 1}; copyArray(vals19, tets[4][2]); | |
int vals20[] = {0, 1, 1}; copyArray(vals20, tets[4][3]); | |
int vals21[] = {0, 0, 0}; copyArray(vals21, tets[5][0]); | |
int vals22[] = {1, 1, 1}; copyArray(vals22, tets[5][1]); | |
int vals23[] = {0, 1, 1}; copyArray(vals23, tets[5][2]); | |
int vals24[] = {0, 0, 1}; copyArray(vals24, tets[5][3]); | |
} | |
Geom getVertClassification(VertIdx v, Sizes sizes) | |
{ | |
return getVertClassification(v.i, v.j, v.k, sizes); | |
} | |
Geom getVertClassification(int i, int j, int k, Sizes sizes) | |
{ | |
int model_dim; | |
int model_tag; | |
int numElx = sizes.numElx; | |
int numEly = sizes.numEly; | |
int numElz = sizes.numElz; | |
// figure out what model entity to classify this vertex on | |
/* corners in x-y plane */ | |
if ( i == 0 && j == 0 && k == 0 ) | |
{ | |
model_dim = 0; | |
model_tag = 0; | |
} else if ( i == (numElx) && j == 0 && k == 0 ) | |
{ | |
model_dim = 0; | |
model_tag = 1; | |
} else if ( i == (numElx) && j == (numEly) && k == 0) | |
{ | |
model_dim = 0; | |
model_tag = 2; | |
} else if ( i == 0 && j == (numEly) && k == 0 ) | |
{ | |
model_dim = 0; | |
model_tag = 3; | |
/* corners in z = numElz plane */ | |
} else if ( i == 0 && j == 0 && k == numElz ) // corners in z=numElz plane | |
{ | |
model_dim = 0; | |
model_tag = 4; | |
} else if ( i == (numElx) && j == 0 && k == numElz ) | |
{ | |
model_dim = 0; | |
model_tag = 5; | |
} else if ( i == (numElx) && j == (numEly) && k == numElz) | |
{ | |
model_dim = 0; | |
model_tag = 6; | |
} else if ( i == 0 && j == (numEly) && k == numElz ) | |
{ | |
model_dim = 0; | |
model_tag = 7; | |
/* domain edges in x-y plane */ | |
} else if ( j == 0 && k == 0) // bottom row | |
{ | |
model_dim = 1; | |
model_tag = 0; | |
} else if ( i == (numElx) && k == 0) // right column | |
{ | |
model_dim = 1; | |
model_tag = 1; | |
} else if ( j == (numEly) && k == 0) // top row | |
{ | |
model_dim = 1; | |
model_tag = 2; | |
} else if ( i == 0 && k == 0 ) // left column | |
{ | |
model_dim = 1; | |
model_tag = 3; | |
/* domain edges in z = numElz plane */ | |
/* counterclockwise from the origin */ | |
} else if ( j == 0 && k == numElz) | |
{ | |
model_dim = 1; | |
model_tag = 4; | |
} else if ( i == (numElx) && k == numElz) | |
{ | |
model_dim = 1; | |
model_tag = 5; | |
} else if ( j == (numEly) && k == numElz) | |
{ | |
model_dim = 1; | |
model_tag = 6; | |
} else if ( i == 0 && k == numElz ) | |
{ | |
model_dim = 1; | |
model_tag = 7; | |
/* domain edges in parallel to z axis */ | |
/* counterclockwise starting at the origin */ | |
} else if ( i == 0 && j == 0) | |
{ | |
model_dim = 1; | |
model_tag = 8; | |
} else if ( i == numElx && j == 0) | |
{ | |
model_dim = 1; | |
model_tag = 9; | |
} else if ( i == numElx && j == numEly) | |
{ | |
model_dim = 1; | |
model_tag = 10; | |
} else if ( i == 0 && j == numEly ) | |
{ | |
model_dim = 1; | |
model_tag = 11; | |
/* domain faces */ | |
} else if ( k == 0 ) // bottom face (x-y plane) | |
{ | |
model_dim = 2; | |
model_tag = 0; | |
} else if ( j == 0) // x-z plane | |
{ | |
model_dim = 2; | |
model_tag = 1; | |
} else if ( i == numElx) // parallel to y-z plane | |
{ | |
model_dim = 2; | |
model_tag = 2; | |
} else if ( j == numEly) // parallel to x-z plane | |
{ | |
model_dim = 2; | |
model_tag = 3; | |
} else if ( i == 0) // y-z plane | |
{ | |
model_dim = 2; | |
model_tag = 4; | |
} else if ( k == numElz) // top face (parallel to x-y plane) | |
{ | |
model_dim = 2; | |
model_tag = 5; | |
} else // classify on face | |
{ | |
model_dim = 3; | |
model_tag = 0; | |
} | |
Geom geo = {model_tag, model_dim}; | |
return geo; | |
} | |
// determine the unique set of edges as defined by their vertices | |
void extractEdges() | |
{ | |
std::cout << "extracting edges" << std::endl; | |
// algorithm: loop over vertices in tet, form edge between current vertex and | |
// all previous vertices, check if edge is already in list | |
// add it if not | |
for (int i=0; i < NFACES; ++i) | |
{ | |
for (int j=0; j < 2; ++j) | |
{ | |
for (int k = 0; k < 3; ++k) | |
{ | |
edges[i][j][k] = 0; | |
} | |
} | |
} | |
int nedges=0; | |
for (int i=0; i < NTETS; ++i) | |
{ | |
for (int j=0; j < 4; ++j) | |
{ | |
for (int k=(j+1); k < 4; ++ k) | |
{ | |
// check against list of existing edges | |
bool already_added = checkEdges(tets[i][j], tets[i][k], nedges); | |
if (!already_added) | |
{ | |
if (nedges >= NEDGES) | |
std::cerr << " Warning: too many edges detected" << std::endl; | |
copyArray(tets[i][j], edges[nedges][0]); | |
copyArray(tets[i][k], edges[nedges][1]); | |
++nedges; | |
} | |
} | |
} | |
} | |
if (nedges != NEDGES) | |
{ | |
std::cerr << "Warning: wrong number of edges detected" << std::endl; | |
throw nedges; | |
} else | |
{ | |
std::cout << "Correct number of edges detected" << std::endl; | |
} | |
} | |
// check if the edges list already contains the edge defined by | |
// these two verts | |
bool checkEdges(int vert1[3], int vert2[3], int nedges) | |
{ | |
bool found1; | |
bool found2; | |
for (int i=0; i < nedges; ++i) | |
{ | |
// check if edges[i] contains vert1 | |
found1 = contains(edges[i], 2, vert1); | |
found2 = contains(edges[i], 2, vert2); | |
if (found1 && found2) | |
return true; | |
} | |
return false; | |
} | |
// get the index in the edge array containing the specified edge | |
int findEdge(int edge[2][3]) | |
{ | |
int idx = -1; | |
bool found1; | |
bool found2; | |
for (int i=0; i < NEDGES; ++i) | |
{ | |
found1 = contains(edges[i], 2, edge[0]); | |
found2 = contains(edges[i], 2, edge[1]); | |
if (found1 && found2) | |
{ | |
idx = i; | |
break; | |
} | |
} | |
return idx; | |
} | |
bool checkFace(int vert1[3], int vert2[3], int vert3[3], int nfaces) | |
{ | |
bool found1; | |
bool found2; | |
bool found3; | |
for (int i=0; i < NFACES; ++i) | |
{ | |
found1 = contains(faces[i], 3, vert1); | |
found2 = contains(faces[i], 3, vert2); | |
found3 = contains(faces[i], 3, vert3); | |
if (found1 && found2 && found3) | |
return true; | |
} | |
return false; | |
} | |
int findFace(int face[3][3]) | |
{ | |
int idx = -1; | |
bool found1; | |
bool found2; | |
bool found3; | |
for (int i=0; i < NFACES; ++i) | |
{ | |
found1 = contains(faces[i], 3, face[0]); | |
found2 = contains(faces[i], 3, face[1]); | |
found3 = contains(faces[i], 3, face[2]); | |
if (found1 && found2 && found3) | |
{ | |
idx = i; | |
break; | |
} | |
} | |
return idx; | |
} | |
// check if the specified entry in th list contains a given | |
// vertex (in either position) | |
bool contains(int list_entry[][3], const int dim1, int vert1[3]) | |
{ | |
bool matched; | |
for (int i = 0; i < dim1; ++i) | |
{ | |
matched = true; | |
for (int j=0; j < 3; ++j) | |
{ | |
matched = matched && (vert1[j] == list_entry[i][j]); | |
} | |
if (matched) | |
return matched; | |
} | |
return matched; | |
} | |
// get the list of triangles | |
void extractFaces() | |
{ | |
std::cout << "extracting faces" << std::endl; | |
// algorithm: loop over vertices in tet, form face between current vertex and | |
// all sets of 2 future vertices, check if face is already in list | |
// add it if not | |
for (int i=0; i < NFACES; ++i) | |
{ | |
for (int j=0; j < 3; ++j) | |
{ | |
for (int k = 0; k < 3; ++k) | |
{ | |
faces[i][j][k] = 0; | |
} | |
} | |
} | |
bool foundface; | |
int nfaces = 0; | |
for (int i=0; i < NTETS; ++i) | |
{ | |
std::cout << "\nconsidering tet " << i << std::endl; | |
for (int v1=0; v1 < 4; ++v1) | |
{ | |
for (int v2=(v1+1); v2 < 4; ++v2) | |
{ | |
for (int v3=(v2+1); v3 < 4; ++v3) | |
{ | |
foundface = checkFace(tets[i][v1], tets[i][v2], tets[i][v3], nfaces); | |
if (!foundface) | |
{ | |
if (nfaces >= NFACES) | |
std::cerr << "Warning: too many faces detected" << std::endl; | |
std::cout << "adding face with tet v1 = " << v1 << ", v2 = " << v2 << ", v3 = " << v3 << std::endl; | |
std::cout << "cube verts = " << getVertNum(tets[i][v1]) << ", " << getVertNum(tets[i][v2]) << ", " << getVertNum(tets[i][v3]) << std::endl; | |
copyArray(tets[i][v1], faces[nfaces][0]); | |
copyArray(tets[i][v2], faces[nfaces][1]); | |
copyArray(tets[i][v3], faces[nfaces][2]); | |
++nfaces; | |
} | |
} | |
} | |
} | |
} | |
if ( nfaces != NFACES) | |
{ | |
std::cerr << "Warning: wrong number of faces detected" << std::endl; | |
throw nfaces; | |
} else | |
{ | |
std::cout << "Correct number of faces detected" << std::endl; | |
} | |
} | |
void extractRearEdges() | |
{ | |
int rear_edges[NREAREDGES][2][3] ={ | |
// edge on axes of the cube | |
{ {0, 0, 0}, {1, 0, 0} }, | |
{ {0, 0, 0}, {0, 1, 0} }, | |
{ {0, 0, 0}, {0, 0, 1} }, | |
// j = 0 edges | |
{ {0, 0, 0}, {1, 0, 1} }, | |
{ {1, 0, 0}, {1, 0, 1} }, | |
{ {0, 0, 1}, {1, 0, 1} }, | |
// i = 0 edges | |
{ {0, 0, 0}, {0, 1, 1} }, | |
{ {0, 1, 0}, {0, 1, 1} }, | |
{ {0, 0, 1}, {0, 1, 1} }, | |
// k = 0 edges | |
{ {0, 0, 0}, {1, 1, 0} }, | |
{ {1, 0, 0}, {1, 1, 0} }, | |
{ {0, 1, 0}, {1, 1, 0} }, | |
}; | |
for (int i = 0; i < NREAREDGES; ++i) | |
{ | |
rear_edge_idx[i] = findEdge(rear_edges[i]); | |
create_edge[i] = false; | |
if (rear_edge_idx[i] < 0) | |
{ | |
std::cerr << "rear edge " << i << " not found" << std::endl; | |
throw i; | |
} | |
std::cout << "rear edge " << i << " idx = " << rear_edge_idx[i] << std::endl; | |
} | |
} | |
// set the values in create_edge | |
// start should be the indices of the vertex at the origin of the cube | |
void identifyEdges(VertIdx start) | |
{ | |
for (int i=0; i < NREAREDGES; ++i) | |
{ | |
create_edge[i] = false; | |
} | |
const int i = start.i; | |
const int j = start.j; | |
const int k = start.k; | |
// select which edges to create | |
if (j == 0 && k == 0) | |
create_edge[0] = true; | |
if (i == 0 && k == 0) | |
create_edge[1] = true; | |
if ( i == 0 && j == 0) | |
create_edge[2] = true; | |
if ( j == 0 ) | |
{ | |
create_edge[3] = true; | |
create_edge[4] = true; | |
create_edge[5] = true; | |
} | |
if ( i == 0) | |
{ | |
create_edge[6] = true; | |
create_edge[7] = true; | |
create_edge[8] = true; | |
} | |
if ( k == 0) | |
{ | |
create_edge[9] = true; | |
create_edge[10] = true; | |
create_edge[11] = true; | |
} | |
} | |
void extractRearFaces() | |
{ | |
int rear_faces[6][3][3] = { | |
// face 2 | |
{ {0, 0, 0}, {1, 0, 1}, {0, 0, 1} }, | |
{ {0, 0, 0}, {1, 0, 0}, {1, 0, 1} }, | |
// face 5 | |
{ {0, 0, 0}, {0, 1, 0}, {0, 1, 1} }, | |
{ {0, 0, 0}, {0, 1, 1}, {0, 0, 1} }, | |
// face 1 | |
{ {0, 0, 0}, {1, 1, 0}, {1, 0, 0} }, | |
{ {0, 0, 0}, {1, 1, 0}, {0, 1, 0} }, | |
}; | |
for (int i = 0; i < 6; ++i) | |
{ | |
rear_face_idx[i] = findFace(rear_faces[i]); | |
create_face[i] = false; | |
if (rear_face_idx[i] < 0) | |
{ | |
std::cerr << "rear face " << i << " not found" << std::endl; | |
throw i; | |
} | |
std::cout << "rear face " << i << " idx = " << rear_face_idx[i] << std::endl; | |
} | |
} | |
void identifyFaces(VertIdx start) | |
{ | |
for (int i=0; i < 6; ++i) | |
{ | |
create_face[i] = false; | |
} | |
// select which faces to create | |
if (start.j == 0) | |
{ | |
create_face[0] = true; | |
create_face[1] = true; | |
} | |
if (start.i == 0) | |
{ | |
create_face[2] = true; | |
create_face[3] = true; | |
} | |
if (start.k == 0) | |
{ | |
create_face[4] = true; | |
create_face[5] = true; | |
} | |
} | |
// create the needed edges on an element | |
// TODO: need Mesh*, need sizes | |
void createEdges(apf::Mesh2* m, Sizes sizes, VertIdx start, apf::MeshEntity**** verts) | |
{ | |
std::cout << "\ncreating edges" << std::endl; | |
std::cout << "start idx = " << start.i << ", " << start.j << ", " << start.k << std::endl; | |
int idx; | |
VertIdx vertidx; | |
apf::MeshEntity* verts_i[2]; | |
Geom g_class[2]; // geometric classification of the vertices | |
apf::ModelEntity* model_entity; | |
for (int i = 0; i < NEDGES; ++i) | |
{ | |
std::cout << "\nconsidering edge " << i << std::endl; | |
idx = contains(rear_edge_idx, NREAREDGES, i); | |
if (idx > 0) // if found | |
{ | |
std::cout << "this is a rear edge" << std::endl; | |
if (!create_edge[idx]) | |
{ | |
std::cout << "skipping this edge" << std::endl; | |
continue; | |
} | |
} | |
std::cout << "creating edge" << std::endl; | |
// if we get here, we should create the edge | |
for (int j=0; j < 2; ++j) | |
{ | |
vertidx = add(start, edges[i][j]); | |
std::cout << "vert idx = " << vertidx.i << ", " << vertidx.j << ", " << vertidx.k << std::endl; | |
verts_i[j] = getVert(vertidx, verts); | |
std::cout << "vert " << j << " = " << verts_i[j] << std::endl; | |
g_class[j] = getVertClassification(vertidx, sizes); | |
} | |
model_entity = getModelEntity(m, g_class, 2); | |
createEdge(m, verts_i, model_entity); | |
} | |
} | |
void createEdge(apf::Mesh2* m, apf::MeshEntity* edge_verts[2], apf::ModelEntity* model_entity) | |
{ | |
std::cerr << "manually creating edge with verts " << edge_verts[0] | |
<< " " << edge_verts[1] << std::endl; | |
apf::MeshEntity* existing = apf::findUpward(m, apf::Mesh::EDGE, edge_verts); | |
if (existing) { | |
std::cerr << "createEdge error: edge already exists!\n"; | |
abort(); | |
} | |
apf::MeshEntity* e = m->createEntity(apf::Mesh::EDGE, model_entity, edge_verts); | |
std::cerr << "created edge was " << e << std::endl; | |
} | |
void createFaces(apf::Mesh2* m, Sizes sizes, VertIdx start, apf::MeshEntity**** verts) | |
{ | |
std::cout << "\ncreating faces" << std::endl; | |
int idx; | |
VertIdx vertidx; | |
apf::MeshEntity* verts_i[3]; | |
Geom g_class[3]; // geometric classification of the vertices | |
apf::ModelEntity* model_entity; | |
for (int i = 0; i < NFACES; ++i) | |
{ | |
std::cout << "\nconsidering face " << i << std::endl; | |
idx = contains(rear_face_idx, 6, i); | |
if (idx > 0) // if found | |
{ | |
std::cout << "face is a rear face" << std::endl; | |
if (!create_face[idx]) | |
{ | |
std::cout << "not creating face" << std::endl; | |
continue; | |
} | |
} | |
std::cout << "creating face " << std::endl; | |
// if we get here, we should create the face | |
for (int j=0; j < 3; ++j) | |
{ | |
vertidx = add(start, faces[i][j]); | |
std::cout << "vert idx = " << vertidx.i << ", " << vertidx.j << ", " << vertidx.k << std::endl; | |
verts_i[j] = getVert(vertidx, verts); | |
g_class[j] = getVertClassification(vertidx, sizes); | |
std::cout << "vert " << j << " = " << verts_i[j] << std::endl; | |
} | |
std::cout << "finished getting geometric classification" << std::endl; | |
model_entity = getModelEntity(m, g_class, 3); | |
std::cout << "model_entity = " << model_entity << std::endl; | |
std::cout << "creating face" << std::endl; | |
createFace(m, verts_i, model_entity); | |
std::cout << "finished creating face" << std::endl; | |
} | |
} | |
void createFace(apf::Mesh2* m, apf::MeshEntity* face_verts[3], apf::ModelEntity* model_entity) | |
{ | |
double centroid[3]; | |
calcCentroid(m, face_verts, centroid); | |
std::cout << "face_verts = " << face_verts[0] << ", " << face_verts[1]; | |
std::cout << ", " << face_verts[2] << std::endl; | |
std::cout << "model entity = " << model_entity << std::endl; | |
std::cout << "centroid = " << centroid[0] << ", " << centroid[1] << ", "; | |
std::cout << centroid[2] << std::endl; | |
apf::MeshEntity* e; | |
FaceCallback cb; | |
cb.m_closure = m; | |
e = apf::buildElement(m, model_entity, apf::Mesh::TRIANGLE, face_verts, &cb); | |
model_entity = m->toModel(e); | |
std::cout << "after creation, model_entity = " << model_entity << std::endl; | |
} | |
// get the ModelEntity that the edge defind by g1 and g2 should be classified | |
// on | |
apf::ModelEntity* getModelEntity(apf::Mesh* m, Geom g_class[], const int ng) | |
{ | |
int model_dim; | |
int model_tag; | |
int max_dim = 0; | |
int min_tag = INT_MAX; | |
int n_max_dim = 0; | |
// find the maximum dimension | |
for (int i=0; i < ng; ++i) | |
{ | |
model_dim = g_class[i].model_dim; | |
if (model_dim > max_dim) | |
{ | |
max_dim = model_dim; | |
n_max_dim = 1; | |
} else if (model_dim == max_dim) | |
{ | |
++n_max_dim; | |
} | |
} | |
// now find the minimum tag on that dimension | |
for (int i=0; i < ng; ++i) | |
{ | |
if (g_class[i].model_dim == max_dim) | |
{ | |
model_tag = g_class[i].model_tag; | |
if (model_tag < min_tag) | |
min_tag = model_tag; | |
} | |
} | |
std::cout << "model_dim = " << max_dim << std::endl; | |
std::cout << "model_tag = " << min_tag << std::endl; | |
// max_dim and min_tag now fully describe the geometric entity | |
apf::ModelEntity* me = m->findModelEntity(max_dim, min_tag); | |
std::cout << "model entity = " << me << std::endl; | |
return me; | |
} | |
// get a vert from the array of all vertices | |
apf::MeshEntity* getVert(VertIdx pos, apf::MeshEntity**** verts) | |
{ | |
apf::MeshEntity* vert = verts[pos.i][pos.j][pos.k]; | |
return vert; | |
} | |
void getTetVerts(VertIdx start, int tet[4][3], apf::MeshEntity**** verts_all, apf::MeshEntity* verts[4]) | |
{ | |
VertIdx pos; | |
for (int i=0; i < 4; ++i) | |
{ | |
pos = add(start, tet[i]); | |
std::cout << "tet vert " << i << " idx = " << pos.i << ", " << pos.j << ", " << pos.k << std::endl; | |
verts[i] = getVert(pos, verts_all); | |
} | |
} | |
void copyArray(int src[3], int dest[3]) | |
{ | |
for (int i = 0; i < 3; ++ i) | |
dest[i] = src[i]; | |
} | |
void printArray(int vals[3]) | |
{ | |
std::cout << vals[0] << ", " << vals[1] << ", " << vals[2]; | |
} | |
void printEdges(int nedges) | |
{ | |
std::cout << "edges = " << std::endl; | |
for (int i=0; i < nedges; ++i) | |
{ | |
std::cout << " edge " << i << ": v1 = " << getVertNum(edges[i][0]); | |
std::cout << ", v2 = " << getVertNum(edges[i][1]); | |
std::cout << std::endl; | |
} | |
} | |
int getVertNum(int vert[3]) | |
{ | |
return vert[0] + 2*vert[1] + 4*vert[2]; | |
} | |
int contains(int vals[], const int len, int val) | |
{ | |
int idx = -1; | |
for (int i = 0; i < len; ++i) | |
{ | |
if (vals[i] == val) | |
{ | |
idx = i; | |
break; | |
} | |
} | |
return idx; | |
} | |
VertIdx add(const VertIdx v1, const VertIdx v2) | |
{ | |
VertIdx result = {v1.i + v2.i, v1.j + v2.j, v1.k + v2.k}; | |
return result; | |
} | |
VertIdx add(const VertIdx v1, const int arr[3]) | |
{ | |
VertIdx result = {v1.i + arr[0], v1.j + arr[1], + v1.k + arr[2]}; | |
return result; | |
} | |
void printVerts(apf::MeshEntity**** verts, Sizes sizes) | |
{ | |
std::cout << "verts: " << std::endl; | |
for (int i=0; i < (sizes.numElx+1); ++i) | |
for (int j=0; j < (sizes.numEly+1); ++j) | |
for(int k=0; k < (sizes.numElz+1); ++k) | |
{ | |
std::cout << "vert[" << i << "][" << j << "][" << k << "] = " << verts[i][j][k] << std::endl; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment