Files
mfem/mesh/mesquite.cpp
T
2020-03-09 15:36:41 -07:00

1190 lines
35 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 "mesquite.hpp"
#ifdef MFEM_USE_MESQUITE
#include "../fem/fem.hpp"
#include <iostream>
namespace mfem
{
using namespace std;
MesquiteMesh::MeshTags::TagData::~TagData()
{
if (elementData)
{
free(elementData);
}
if (vertexData)
{
free(vertexData);
}
if (defaultValue)
{
free(defaultValue);
}
}
void MesquiteMesh::MeshTags::clear()
{
for (std::vector<TagData*>::iterator iter = tagList.begin();
iter != tagList.end(); ++iter)
if (*iter)
{
delete *iter;
}
tagList.clear();
}
size_t MesquiteMesh::MeshTags::size_from_tag_type( Mesh::TagType type )
{
switch ( type )
{
case Mesh::BYTE: return 1;
case Mesh::BOOL: return sizeof(bool);
case Mesh::DOUBLE: return sizeof(double);
case Mesh::INT: return sizeof(int);
case Mesh::HANDLE: return sizeof(void*);
case Mesh::LONG_LONG: return sizeof(long long);
default: assert(0); return 0;
}
}
size_t MesquiteMesh::MeshTags::create( const std::string& name,
Mesh::TagType type,
unsigned length,
const void* defval,
MsqError& err )
{
size_t h = handle( name, err );
if (h)
{
MSQ_SETERR(err)(name, MsqError::TAG_ALREADY_EXISTS);
return 0;
}
if (length == 0 || size_from_tag_type(type) == 0)
{
MSQ_SETERR(err)(MsqError::INVALID_ARG);
return 0;
}
TagData* tag = new TagData( name, type, length );
h = tagList.size();
tagList.push_back(tag);
if (defval)
{
tag->defaultValue = malloc( tag->desc.size );
memcpy( tag->defaultValue, defval, tag->desc.size );
}
return h+1;
}
size_t MesquiteMesh::MeshTags::create( const MfemTagDescription& desc,
const void* defval,
MsqError& err )
{
size_t h = handle( desc.name.c_str(), err );
if (h)
{
MSQ_SETERR(err)(desc.name.c_str(), MsqError::TAG_ALREADY_EXISTS);
return 0;
}
err.clear();
if (desc.size == 0 || (desc.size % size_from_tag_type(desc.type)) != 0)
{
MSQ_SETERR(err)(MsqError::INVALID_ARG);
return 0;
}
TagData* tag = new TagData( desc );
h = tagList.size();
tagList.push_back(tag);
if (defval)
{
tag->defaultValue = malloc( tag->desc.size );
memcpy( tag->defaultValue, defval, tag->desc.size );
}
return h+1;
}
void MesquiteMesh::MeshTags::destroy( size_t tag_index, MsqError& err )
{
--tag_index;
if (tag_index >= tagList.size() || 0 == tagList[tag_index])
{
MSQ_SETERR(err)(MsqError::TAG_NOT_FOUND);
return ;
}
delete tagList[tag_index];
tagList[tag_index] = 0;
}
size_t MesquiteMesh::MeshTags::handle( const std::string& name,
MsqError& err ) const
{
for (size_t i = 0; i < tagList.size(); ++i)
if (tagList[i] && tagList[i]->desc.name == name)
{
return i+1;
}
return 0;
}
const MesquiteMesh::MfemTagDescription& MesquiteMesh::MeshTags::properties(
size_t tag_index, MsqError& err ) const
{
static MfemTagDescription dummy_desc;
--tag_index;
if (tag_index >= tagList.size() || !tagList[tag_index])
{
MSQ_SETERR(err)("Invalid tag handle", MsqError::INVALID_ARG);
return dummy_desc;
}
return tagList[tag_index]->desc;
}
void MesquiteMesh::MeshTags::set_element_data( size_t tag_index,
size_t num_indices,
const size_t* index_array,
const void* values,
MsqError& err )
{
size_t i;
char* data;
--tag_index;
if (tag_index >= tagList.size() || !tagList[tag_index])
{
MSQ_SETERR(err)("Invalid tag handle", MsqError::INVALID_ARG);
return;
}
TagData* tag = tagList[tag_index];
// Get highest element index
size_t total = tag->elementCount;
for (i = 0; i < num_indices; ++i)
if (index_array[i] >= total)
{
total = index_array[i] + 1;
}
// If need more space
if (total > tag->elementCount)
{
// allocate more space
tag->elementData = realloc( tag->elementData, tag->desc.size * total );
// if a default value, initialize new space with it
if (tag->defaultValue)
{
data = ((char*)tag->elementData) + tag->elementCount * tag->desc.size;
for (i = tag->elementCount; i < total; ++i)
{
memcpy( data, tag->defaultValue, tag->desc.size );
data += tag->desc.size;
}
}
else
{
memset( (char*)tag->elementData + tag->elementCount * tag->desc.size, 0,
(total - tag->elementCount) * tag->desc.size );
}
tag->elementCount = total;
}
// Store passed tag values
data = (char*)tag->elementData;
const char* iter = (const char*)values;
for (i = 0; i < num_indices; ++i)
{
memcpy( data + index_array[i]*tag->desc.size, iter, tag->desc.size );
iter += tag->desc.size;
}
}
void MesquiteMesh::MeshTags::get_element_data( size_t tag_index,
size_t num_indices,
const size_t* index_array,
void* values,
MsqError& err ) const
{
--tag_index;
if (tag_index >= tagList.size() || !tagList[tag_index])
{
MSQ_SETERR(err)("Invalid tag handle", MsqError::INVALID_ARG);
return;
}
TagData* tag = tagList[tag_index];
char* iter = (char*)values;
const char* data = (const char*)tag->elementData;
for (size_t i = 0; i < num_indices; ++i)
{
const void* ptr;
size_t index = index_array[i];
if (index >= tag->elementCount)
{
ptr = tag->defaultValue;
if (!ptr)
{
MSQ_SETERR(err)(MsqError::TAG_NOT_FOUND);
return;
}
}
else
{
ptr = data + index * tag->desc.size;
}
memcpy( iter, ptr, tag->desc.size );
iter += tag->desc.size;
}
}
void MesquiteMesh::MeshTags::set_vertex_data( size_t tag_index,
size_t num_indices,
const size_t* index_array,
const void* values,
MsqError& err )
{
size_t i;
char* data;
--tag_index;
if (tag_index >= tagList.size() || !tagList[tag_index])
{
MSQ_SETERR(err)("Invalid tag handle", MsqError::INVALID_ARG);
return;
}
TagData* tag = tagList[tag_index];
// Get highest element index
size_t total = tag->vertexCount;
for (i = 0; i < num_indices; ++i)
if (index_array[i] >= total)
{
total = index_array[i] + 1;
}
// If need more space
if (total > tag->vertexCount)
{
// allocate more space
tag->vertexData = realloc( tag->vertexData, tag->desc.size * total );
// if a default value, initialize new space with it
if (tag->defaultValue)
{
data = ((char*)tag->vertexData) + tag->vertexCount * tag->desc.size;
for (i = tag->vertexCount; i < total; ++i)
{
memcpy( data, tag->defaultValue, tag->desc.size );
data += tag->desc.size;
}
}
else
{
memset( (char*)tag->vertexData + tag->vertexCount * tag->desc.size, 0,
(total - tag->vertexCount) * tag->desc.size );
}
tag->vertexCount = total;
}
// Store passed tag values
data = (char*)tag->vertexData;
const char* iter = (const char*)values;
for (i = 0; i < num_indices; ++i)
{
memcpy( data + index_array[i]*tag->desc.size, iter, tag->desc.size );
iter += tag->desc.size;
}
}
void MesquiteMesh::MeshTags::get_vertex_data( size_t tag_index,
size_t num_indices,
const size_t* index_array,
void* values,
MsqError& err ) const
{
--tag_index;
if (tag_index >= tagList.size() || !tagList[tag_index])
{
MSQ_SETERR(err)("Invalid tag handle", MsqError::INVALID_ARG);
return;
}
TagData* tag = tagList[tag_index];
char* iter = (char*)values;
const char* data = (const char*)tag->vertexData;
for (size_t i = 0; i < num_indices; ++i)
{
const void* ptr;
size_t index = index_array[i];
if (index >= tag->vertexCount)
{
ptr = tag->defaultValue;
if (!ptr)
{
MSQ_SETERR(err)(MsqError::TAG_NOT_FOUND);
return;
}
}
else
{
ptr = data + index * tag->desc.size;
}
memcpy( iter, ptr, tag->desc.size );
iter += tag->desc.size;
}
}
bool MesquiteMesh::MeshTags::tag_has_vertex_data( size_t tag_index,
MsqError& err )
{
--tag_index;
if (tag_index >= tagList.size() || !tagList[tag_index])
{
MSQ_SETERR(err)("Invalid tag handle", MsqError::INVALID_ARG);
return false;
}
TagData* tag = tagList[tag_index];
return 0 != tag->vertexData || tag->defaultValue;
}
bool MesquiteMesh::MeshTags::tag_has_element_data( size_t tag_index,
MsqError& err )
{
--tag_index;
if (tag_index >= tagList.size() || !tagList[tag_index])
{
MSQ_SETERR(err)("Invalid tag handle", MsqError::INVALID_ARG);
return false;
}
TagData* tag = tagList[tag_index];
return 0 != tag->elementData || tag->defaultValue;
}
MesquiteMesh::MeshTags::TagIterator MesquiteMesh::MeshTags::tag_begin()
{
size_t index = 0;
while (index < tagList.size() && tagList[index] == NULL)
{
++index;
}
return TagIterator( this, index );
}
MesquiteMesh::MeshTags::TagIterator
MesquiteMesh::MeshTags::TagIterator::operator++()
{
++index;
while (index < tags->tagList.size() && NULL == tags->tagList[index])
{
++index;
}
return TagIterator( tags, index );
}
MesquiteMesh::MeshTags::TagIterator
MesquiteMesh::MeshTags::TagIterator::operator--()
{
--index;
while (index < tags->tagList.size() && NULL == tags->tagList[index])
{
--index;
}
return TagIterator( tags, index );
}
MesquiteMesh::MeshTags::TagIterator
MesquiteMesh::MeshTags::TagIterator::operator++(int)
{
size_t old = index;
++index;
while (index < tags->tagList.size() && NULL == tags->tagList[index])
{
++index;
}
return TagIterator( tags, old );
}
MesquiteMesh::MeshTags::TagIterator
MesquiteMesh::MeshTags::TagIterator::operator--(int)
{
size_t old = index;
--index;
while (index < tags->tagList.size() && NULL == tags->tagList[index])
{
--index;
}
return TagIterator( tags, old );
}
//
// MesquiteMesh implementation follows
//
MesquiteMesh::MesquiteMesh(mfem::Mesh *mfem_mesh)
: myTags( new MeshTags )
{
mesh = mfem_mesh;
nelems = mesh->GetNE();
nodes = mesh->GetNodes();
if (nodes)
{
fes = nodes->FESpace();
ndofs = fes->GetNDofs();
fes->BuildElementToDofTable();
const Table *elem_dof = &fes->GetElementToDofTable();
dof_elem = new Table;
Transpose(*elem_dof, *dof_elem, ndofs);
}
else
{
ndofs = mesh->GetNV();
dof_elem = mesh->GetVertexToElementTable();
}
mByte = vector<char>(ndofs);
mFixed = vector<bool>(ndofs, false);
// By default, flag all boundary nodes as fixed
Array<int> bdofs;
for (int i = 0; i < mesh->GetNBE(); i++)
{
if (nodes)
{
fes->GetBdrElementDofs(i, bdofs);
}
else
{
mesh->GetBdrElementVertices(i, bdofs);
}
for (int j = 0; j < bdofs.Size(); j++)
{
mFixed[bdofs[j]] = true;
}
}
}
int MesquiteMesh::get_geometric_dimension(Mesquite::MsqError &err)
{
return mesh->Dimension();
}
void MesquiteMesh::get_all_elements(std::vector<ElementHandle>& elements,
Mesquite::MsqError& err)
{
elements.resize(nelems);
for (int i = 0; i < nelems; i++)
{
elements[i] = (ElementHandle) i;
}
}
void MesquiteMesh::get_all_vertices(std::vector<VertexHandle>& vertices,
Mesquite::MsqError& err)
{
vertices.resize(ndofs);
for (int i = 0; i < ndofs; i++)
{
vertices[i] = (VertexHandle) i;
}
}
void MesquiteMesh::vertices_get_coordinates(const VertexHandle vert_array[],
MsqVertex* coordinates,
size_t num_vtx,
MsqError &err)
{
const size_t *indices = (const size_t*) vert_array;
double coords[3];
for (int i = 0; i < num_vtx; i++)
{
mesh->GetNode(indices[i], coords);
coordinates[i].x(coords[0]);
coordinates[i].y(coords[1]);
if (mesh->Dimension() == 3 )
{
coordinates[i].z(coords[2]);
}
else
{
coordinates[i].z(0.0);
}
}
}
void MesquiteMesh::vertex_set_coordinates(VertexHandle vertex,
const Vector3D &coordinates,
MsqError &err)
{
double coords[3];
coords[0] = coordinates.x();
coords[1] = coordinates.y();
coords[2] = coordinates.z();
mesh->SetNode((size_t) vertex, coords);
}
void MesquiteMesh::vertex_set_byte(VertexHandle vertex,
unsigned char byte,
MsqError &err)
{
size_t index = (size_t) vertex;
mByte[index] = byte;
}
void MesquiteMesh::vertices_set_byte(const VertexHandle *vert_array,
const unsigned char *byte_array,
size_t array_size,
MsqError &err)
{
const size_t* indices = (const size_t*) vert_array;
for (int i = 0; i < array_size; i++)
{
mByte[indices[i]] = byte_array[i];
}
}
void MesquiteMesh::vertex_get_byte(const VertexHandle vertex,
unsigned char *byte,
MsqError &err )
{
*byte = mByte[(const size_t) vertex];
}
void MesquiteMesh::vertices_get_byte(const VertexHandle *vertex,
unsigned char *byte_array,
size_t array_size,
MsqError &err )
{
const size_t* indices = (const size_t*) vertex;
for (int i = 0; i < array_size; i++)
{
byte_array[i] = mByte[indices[i]];
}
}
void MesquiteMesh::vertices_get_fixed_flag(const VertexHandle vert_array[],
std::vector<bool>& fixed_flag_array,
size_t num_vtx,
MsqError &err )
{
fixed_flag_array.resize(num_vtx + 1);
const size_t* indices = (const size_t*) vert_array;
for (int i = 0; i < num_vtx; i++)
{
fixed_flag_array[i] = mFixed[indices[i]];
}
}
void MesquiteMesh::vertices_set_fixed_flag(const VertexHandle vert_array[],
const std::vector< bool > &fixed_flag_array,
size_t num_vtx,
MsqError &err )
{
const size_t* indices = (const size_t*) vert_array;
for (int i = 0; i < num_vtx; i++)
{
mFixed[indices[i]] = fixed_flag_array[i];
}
}
void MesquiteMesh::elements_get_attached_vertices(const ElementHandle
*elem_handles,
size_t num_elems,
std::vector<VertexHandle>& vert_handles,
std::vector<size_t>& offsets,
MsqError &err)
{
const size_t* indices = (const size_t*) elem_handles;
vert_handles.clear();
offsets.resize(num_elems + 1);
Array<int> elem_dofs;
for (int i = 0; i < num_elems; i++)
{
offsets[i] = vert_handles.size();
elem = mesh->GetElement(indices[i]);
if (nodes)
{
fes->GetElementDofs(indices[i],elem_dofs);
}
else
{
elem->GetVertices(elem_dofs);
}
for (int j = 0; j < elem_dofs.Size(); j++)
{
// Ordering of this matters!!!
// We are good for triangles, quads and hexes. What about tets?
vert_handles.push_back( (VertexHandle) elem_dofs[j] );
}
}
offsets[num_elems] = vert_handles.size();
}
void MesquiteMesh::vertices_get_attached_elements(const VertexHandle*
vertex_array,
size_t num_vertex,
std::vector<ElementHandle>& elements,
std::vector<size_t>& offsets,
MsqError& err)
{
const size_t* indices = (const size_t*) vertex_array;
elements.clear();
offsets.resize(num_vertex + 1);
for (int i = 0; i < num_vertex; i++)
{
offsets[i] = elements.size();
int* vertex_elems = dof_elem->GetRow(indices[i]);
for (int j = 0; j < dof_elem->RowSize(indices[i]); j++)
{
elements.push_back( (ElementHandle) vertex_elems[j] );
}
}
offsets[num_vertex] = elements.size();
}
void MesquiteMesh::elements_get_topologies(const ElementHandle
*element_handle_array,
EntityTopology *element_topologies,
size_t num_elements,
MsqError &err)
{
// In MESQUITE:
// TRIANGLE = 8
// QUADRILATERAL = 9
// TETRAHEDRON = 11
// HEXAHEDRON = 12
// In MFEM:
// POINT = 0
// SEGMENT = 1
// TRIANGLE = 2
// QUADRILATERAL = 3
// TETRAHEDRON = 4
// HEXAHEDRON = 5
// BISECTED = 6
// QUADRISECTED = 7
// OCTASECTED = 8
int mfem_to_mesquite[9] = {0,0,8,9,11,12,0,0,0};
const size_t* indices = (const size_t*) element_handle_array;
for (int i = 0; i < num_elements; i++)
{
element_topologies[i] = (EntityTopology) mfem_to_mesquite[mesh->GetElementType(
indices[i])];
}
}
MesquiteMesh::~MesquiteMesh()
{
MsqPrintError err(mfem::err);
delete myTags;
delete dof_elem;
}
void
MesquiteMesh::tag_attributes()
{
MsqError err;
// create a tag for a single integer value
TagHandle attributeTagHandle = tag_create( "material", Mesh::INT, 1, 0, err );
int *materialValues = new int[nelems];
for (int i=0; i<nelems; i++)
{
materialValues[i] = mesh->GetAttribute(i);
}
//
// now put these values into an element tag
//
std::vector<ElementHandle> elements;
get_all_elements(elements, err );
tag_set_element_data( attributeTagHandle, nelems, arrptr(elements),
(const void*)(materialValues), err );
delete[] materialValues;
}
TagHandle MesquiteMesh::tag_create( const std::string& name,
TagType type,
unsigned length,
const void* defval,
MsqError& err )
{
size_t size = MeshTags::size_from_tag_type( type );
MfemTagDescription desc( name, type, length*size );
size_t index = myTags->create( desc, defval, err ); MSQ_ERRZERO(err);
return (TagHandle)index;
}
void MesquiteMesh::tag_delete( TagHandle handle, MsqError& err )
{
myTags->destroy( (size_t)handle, err ); MSQ_CHKERR(err);
}
TagHandle MesquiteMesh::tag_get( const std::string& name, MsqError& err )
{
size_t index = myTags->handle( name, err ); MSQ_ERRZERO(err);
if (!index)
{
MSQ_SETERR(err)( MsqError::TAG_NOT_FOUND, "could not find tag \"%s\"",
name.c_str() );
}
return (TagHandle)index;
}
void MesquiteMesh::tag_properties( TagHandle handle,
std::string& name,
TagType& type,
unsigned& length,
MsqError& err )
{
const MfemTagDescription& desc
= myTags->properties( (size_t)handle, err ); MSQ_ERRRTN(err);
name = desc.name;
type = desc.type;
length = (unsigned)(desc.size / MeshTags::size_from_tag_type( desc.type ));
}
void MesquiteMesh::tag_set_element_data( TagHandle handle,
size_t num_elems,
const ElementHandle* elem_array,
const void* values,
MsqError& err )
{
myTags->set_element_data( (size_t)handle,
num_elems,
(const size_t*)elem_array,
values,
err ); MSQ_CHKERR(err);
}
void MesquiteMesh::tag_get_element_data( TagHandle handle,
size_t num_elems,
const ElementHandle* elem_array,
void* values,
MsqError& err )
{
myTags->get_element_data( (size_t)handle,
num_elems,
(const size_t*)elem_array,
values,
err ); MSQ_CHKERR(err);
}
void MesquiteMesh::tag_set_vertex_data( TagHandle handle,
size_t num_elems,
const VertexHandle* elem_array,
const void* values,
MsqError& err )
{
myTags->set_vertex_data( (size_t)handle,
num_elems,
(const size_t*)elem_array,
values,
err ); MSQ_CHKERR(err);
}
void MesquiteMesh::tag_get_vertex_data( TagHandle handle,
size_t num_elems,
const VertexHandle* elem_array,
void* values,
MsqError& err )
{
myTags->get_vertex_data( (size_t)handle,
num_elems,
(const size_t*)elem_array,
values,
err ); MSQ_CHKERR(err);
}
static void BoundaryPreservingOptimization(mfem::MesquiteMesh &mesh)
{
MsqDebug::enable(1);
MsqPrintError err(mfem::err);
int pOrder = 2;
int mNumInterfaceSmoothIters = 5;
bool mFixBndryInInterfaceSmooth = true; //this fixes exterior surface nodes
bool project_gradient= false;
double cos_crease_angle=0.2;
// get all vertices
std::vector<Mesquite::Mesh::VertexHandle> vertices;
mesh.get_all_vertices(vertices, err);
if (MSQ_CHKERR(err)) {mfem::out << err << std::endl; exit(EXIT_FAILURE);}
int num_vertices = vertices.size();
// get application fixed vertices
std::vector<bool> app_fixed(num_vertices);
mesh.vertices_get_fixed_flag(&(vertices[0]), app_fixed, num_vertices, err);
if (MSQ_CHKERR(err)) {mfem::out << err << std::endl; exit(EXIT_FAILURE);}
int num_app_fixed = 0;
for (int i = 0; i < num_vertices; i++)
{
if (app_fixed[i]) { num_app_fixed++; }
}
mfem::out << "mesh has " << num_vertices << " vertices and " << num_app_fixed <<
" are app fixed. ";
// create planar domain for interior and assessor queues
Mesquite::PlanarDomain geom( PlanarDomain::XY );
// tag the underlying mesh material attributes.
mesh.tag_attributes();
// create boundary domain and find mesh boundary
Mesquite::MeshBoundaryDomain2D* mesh_domain = new
Mesquite::MeshBoundaryDomain2D( MeshBoundaryDomain2D::XY, 0.0, project_gradient,
Mesquite::MeshBoundaryDomain2D::QUADRATIC);
mesh_domain->skin_area_mesh(&mesh,cos_crease_angle,"material");
std::vector<Mesquite::Mesh::VertexHandle> theBoundaryVertices;
mesh_domain->get_boundary_vertices( theBoundaryVertices );
int num_boundary_vertices = theBoundaryVertices.size();
std::vector<Mesquite::Mesh::VertexHandle> theBoundaryEdges;
mesh_domain->get_boundary_edges( theBoundaryEdges );
// int num_boundary_edges = theBoundaryEdges.size();
std::vector<bool> fixed_flags_boundary(num_boundary_vertices);
// get application fixed boundary vertices
std::vector<bool> app_fixed_boundary(num_boundary_vertices);
mesh.vertices_get_fixed_flag(&(theBoundaryVertices[0]),app_fixed_boundary,
num_boundary_vertices, err);
int num_app_fixed_boundary = 0;
for (int i = 0; i < num_boundary_vertices; i++)
{
if (app_fixed_boundary[i]) { num_app_fixed_boundary++; }
}
mfem::out << "mesh has " << num_boundary_vertices << " boundary vertices and "
<< num_app_fixed_boundary << " are app fixed" << std::endl;
// only fix boundary vertices along corners
int num_fixed_boundary_flags = 0;
std::vector<Mesquite::Mesh::VertexHandle> theCornerVertices;
mesh_domain->get_corner_vertices( theCornerVertices );
// fix only vertices that are classified as corners
for (int i = 0; i < num_boundary_vertices; i++)
{
if (!mFixBndryInInterfaceSmooth)
{
fixed_flags_boundary[i] = false;
}
else
{
fixed_flags_boundary[i] = app_fixed_boundary[i];
}
for (int j = 0; j < theCornerVertices.size(); j++)
{
// printf("theCornerVertices[%d]=%lu\n",j, (size_t)(theCornerVertices[j]));
if (theCornerVertices[j] == theBoundaryVertices[i])
{
fixed_flags_boundary[i] = true;
num_fixed_boundary_flags++;
break;
}
}
}
printf("fixed %d of %d boundary vertices (those classified corner)\n",
num_fixed_boundary_flags, num_boundary_vertices);
// creates three intruction queues
Mesquite::InstructionQueue boundary_queue;
Mesquite::InstructionQueue interior_queue;
boundary_queue.set_slaved_ho_node_mode(Settings::SLAVE_ALL);
interior_queue.set_slaved_ho_node_mode(Settings::SLAVE_ALL);
TShapeB1 targetMetric;
IdealShapeTarget tc;
TQualityMetric metric( &tc, &targetMetric );
Mesquite::LPtoPTemplate* obj_func = new Mesquite::LPtoPTemplate(&metric, pOrder,
err);
if (MSQ_CHKERR(err)) {mfem::out << err << std::endl; exit(EXIT_FAILURE);}
Mesquite::QuasiNewton* boundary_alg = new Mesquite::QuasiNewton( obj_func);
boundary_alg->use_element_on_vertex_patch();
Mesquite::QuasiNewton* interior_alg = new Mesquite::QuasiNewton( obj_func );
interior_alg->use_global_patch();
// **************Set stopping criterion**************
double grad_norm = 1e-5;
double successiveEps = 1e-5;
int boundary_outer = 5;
int boundary_inner = 3;
// for boundary
Mesquite::TerminationCriterion* boundaryTermInner = new
Mesquite::TerminationCriterion();
Mesquite::TerminationCriterion* boundaryTermOuter = new
Mesquite::TerminationCriterion();
// boundaryTermInner->add_absolute_gradient_L2_norm(grad_norm);
// boundaryTermInner->add_relative_successive_improvement(successiveEps);
boundaryTermOuter->add_relative_successive_improvement(successiveEps);
boundaryTermOuter->add_iteration_limit(boundary_outer);
boundaryTermInner->add_iteration_limit(boundary_inner);
ostringstream bndryStream;
bndryStream<<"boundary_"<<targetMetric.get_name()<<"_p"<<pOrder;
boundaryTermOuter->write_mesh_steps(bndryStream.str().c_str());
boundary_alg->set_outer_termination_criterion(boundaryTermOuter);
boundary_alg->set_inner_termination_criterion(boundaryTermInner);
// for interior
Mesquite::TerminationCriterion* interiorTermInner = new
Mesquite::TerminationCriterion();
Mesquite::TerminationCriterion* interiorTermOuter = new
Mesquite::TerminationCriterion();
interiorTermInner->add_absolute_gradient_L2_norm(grad_norm);
interiorTermInner->add_relative_successive_improvement(successiveEps);
// interiorTermInner->add_iteration_limit(3); // for element_on_vertex_patch mode
interiorTermInner->add_iteration_limit(100); // for global_patch mode
ostringstream interiorStream;
interiorStream<<"interior_"<<targetMetric.get_name()<<"_p"<<pOrder;
interiorTermOuter->write_mesh_steps(interiorStream.str().c_str());
interiorTermOuter->add_iteration_limit(1);
interior_alg->set_outer_termination_criterion(interiorTermOuter);
interior_alg->set_inner_termination_criterion(interiorTermInner);
// ConditionNumberQualityMetric qm_metric;
// QualityAssessor boundary_assessor,interior_assessor;
// boundary_assessor.add_quality_assessment( &metric, 10 );
// boundary_assessor.add_quality_assessment( &qm_metric );
// interior_assessor.add_quality_assessment( &metric, 10 );
// interior_assessor.add_quality_assessment( &qm_metric );
// set the boundary instruction queue
// boundary_queue.add_quality_assessor( &boundary_assessor, err );
boundary_queue.set_master_quality_improver(boundary_alg, err);
// boundary_queue.add_quality_assessor( &boundary_assessor, err );
if (MSQ_CHKERR(err)) {mfem::out << err << std::endl; exit(EXIT_FAILURE);}
// set the interior instruction queue
// interior_queue.add_quality_assessor( &interior_assessor, err );
interior_queue.set_master_quality_improver(interior_alg, err);
// interior_queue.add_quality_assessor( &interior_assessor, err );
if (MSQ_CHKERR(err)) {mfem::out << err << std::endl; exit(EXIT_FAILURE);}
err.clear();
std::vector<bool> fixed_flags(num_vertices);
for (int j=0; j<mNumInterfaceSmoothIters; j++)
{
mfem::out<<" Boundary + Interior smoothing pass "<< j<<"....."<<endl;
// smooth boundary only
for (int i = 0; i < num_vertices; i++) { fixed_flags[i] = true; }
mesh.vertices_set_fixed_flag(&(vertices[0]),fixed_flags,num_vertices, err);
if (MSQ_CHKERR(err)) {mfem::out << err << std::endl; exit(EXIT_FAILURE);}
mesh.vertices_set_fixed_flag(&(theBoundaryVertices[0]),fixed_flags_boundary,
num_boundary_vertices, err);
if (MSQ_CHKERR(err)) {mfem::out << err << std::endl; exit(EXIT_FAILURE);}
// -----------------------------------------------------
// debug
//
mesh.vertices_get_fixed_flag(&(vertices[0]),fixed_flags,num_vertices, err);
if (MSQ_CHKERR(err)) {mfem::out << err << std::endl; exit(EXIT_FAILURE);}
int num_fixed = 0;
for (int i = 0; i < num_vertices; i++)
{
if (fixed_flags[i]) { num_fixed++; }
}
mfem::out << " For Boundary smooth, mesh has " << num_vertices <<
" vertices and " << num_fixed << " are fixed. "<<endl;
//
// debug
// -----------------------------------------------------
boundary_queue.run_instructions(&mesh, mesh_domain, err);
if (MSQ_CHKERR(err)) {mfem::out << err << std::endl; exit(EXIT_FAILURE);}
mfem::out<<" boundary smooth completed in "<<boundaryTermOuter->get_iteration_count()
<<" outer and "<<boundaryTermInner->get_iteration_count()
<<" inner iterations."<<endl;
// smooth interior only
if (!mFixBndryInInterfaceSmooth)
{
//
// let all interior vertices float during the interior smooth.
//
for (int i = 0; i < num_vertices; i++) { fixed_flags[i] = false; }
mesh.vertices_set_fixed_flag(&(vertices[0]),fixed_flags,num_vertices, err);
}
else
{
//
// use the app_fixed settings for the fixed state of boundary vertices.
//
mesh.vertices_set_fixed_flag(&(vertices[0]),app_fixed,num_vertices, err);
}
if (MSQ_CHKERR(err)) {mfem::out << err << std::endl; exit(EXIT_FAILURE);}
for (int i = 0; i < num_boundary_vertices; i++) { fixed_flags[i] = true; }
mesh.vertices_set_fixed_flag(&(theBoundaryVertices[0]),fixed_flags,
num_boundary_vertices, err);
if (MSQ_CHKERR(err)) {mfem::out << err << std::endl; exit(EXIT_FAILURE);}
// -----------------------------------------------------
// debug
//
mesh.vertices_get_fixed_flag(&(vertices[0]),fixed_flags,num_vertices, err);
if (MSQ_CHKERR(err)) {mfem::out << err << std::endl; exit(EXIT_FAILURE);}
num_fixed = 0;
for (int i = 0; i < num_vertices; i++)
{
if (fixed_flags[i]) { num_fixed++; }
}
mfem::out << " For Interior smooth, mesh has " << num_vertices <<
" vertices and " << num_fixed << " are fixed. "<<endl;
//
// debug
// -----------------------------------------------------
interior_queue.run_instructions(&mesh, &geom, err);
if (MSQ_CHKERR(err)) {mfem::out << err << std::endl; exit(EXIT_FAILURE);}
mfem::out<<" interior smooth completed in "<<interiorTermOuter->get_iteration_count()
<<" outer and "<<interiorTermInner->get_iteration_count()
<<" inner iterations."<<endl;
}
delete mesh_domain;
delete interiorTermOuter;
delete interiorTermInner;
delete boundaryTermOuter;
delete boundaryTermInner;
delete interior_alg;
delete boundary_alg;
delete obj_func;
}
// Implementation of Mesh::MesquiteSmooth method
void mfem::Mesh::MesquiteSmooth(const int mesquite_option)
{
mfem::MesquiteMesh msq_mesh(this);
MsqDebug::enable(1);
MsqPrintError err(mfem::err);
Wrapper *method;
const double vert_move_tol = 1e-3;
switch (mesquite_option)
{
case 0: method = new LaplaceWrapper(); break;
case 1: method = new UntangleWrapper(); break;
case 2: method = new ShapeImprover(); break;
case 3: method = new PaverMinEdgeLengthWrapper(vert_move_tol); break;
}
if ( mesquite_option < 4 )
{
// Specify SLAVE_NONE for high order node positions
method->set_slaved_ho_node_mode(Settings::SLAVE_NONE);
if ( this->Dimension() == 3 )
{
method->run_instructions(&msq_mesh, err);
}
else
{
Vector3D normal(0,0,1);
Vector3D point(0,0,0);
PlanarDomain mesh_plane(normal, point);
method->run_instructions(&msq_mesh, &mesh_plane, err);
}
}
else
{
// boundary perserving smoothing doesn't have a wrapper yet.
BoundaryPreservingOptimization( msq_mesh );
}
}
}
#endif