Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
// Copyright (c) 2010-2023, 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.
//
// --------------------------------------------------------------
// Shaper Miniapp: Resolve material interfaces by mesh refinement
// --------------------------------------------------------------
//
// This miniapp performs multiple levels of adaptive mesh refinement to resolve
// the interfaces between different "materials" in the mesh, as specified by the
// given material() function. It can be used as a simple initial mesh generator,
// for example in the case when the interface is too complex to describe without
// local refinement. Both conforming and non-conforming refinements are supported.
//
// Two additional versions of this miniapp can be found in the miniapps/toys
// directory: Mandel uses the Shaper algorithm for fractal visualization, while
// Mondrian convert an image to an AMR mesh suitable for MFEM computations.
//
// Compile with: make shaper
//
// Sample runs: shaper
// shaper -m ../../data/inline-tri.mesh
// shaper -m ../../data/inline-hex.mesh
// shaper -m ../../data/inline-tet.mesh
// shaper -m ../../data/amr-quad.mesh
// shaper -m ../../data/beam-quad.mesh -a -ncl -1 -sd 4
// shaper -m ../../data/ball-nurbs.mesh
// shaper -m ../../data/mobius-strip.mesh
// shaper -m ../../data/square-disc-surf.mesh
// shaper -m ../../data/star-q3.mesh -sd 2 -ncl -1
// shaper -m ../../data/fichera-amr.mesh -a -ncl -1
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace mfem;
using namespace std;
// Given a point x, return its material id as an integer. The ids should be
// positive. If the point is exactly on the interface, return 0.
//
// This particular implementation, rescales the mesh to [-1,1]^sdim given the
// xmin/xmax bounding box, and shapes in a simple annulus/shell with respect to
// the rescaled coordinates.
int material(Vector &x, Vector &xmin, Vector &xmax)
{
static double p = 2.0;
// Rescaling to [-1,1]^sdim
for (int i = 0; i < x.Size(); i++)
{
x(i) = (2*x(i)-xmin(i)-xmax(i))/(xmax(i)-xmin(i));
}
// A simple annulus/shell
if (x.Normlp(p) > 0.4 && x.Normlp(p) < 0.6) { return 1; }
if (x.Normlp(p) < 0.4 || x.Normlp(p) > 0.6) { return 2; }
return 0;
}
int main(int argc, char *argv[])
{
int sd = 2;
int nclimit = 1;
const char *mesh_file = "../../data/inline-quad.mesh";
bool aniso = false;
// Parse command line
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Input mesh file to shape materials in.");
args.AddOption(&sd, "-sd", "--sub-divisions",
"Number of element subdivisions for interface detection.");
args.AddOption(&nclimit, "-ncl", "--nc-limit",
"Level of hanging nodes allowed (-1 = unlimited).");
args.AddOption(&aniso, "-a", "--aniso", "-i", "--iso",
"Enable anisotropic refinement of quads and hexes.");
args.Parse();
if (!args.Good()) { args.PrintUsage(cout); return 1; }
args.PrintOptions(cout);
// Read initial mesh, get dimensions and bounding box
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
int sdim = mesh.SpaceDimension();
Vector xmin, xmax;
mesh.GetBoundingBox(xmin, xmax);
// NURBS meshes don't support non-conforming refinement for now
if (mesh.NURBSext) { mesh.SetCurvature(2); }
// Anisotropic refinement not supported for simplex meshes.
if (mesh.MeshGenerator() & 1) { aniso = false; }
// Mesh attributes will be visualized as piece-wise constants
L2_FECollection attr_fec(0, dim);
FiniteElementSpace attr_fespace(&mesh, &attr_fec);
GridFunction attr(&attr_fespace);
// GLVis server to visualize to
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
// Shaping loop
for (int iter = 0; 1; iter++)
{
Array<Refinement> refs;
for (int i = 0; i < mesh.GetNE(); i++)
{
bool refine = false;
// Sample materials in each element using "sd" sub-divisions
Vector pt;
Geometry::Type geom = mesh.GetElementBaseGeometry(i);
ElementTransformation *T = mesh.GetElementTransformation(i);
RefinedGeometry *RefG = GlobGeometryRefiner.Refine(geom, sd, 1);
IntegrationRule &ir = RefG->RefPts;
// Refine any element where different materials are detected. A more
// sophisticated logic can be implemented here -- e.g. don't refine
// the interfaces between certain materials.
Array<int> mat(ir.GetNPoints());
double matsum = 0.0;
for (int j = 0; j < ir.GetNPoints(); j++)
{
T->Transform(ir.IntPoint(j), pt);
int m = material(pt, xmin, xmax);
mat[j] = m;
matsum += m;
if ((int)matsum != m*(j+1))
{
refine = true;
}
}
// Set the element attribute as the "average". Other choices are
// possible here too, e.g. attr(i) = mat;
attr(i) = round(matsum/ir.GetNPoints());
// Mark the element for refinement
if (refine)
{
int type = 7;
if (aniso)
{
// Determine the XYZ bitmask for anisotropic refinement.
int dx = 0, dy = 0, dz = 0;
const int s = sd+1;
if (dim == 2)
{
for (int jj = 0; jj <= sd; jj++)
for (int ii = 0; ii < sd; ii++)
{
dx += abs(mat[jj*s + ii+1] - mat[jj*s + ii]);
dy += abs(mat[(ii+1)*s + jj] - mat[ii*s + jj]);
}
}
else if (dim == 3)
{
for (int kk = 0; kk <= sd; kk++)
for (int jj = 0; jj <= sd; jj++)
for (int ii = 0; ii < sd; ii++)
{
dx += abs(mat[(kk*s + jj)*s + ii+1] - mat[(kk*s + jj)*s + ii]);
dy += abs(mat[(kk*s + ii+1)*s + jj] - mat[(kk*s + ii)*s + jj]);
dz += abs(mat[((ii+1)*s + jj)*s + kk] - mat[(ii*s + jj)*s + kk]);
}
}
type = 0;
const int tol = mat.Size() / 10;
if (dx > tol) { type |= 1; }
if (dy > tol) { type |= 2; }
if (dz > tol) { type |= 4; }
if (!type) { type = 7; } // because of tol
}
refs.Append(Refinement(i, type));
}
}
// Visualization
sol_sock << "solution\n" << mesh << attr;
if (iter == 0 && sdim == 2)
{
sol_sock << "keys 'RjlmpppppppppppppA*************'\n";
}
if (iter == 0 && sdim == 3)
{
sol_sock << "keys 'YYYYYYYYYXXXXXXXmA********8888888pppttt";
if (dim == 3) { sol_sock << "iiM"; }
sol_sock << "'\n";
}
sol_sock << flush;
// Ask the user if we should continue refining
char yn;
cout << "Mesh has " << mesh.GetNE() << " elements. \n"
<< "Continue shaping? --> ";
cin >> yn;
if (yn == 'n' || yn == 'q') { break; }
// Perform refinement, update spaces and grid functions
mesh.GeneralRefinement(refs, -1, nclimit);
attr_fespace.Update();
attr.Update();
}
// Set element attributes in the mesh object before saving
for (int i = 0; i < mesh.GetNE(); i++)
{
mesh.SetAttribute(i, static_cast<int>(attr(i)));
}
mesh.SetAttributes();
// Save the final mesh
ofstream mesh_ofs("shaper.mesh");
mesh_ofs.precision(8);
mesh.Print(mesh_ofs);
}