Merge pull request #4044 from mfem/named-attr-sets
Named attribute sets
This commit is contained in:
@@ -70,6 +70,9 @@ Miscellaneous
|
||||
- RAJA backend will use seq_exec for serial loop execution when RAJA
|
||||
v2023.06.00 and beyond is detected as loop_exec is deprecated.
|
||||
|
||||
- Adding named attribute sets and basic supporting methods to the Mesh class as
|
||||
a convenient means of referring to sets of domain or boundary attribute
|
||||
numbers. Also adding related serial and parallel examples which illustrate.
|
||||
|
||||
Version 4.6, released on September 27, 2023
|
||||
===========================================
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
SetFactory("OpenCASCADE");
|
||||
|
||||
order = 1;
|
||||
|
||||
R = 1;
|
||||
r = 0.2;
|
||||
|
||||
Point(1) = {0,0,0};
|
||||
|
||||
Point(2) = {r/Sqrt(2),r/Sqrt(2),0};
|
||||
Point(3) = {-r/Sqrt(2),r/Sqrt(2),0};
|
||||
Point(4) = {-r/Sqrt(2),-r/Sqrt(2),0};
|
||||
Point(5) = {r/Sqrt(2),-r/Sqrt(2),0};
|
||||
|
||||
Point(6) = {R,0,0};
|
||||
Point(7) = {R/Sqrt(2),R/Sqrt(2),0};
|
||||
Point(8) = {0,R,0};
|
||||
Point(9) = {-R/Sqrt(2),R/Sqrt(2),0};
|
||||
Point(10) = {-R,0,0};
|
||||
Point(11) = {-R/Sqrt(2),-R/Sqrt(2),0};
|
||||
Point(12) = {0,-R,0};
|
||||
Point(13) = {R/Sqrt(2),-R/Sqrt(2),0};
|
||||
|
||||
Line(1) = {1,2};
|
||||
Line(2) = {1,3};
|
||||
Line(3) = {1,4};
|
||||
Line(4) = {1,5};
|
||||
|
||||
Line(5) = {1,6};
|
||||
Line(6) = {1,8};
|
||||
Line(7) = {1,10};
|
||||
Line(8) = {1,12};
|
||||
|
||||
Line(9) = {2,6};
|
||||
Line(10) = {2,8};
|
||||
Line(11) = {3,8};
|
||||
Line(12) = {3,10};
|
||||
Line(13) = {4,10};
|
||||
Line(14) = {4,12};
|
||||
Line(15) = {5,12};
|
||||
Line(16) = {5,6};
|
||||
|
||||
Line(17) = {6,7};
|
||||
Line(18) = {7,8};
|
||||
Line(19) = {8,9};
|
||||
Line(20) = {9,10};
|
||||
Line(21) = {10,11};
|
||||
Line(22) = {11,12};
|
||||
Line(23) = {12,13};
|
||||
Line(24) = {13,6};
|
||||
|
||||
Transfinite Curve{1:24} = 2;
|
||||
|
||||
Physical Curve("ENE") = {17};
|
||||
Physical Curve("NNE") = {18};
|
||||
Physical Curve("NNW") = {19};
|
||||
Physical Curve("WNW") = {20};
|
||||
Physical Curve("WSW") = {21};
|
||||
Physical Curve("SSW") = {22};
|
||||
Physical Curve("SSE") = {23};
|
||||
Physical Curve("ESE") = {24};
|
||||
|
||||
Curve Loop(1) = {9,17,18,-10};
|
||||
Curve Loop(2) = {11,19,20,-12};
|
||||
Curve Loop(3) = {13,21,22,-14};
|
||||
Curve Loop(4) = {15,23,24,-16};
|
||||
|
||||
Plane Surface(1) = {1};
|
||||
Plane Surface(2) = {2};
|
||||
Plane Surface(3) = {3};
|
||||
Plane Surface(4) = {4};
|
||||
|
||||
Transfinite Surface{1} = {2,6,7,8};
|
||||
Transfinite Surface{2} = {3,8,9,10};
|
||||
Transfinite Surface{3} = {4,10,11,12};
|
||||
Transfinite Surface{4} = {5,12,13,6};
|
||||
Recombine Surface{1:4};
|
||||
|
||||
Physical Surface("Base") = {1,2,3,4};
|
||||
|
||||
Curve Loop(5) = {1,10,-6};
|
||||
Plane Surface(5) = {5};
|
||||
Physical Surface("N Even") = {5};
|
||||
|
||||
Curve Loop(6) = {6,-11,-2};
|
||||
Plane Surface(6) = {6};
|
||||
Physical Surface("N Odd") = {6};
|
||||
|
||||
Curve Loop(7) = {2,12,-7};
|
||||
Plane Surface(7) = {7};
|
||||
Physical Surface("W Even") = {7};
|
||||
|
||||
Curve Loop(8) = {7,-13,-3};
|
||||
Plane Surface(8) = {8};
|
||||
Physical Surface("W Odd") = {8};
|
||||
|
||||
Curve Loop(9) = {3,14,-8};
|
||||
Plane Surface(9) = {9};
|
||||
Physical Surface("S Even") = {9};
|
||||
|
||||
Curve Loop(10) = {8,-15,-4};
|
||||
Plane Surface(10) = {10};
|
||||
Physical Surface("S Odd") = {10};
|
||||
|
||||
Curve Loop(11) = {4,16,-5};
|
||||
Plane Surface(11) = {11};
|
||||
Physical Surface("E Even") = {11};
|
||||
|
||||
Curve Loop(12) = {5,-9,-1};
|
||||
Plane Surface(12) = {12};
|
||||
Physical Surface("E Odd") = {12};
|
||||
|
||||
// Generate 2D mesh
|
||||
Mesh 2;
|
||||
SetOrder order;
|
||||
Mesh.MshFileVersion = 2.2;
|
||||
|
||||
Save "compass.msh";
|
||||
@@ -0,0 +1,95 @@
|
||||
MFEM mesh v1.3
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
#
|
||||
|
||||
dimension
|
||||
2
|
||||
|
||||
elements
|
||||
12
|
||||
10 2 7 0 1
|
||||
11 2 0 7 2
|
||||
12 2 9 0 2
|
||||
13 2 0 9 3
|
||||
14 2 11 0 3
|
||||
15 2 0 11 4
|
||||
16 2 5 0 4
|
||||
17 2 0 5 1
|
||||
9 3 1 5 6 7
|
||||
9 3 2 7 8 9
|
||||
9 3 3 9 10 11
|
||||
9 3 4 11 12 5
|
||||
|
||||
attribute_sets
|
||||
16
|
||||
"Base" 1 9
|
||||
"E Even" 1 16
|
||||
"E Odd" 1 17
|
||||
"East" 2 16 17
|
||||
"N Even" 1 10
|
||||
"N Odd" 1 11
|
||||
"North" 2 10 11
|
||||
"Rose" 8 10 11 12 13 14 15 16 17
|
||||
"Rose Even" 4 10 12 14 16
|
||||
"Rose Odd" 4 11 13 15 17
|
||||
"S Even" 1 14
|
||||
"S Odd" 1 15
|
||||
"South" 2 14 15
|
||||
"W Even" 1 12
|
||||
"W Odd" 1 13
|
||||
"West" 2 12 13
|
||||
|
||||
boundary
|
||||
8
|
||||
1 1 5 6
|
||||
2 1 6 7
|
||||
3 1 7 8
|
||||
4 1 8 9
|
||||
5 1 9 10
|
||||
6 1 10 11
|
||||
7 1 11 12
|
||||
8 1 12 5
|
||||
|
||||
bdr_attribute_sets
|
||||
13
|
||||
"Boundary" 8 1 2 3 4 5 6 7 8
|
||||
"ENE" 1 1
|
||||
"ESE" 1 8
|
||||
"Eastern Boundary" 2 1 8
|
||||
"NNE" 1 2
|
||||
"NNW" 1 3
|
||||
"Northern Boundary" 2 2 3
|
||||
"SSE" 1 7
|
||||
"SSW" 1 6
|
||||
"Southern Boundary" 2 6 7
|
||||
"WNW" 1 4
|
||||
"WSW" 1 5
|
||||
"Western Boundary" 2 4 5
|
||||
|
||||
vertices
|
||||
13
|
||||
2
|
||||
0 0
|
||||
0.14142136 0.14142136
|
||||
-0.14142136 0.14142136
|
||||
-0.14142136 -0.14142136
|
||||
0.14142136 -0.14142136
|
||||
1 0
|
||||
0.70710678 0.70710678
|
||||
0 1
|
||||
-0.70710678 0.70710678
|
||||
-1 0
|
||||
-0.70710678 -0.70710678
|
||||
0 -1
|
||||
0.70710678 -0.70710678
|
||||
mfem_mesh_end
|
||||
@@ -0,0 +1,62 @@
|
||||
$MeshFormat
|
||||
2.2 0 8
|
||||
$EndMeshFormat
|
||||
$PhysicalNames
|
||||
17
|
||||
1 1 "ENE"
|
||||
1 2 "NNE"
|
||||
1 3 "NNW"
|
||||
1 4 "WNW"
|
||||
1 5 "WSW"
|
||||
1 6 "SSW"
|
||||
1 7 "SSE"
|
||||
1 8 "ESE"
|
||||
2 9 "Base"
|
||||
2 10 "N Even"
|
||||
2 11 "N Odd"
|
||||
2 12 "W Even"
|
||||
2 13 "W Odd"
|
||||
2 14 "S Even"
|
||||
2 15 "S Odd"
|
||||
2 16 "E Even"
|
||||
2 17 "E Odd"
|
||||
$EndPhysicalNames
|
||||
$Nodes
|
||||
13
|
||||
1 0 0 0
|
||||
2 0.1414213562373095 0.1414213562373095 0
|
||||
3 -0.1414213562373095 0.1414213562373095 0
|
||||
4 -0.1414213562373095 -0.1414213562373095 0
|
||||
5 0.1414213562373095 -0.1414213562373095 0
|
||||
6 1 0 0
|
||||
7 0.7071067811865475 0.7071067811865475 0
|
||||
8 0 1 0
|
||||
9 -0.7071067811865475 0.7071067811865475 0
|
||||
10 -1 0 0
|
||||
11 -0.7071067811865475 -0.7071067811865475 0
|
||||
12 0 -1 0
|
||||
13 0.7071067811865475 -0.7071067811865475 0
|
||||
$EndNodes
|
||||
$Elements
|
||||
20
|
||||
1 1 2 1 17 6 7
|
||||
2 1 2 2 18 7 8
|
||||
3 1 2 3 19 8 9
|
||||
4 1 2 4 20 9 10
|
||||
5 1 2 5 21 10 11
|
||||
6 1 2 6 22 11 12
|
||||
7 1 2 7 23 12 13
|
||||
8 1 2 8 24 13 6
|
||||
9 2 2 10 5 1 2 8
|
||||
10 2 2 11 6 1 8 3
|
||||
11 2 2 12 7 1 3 10
|
||||
12 2 2 13 8 1 10 4
|
||||
13 2 2 14 9 1 4 12
|
||||
14 2 2 15 10 1 12 5
|
||||
15 2 2 16 11 1 5 6
|
||||
16 2 2 17 12 1 6 2
|
||||
17 3 2 9 1 2 6 7 8
|
||||
18 3 2 9 2 3 8 9 10
|
||||
19 3 2 9 3 4 10 11 12
|
||||
20 3 2 9 4 5 12 13 6
|
||||
$EndElements
|
||||
@@ -43,13 +43,9 @@ list(APPEND ALL_EXE_SRCS
|
||||
ex34.cpp
|
||||
ex36.cpp
|
||||
ex37.cpp
|
||||
)
|
||||
|
||||
if(MFEM_USE_LAPACK)
|
||||
list(APPEND ALL_EXE_SRCS
|
||||
ex38.cpp
|
||||
ex39.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if (MFEM_USE_MPI)
|
||||
list(APPEND ALL_EXE_SRCS
|
||||
@@ -90,7 +86,8 @@ if (MFEM_USE_MPI)
|
||||
ex35p.cpp
|
||||
ex36p.cpp
|
||||
ex37p.cpp
|
||||
)
|
||||
ex39p.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
# Examples that return MFEM_SKIP_RETURN_VALUE in some cases:
|
||||
@@ -101,6 +98,9 @@ endif()
|
||||
if (MFEM_USE_SINGLE)
|
||||
list(APPEND SKIP_TESTS ex33.cpp ex33p.cpp)
|
||||
endif()
|
||||
if (NOT MFEM_USE_LAPACK)
|
||||
list(APPEND SKIP_TESTS ex38.cpp)
|
||||
endif()
|
||||
|
||||
# Include the source directory where mfem.hpp and mfem-performance.hpp are.
|
||||
include_directories(BEFORE ${PROJECT_BINARY_DIR})
|
||||
|
||||
+1
-1
@@ -505,7 +505,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
#ifndef MFEM_USE_LAPACK
|
||||
cout << "MFEM must be built with LAPACK for this example." << endl;
|
||||
return EXIT_FAILURE;
|
||||
return MFEM_SKIP_RETURN_VALUE;
|
||||
#else
|
||||
// 1. Parse he command-line options.
|
||||
int ref_levels = 3;
|
||||
|
||||
@@ -0,0 +1,285 @@
|
||||
// MFEM Example 39
|
||||
//
|
||||
// Compile with: make ex39
|
||||
//
|
||||
// Sample runs: ex39
|
||||
// ex39 -ess "Southern Boundary"
|
||||
// ex39 -src Base
|
||||
//
|
||||
// Description: This example code demonstrates the use of named attribute
|
||||
// sets in MFEM to specify material regions, boundary regions,
|
||||
// or source regions by name rather than attribute numbers. It
|
||||
// also demonstrates how new named attribute sets may be created
|
||||
// from arbitrary groupings of attribute numbers and used as a
|
||||
// convenient shorthand to refer to those groupings in other
|
||||
// portions of the application or through the command line.
|
||||
//
|
||||
// The particular problem being solved here is nearly the same
|
||||
// as that in example 1 i.e. a simple finite element
|
||||
// discretization of the Laplace problem -Delta u = 1 with
|
||||
// homogeneous Dirichlet boundary conditions and, in this case,
|
||||
// an inhomogeneous diffusion coefficient. The diffusion
|
||||
// coefficient is given a small default value throughout the
|
||||
// domain which is increased by two separate amounts in two named
|
||||
// regions.
|
||||
//
|
||||
// This example makes use of a specific input mesh, "compass.msh",
|
||||
// containing named domain and boundary regions generated by Gmsh
|
||||
// and stored in their "msh" format (version 2.2). This file
|
||||
// defines eight boundary regions corresponding to eight compass
|
||||
// headings; "ENE", "NNE", "NNW", "WSW", "SSW", "SSE", and "ESE".
|
||||
// It also defines nine domain regions; "Base", "N Even", "N Odd",
|
||||
// "W Even", "W Odd", "S Even", "S Odd", "E Even", and "E Odd".
|
||||
// These regions split the four compass pointers into two halves
|
||||
// each and also label the remaining elements as "Base". Starting
|
||||
// with these named regions we test the construction of named
|
||||
// sets as well as reading and writing these named groupings from
|
||||
// and to mesh files.
|
||||
//
|
||||
// The example highlights the use of named attribute sets for
|
||||
// both subdomains and boundaries in different contexts as well
|
||||
// as basic methods to create named sets from existing attributes.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../data/compass.msh";
|
||||
int order = 1;
|
||||
string source_name = "Rose Even";
|
||||
string ess_name = "Boundary";
|
||||
bool visualization = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree) or -1 for"
|
||||
" isoparametric space.");
|
||||
args.AddOption(&source_name,"-src","--source-attr-name",
|
||||
"Name of attribute set containing source.");
|
||||
args.AddOption(&ess_name,"-ess","--ess-attr-name",
|
||||
"Name of attribute set containing essential BC.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.ParseCheck();
|
||||
|
||||
// 2. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
|
||||
// the same code.
|
||||
Mesh mesh(mesh_file, 1, 1);
|
||||
int dim = mesh.Dimension();
|
||||
|
||||
// 3. Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
|
||||
// largest number that gives a final mesh with no more than 50,000
|
||||
// elements.
|
||||
{
|
||||
int ref_levels =
|
||||
(int)floor(log(50000./mesh.GetNE())/log(2.)/dim);
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
}
|
||||
}
|
||||
|
||||
// 4a. Display attribute set names contained in the initial mesh
|
||||
AttributeSets &attr_sets = mesh.attribute_sets;
|
||||
AttributeSets &bdr_attr_sets = mesh.bdr_attribute_sets;
|
||||
{
|
||||
std::set<string> names = attr_sets.GetAttributeSetNames();
|
||||
cout << "Element Attribute Set Names: ";
|
||||
for (auto const &set_name : names)
|
||||
{
|
||||
cout << " \"" << set_name << "\"";
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
std::set<string> bdr_names = bdr_attr_sets.GetAttributeSetNames();
|
||||
cout << "Boundary Attribute Set Names: ";
|
||||
for (auto const &bdr_set_name : bdr_names)
|
||||
{
|
||||
cout << " \"" << bdr_set_name << "\"";
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
// 4b. Define new regions based on existing attribute sets
|
||||
{
|
||||
Array<int> & Na = attr_sets.GetAttributeSet("N Even");
|
||||
Array<int> & Nb = attr_sets.GetAttributeSet("N Odd");
|
||||
Array<int> & Sa = attr_sets.GetAttributeSet("S Even");
|
||||
Array<int> & Sb = attr_sets.GetAttributeSet("S Odd");
|
||||
Array<int> & Ea = attr_sets.GetAttributeSet("E Even");
|
||||
Array<int> & Eb = attr_sets.GetAttributeSet("E Odd");
|
||||
Array<int> & Wa = attr_sets.GetAttributeSet("W Even");
|
||||
Array<int> & Wb = attr_sets.GetAttributeSet("W Odd");
|
||||
|
||||
// Create a new set spanning the North point
|
||||
attr_sets.SetAttributeSet("North", Na);
|
||||
attr_sets.AddToAttributeSet("North", Nb);
|
||||
|
||||
// Create a new set spanning the South point
|
||||
attr_sets.SetAttributeSet("South", Sa);
|
||||
attr_sets.AddToAttributeSet("South", Sb);
|
||||
|
||||
// Create a new set spanning the East point
|
||||
attr_sets.SetAttributeSet("East", Ea);
|
||||
attr_sets.AddToAttributeSet("East", Eb);
|
||||
|
||||
// Create a new set spanning the West point
|
||||
attr_sets.SetAttributeSet("West", Wa);
|
||||
attr_sets.AddToAttributeSet("West", Wb);
|
||||
|
||||
// Create a new set consisting of the "a" sides of the compass rose
|
||||
attr_sets.SetAttributeSet("Rose Even", Na);
|
||||
attr_sets.AddToAttributeSet("Rose Even", Sa);
|
||||
attr_sets.AddToAttributeSet("Rose Even", Ea);
|
||||
attr_sets.AddToAttributeSet("Rose Even", Wa);
|
||||
|
||||
// Create a new set consisting of the "b" sides of the compass rose
|
||||
attr_sets.SetAttributeSet("Rose Odd", Nb);
|
||||
attr_sets.AddToAttributeSet("Rose Odd", Sb);
|
||||
attr_sets.AddToAttributeSet("Rose Odd", Eb);
|
||||
attr_sets.AddToAttributeSet("Rose Odd", Wb);
|
||||
|
||||
// Create a new set consisting of the full compass rose
|
||||
Array<int> & Ra = attr_sets.GetAttributeSet("Rose Even");
|
||||
Array<int> & Rb = attr_sets.GetAttributeSet("Rose Odd");
|
||||
attr_sets.SetAttributeSet("Rose", Ra);
|
||||
attr_sets.AddToAttributeSet("Rose", Rb);
|
||||
}
|
||||
// 4c. Define new boundary regions based on existing boundary attribute sets
|
||||
{
|
||||
Array<int> & NNE = bdr_attr_sets.GetAttributeSet("NNE");
|
||||
Array<int> & NNW = bdr_attr_sets.GetAttributeSet("NNW");
|
||||
Array<int> & ENE = bdr_attr_sets.GetAttributeSet("ENE");
|
||||
Array<int> & ESE = bdr_attr_sets.GetAttributeSet("ESE");
|
||||
Array<int> & SSE = bdr_attr_sets.GetAttributeSet("SSE");
|
||||
Array<int> & SSW = bdr_attr_sets.GetAttributeSet("SSW");
|
||||
Array<int> & WNW = bdr_attr_sets.GetAttributeSet("WNW");
|
||||
Array<int> & WSW = bdr_attr_sets.GetAttributeSet("WSW");
|
||||
|
||||
bdr_attr_sets.SetAttributeSet("Northern Boundary", NNE);
|
||||
bdr_attr_sets.AddToAttributeSet("Northern Boundary", NNW);
|
||||
|
||||
bdr_attr_sets.SetAttributeSet("Southern Boundary", SSE);
|
||||
bdr_attr_sets.AddToAttributeSet("Southern Boundary", SSW);
|
||||
|
||||
bdr_attr_sets.SetAttributeSet("Eastern Boundary", ENE);
|
||||
bdr_attr_sets.AddToAttributeSet("Eastern Boundary", ESE);
|
||||
|
||||
bdr_attr_sets.SetAttributeSet("Western Boundary", WNW);
|
||||
bdr_attr_sets.AddToAttributeSet("Western Boundary", WSW);
|
||||
|
||||
bdr_attr_sets.SetAttributeSet("Boundary",
|
||||
bdr_attr_sets.GetAttributeSet
|
||||
("Northern Boundary"));
|
||||
bdr_attr_sets.AddToAttributeSet("Boundary",
|
||||
bdr_attr_sets.GetAttributeSet
|
||||
("Southern Boundary"));
|
||||
bdr_attr_sets.AddToAttributeSet("Boundary",
|
||||
bdr_attr_sets.GetAttributeSet
|
||||
("Eastern Boundary"));
|
||||
bdr_attr_sets.AddToAttributeSet("Boundary",
|
||||
bdr_attr_sets.GetAttributeSet
|
||||
("Western Boundary"));
|
||||
}
|
||||
|
||||
// 5. Define a finite element space on the mesh. Here we use continuous
|
||||
// Lagrange finite elements of the specified order.
|
||||
H1_FECollection fec(order, mesh.Dimension());
|
||||
FiniteElementSpace fespace(&mesh, &fec);
|
||||
cout << "Number of finite element unknowns: "
|
||||
<< fespace.GetTrueVSize() << endl;
|
||||
|
||||
// 6. Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
// In this example, the boundary conditions are defined by marking all
|
||||
// the boundary regions corresponding to the boundary attributes
|
||||
// contained in the set named "ess_name" as essential (Dirichlet) and
|
||||
// converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
if (bdr_attr_sets.AttributeSetExists(ess_name))
|
||||
{
|
||||
Array<int> ess_bdr_marker = bdr_attr_sets.GetAttributeSetMarker(ess_name);
|
||||
fespace.GetEssentialTrueDofs(ess_bdr_marker, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 7. Set up the linear form b(.) which corresponds to the right-hand side of
|
||||
// the FEM linear system, which in this case is (1_s,phi_i) where phi_i
|
||||
// are the basis functions in fespace and 1_s is an indicator function
|
||||
// equal to 1 on the region defined by the named set "source_name" and
|
||||
// zero elsewhere.
|
||||
Array<int> source_marker = attr_sets.GetAttributeSetMarker(source_name);
|
||||
|
||||
LinearForm b(&fespace);
|
||||
ConstantCoefficient one(1.0);
|
||||
b.AddDomainIntegrator(new DomainLFIntegrator(one), source_marker);
|
||||
b.Assemble();
|
||||
|
||||
// 8. Define the solution vector x as a finite element grid function
|
||||
// corresponding to fespace. Initialize x with initial guess of zero,
|
||||
// which satisfies the boundary conditions.
|
||||
GridFunction x(&fespace);
|
||||
x = 0.0;
|
||||
|
||||
// 9. Set up the bilinear form a(.,.) on the finite element space
|
||||
// corresponding to the Laplacian operator -Delta, by adding the
|
||||
// Diffusion domain integrator.
|
||||
BilinearForm a(&fespace);
|
||||
|
||||
ConstantCoefficient defaultCoef(1.0e-6);
|
||||
ConstantCoefficient baseCoef(1.0);
|
||||
ConstantCoefficient roseCoef(2.0);
|
||||
|
||||
Array<int> base_marker = attr_sets.GetAttributeSetMarker("Base");
|
||||
Array<int> rose_marker = attr_sets.GetAttributeSetMarker("Rose Even");
|
||||
|
||||
// Impose a very small diffusion coefficient across the entire mesh
|
||||
a.AddDomainIntegrator(new DiffusionIntegrator(defaultCoef));
|
||||
|
||||
// Impose an additional, stronger diffusion coefficient in select regions
|
||||
a.AddDomainIntegrator(new DiffusionIntegrator(baseCoef), base_marker);
|
||||
a.AddDomainIntegrator(new DiffusionIntegrator(roseCoef), rose_marker);
|
||||
|
||||
// 10. Assemble the bilinear form and the corresponding linear system,
|
||||
// applying any necessary transformations.
|
||||
a.Assemble();
|
||||
|
||||
SparseMatrix A;
|
||||
Vector B, X;
|
||||
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
|
||||
|
||||
cout << "Size of linear system: " << A.Height() << endl;
|
||||
|
||||
// 11. Solve the system using PCG with symmetric Gauss-Seidel preconditioner.
|
||||
GSSmoother M(A);
|
||||
PCG(A, M, B, X, 1, 800, 1e-12, 0.0);
|
||||
|
||||
// 12. Recover the solution as a finite element grid function.
|
||||
a.RecoverFEMSolution(X, b, x);
|
||||
|
||||
// 13. Save the refined mesh and the solution. This output can be viewed
|
||||
// later using GLVis: "glvis -m refined.mesh -g sol.gf".
|
||||
mesh.Save("refined.mesh");
|
||||
x.Save("sol.gf");
|
||||
|
||||
// 14. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << mesh << x << "keys Rjmm" << flush;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
// MFEM Example 39 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex39p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex39p
|
||||
// mpirun -np 4 ex39p -ess "Southern Boundary"
|
||||
// mpirun -np 4 ex39p -src Base
|
||||
//
|
||||
// Description: This example code demonstrates the use of named attribute
|
||||
// sets in MFEM to specify material regions, boundary regions,
|
||||
// or source regions by name rather than attribute numbers. It
|
||||
// also demonstrates how new named attribute sets may be created
|
||||
// from arbitrary groupings of attribute numbers and used as a
|
||||
// convenient shorthand to refer to those groupings in other
|
||||
// portions of the application or through the command line.
|
||||
//
|
||||
// The particular problem being solved here is nearly the same
|
||||
// as that in example 1 i.e. a simple finite element
|
||||
// discretization of the Laplace problem -Delta u = 1 with
|
||||
// homogeneous Dirichlet boundary conditions and, in this case,
|
||||
// an inhomogeneous diffusion coefficient. The diffusion
|
||||
// coefficient is given a small default value throughout the
|
||||
// domain which is increased by two separate amounts in two named
|
||||
// regions.
|
||||
//
|
||||
// This example makes use of a specific input mesh, "compass.msh",
|
||||
// containing named domain and boundary regions generated by Gmsh
|
||||
// and stored in their "msh" format (version 2.2). This file
|
||||
// defines eight boundary regions corresponding to eight compass
|
||||
// headings; "ENE", "NNE", "NNW", "WSW", "SSW", "SSE", and "ESE".
|
||||
// It also defines nine domain regions; "Base", "N Even", "N Odd",
|
||||
// "W Even", "W Odd", "S Even", "S Odd", "E Even", and "E Odd".
|
||||
// These regions split the four compass pointers into two halves
|
||||
// each and also label the remaining elements as "Base". Starting
|
||||
// with these named regions we test the construction of named
|
||||
// sets as well as reading and writing these named groupings from
|
||||
// and to mesh files.
|
||||
//
|
||||
// The example highlights the use of named attribute sets for
|
||||
// both subdomains and boundaries in different contexts as well
|
||||
// as basic methods to create named sets from existing attributes.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI and HYPRE.
|
||||
Mpi::Init();
|
||||
Hypre::Init();
|
||||
|
||||
// 2. Parse command-line options.
|
||||
const char *mesh_file = "../data/compass.msh";
|
||||
int order = 1;
|
||||
string source_name = "Rose Even";
|
||||
string ess_name = "Boundary";
|
||||
bool visualization = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree) or -1 for"
|
||||
" isoparametric space.");
|
||||
args.AddOption(&source_name,"-src","--source-attr-name",
|
||||
"Name of attribute set containing source.");
|
||||
args.AddOption(&ess_name,"-ess","--ess-attr-name",
|
||||
"Name of attribute set containing essential BC.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.ParseCheck();
|
||||
|
||||
// 3. Read the serial mesh from the given mesh file.
|
||||
Mesh mesh(mesh_file, 1, 1);
|
||||
int dim = mesh.Dimension();
|
||||
|
||||
// 4. Refine the serial mesh on all processors to increase the resolution. In
|
||||
// this example we do 'ref_levels' of uniform refinement. We choose
|
||||
// 'ref_levels' to be the largest number that gives a final mesh with no
|
||||
// more than 10,000 elements.
|
||||
{
|
||||
int ref_levels =
|
||||
(int)floor(log(10000./mesh.GetNE())/log(2.)/dim);
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
mesh.Clear();
|
||||
{
|
||||
int par_ref_levels = 2;
|
||||
for (int l = 0; l < par_ref_levels; l++)
|
||||
{
|
||||
pmesh.UniformRefinement();
|
||||
}
|
||||
}
|
||||
|
||||
// 6a. Display attribute set names contained in the initial mesh
|
||||
AttributeSets &attr_sets = pmesh.attribute_sets;
|
||||
AttributeSets &bdr_attr_sets = pmesh.bdr_attribute_sets;
|
||||
if (Mpi::Root())
|
||||
{
|
||||
std::set<string> names = attr_sets.GetAttributeSetNames();
|
||||
cout << "Element Attribute Set Names: ";
|
||||
for (auto const &set_name : names)
|
||||
{
|
||||
cout << " \"" << set_name << "\"";
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
std::set<string> bdr_names = bdr_attr_sets.GetAttributeSetNames();
|
||||
cout << "Boundary Attribute Set Names: ";
|
||||
for (auto const &bdr_set_name : bdr_names)
|
||||
{
|
||||
cout << " \"" << bdr_set_name << "\"";
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
// 6b. Define new regions based on existing attribute sets
|
||||
{
|
||||
Array<int> & Na = attr_sets.GetAttributeSet("N Even");
|
||||
Array<int> & Nb = attr_sets.GetAttributeSet("N Odd");
|
||||
Array<int> & Sa = attr_sets.GetAttributeSet("S Even");
|
||||
Array<int> & Sb = attr_sets.GetAttributeSet("S Odd");
|
||||
Array<int> & Ea = attr_sets.GetAttributeSet("E Even");
|
||||
Array<int> & Eb = attr_sets.GetAttributeSet("E Odd");
|
||||
Array<int> & Wa = attr_sets.GetAttributeSet("W Even");
|
||||
Array<int> & Wb = attr_sets.GetAttributeSet("W Odd");
|
||||
|
||||
// Create a new set spanning the North point
|
||||
attr_sets.SetAttributeSet("North", Na);
|
||||
attr_sets.AddToAttributeSet("North", Nb);
|
||||
|
||||
// Create a new set spanning the South point
|
||||
attr_sets.SetAttributeSet("South", Sa);
|
||||
attr_sets.AddToAttributeSet("South", Sb);
|
||||
|
||||
// Create a new set spanning the East point
|
||||
attr_sets.SetAttributeSet("East", Ea);
|
||||
attr_sets.AddToAttributeSet("East", Eb);
|
||||
|
||||
// Create a new set spanning the West point
|
||||
attr_sets.SetAttributeSet("West", Wa);
|
||||
attr_sets.AddToAttributeSet("West", Wb);
|
||||
|
||||
// Create a new set consisting of the "a" sides of the compass rose
|
||||
attr_sets.SetAttributeSet("Rose Even", Na);
|
||||
attr_sets.AddToAttributeSet("Rose Even", Sa);
|
||||
attr_sets.AddToAttributeSet("Rose Even", Ea);
|
||||
attr_sets.AddToAttributeSet("Rose Even", Wa);
|
||||
|
||||
// Create a new set consisting of the "b" sides of the compass rose
|
||||
attr_sets.SetAttributeSet("Rose Odd", Nb);
|
||||
attr_sets.AddToAttributeSet("Rose Odd", Sb);
|
||||
attr_sets.AddToAttributeSet("Rose Odd", Eb);
|
||||
attr_sets.AddToAttributeSet("Rose Odd", Wb);
|
||||
|
||||
|
||||
// Create a new set consisting of the full compass rose
|
||||
Array<int> & Ra = attr_sets.GetAttributeSet("Rose Even");
|
||||
Array<int> & Rb = attr_sets.GetAttributeSet("Rose Odd");
|
||||
attr_sets.SetAttributeSet("Rose", Ra);
|
||||
attr_sets.AddToAttributeSet("Rose", Rb);
|
||||
}
|
||||
// 6c. Define new boundary regions based on existing boundary attribute sets
|
||||
{
|
||||
Array<int> & NNE = bdr_attr_sets.GetAttributeSet("NNE");
|
||||
Array<int> & NNW = bdr_attr_sets.GetAttributeSet("NNW");
|
||||
Array<int> & ENE = bdr_attr_sets.GetAttributeSet("ENE");
|
||||
Array<int> & ESE = bdr_attr_sets.GetAttributeSet("ESE");
|
||||
Array<int> & SSE = bdr_attr_sets.GetAttributeSet("SSE");
|
||||
Array<int> & SSW = bdr_attr_sets.GetAttributeSet("SSW");
|
||||
Array<int> & WNW = bdr_attr_sets.GetAttributeSet("WNW");
|
||||
Array<int> & WSW = bdr_attr_sets.GetAttributeSet("WSW");
|
||||
|
||||
bdr_attr_sets.SetAttributeSet("Northern Boundary", NNE);
|
||||
bdr_attr_sets.AddToAttributeSet("Northern Boundary", NNW);
|
||||
|
||||
bdr_attr_sets.SetAttributeSet("Southern Boundary", SSE);
|
||||
bdr_attr_sets.AddToAttributeSet("Southern Boundary", SSW);
|
||||
|
||||
bdr_attr_sets.SetAttributeSet("Eastern Boundary", ENE);
|
||||
bdr_attr_sets.AddToAttributeSet("Eastern Boundary", ESE);
|
||||
|
||||
bdr_attr_sets.SetAttributeSet("Western Boundary", WNW);
|
||||
bdr_attr_sets.AddToAttributeSet("Western Boundary", WSW);
|
||||
|
||||
bdr_attr_sets.SetAttributeSet("Boundary",
|
||||
bdr_attr_sets.GetAttributeSet
|
||||
("Northern Boundary"));
|
||||
bdr_attr_sets.AddToAttributeSet("Boundary",
|
||||
bdr_attr_sets.GetAttributeSet
|
||||
("Southern Boundary"));
|
||||
bdr_attr_sets.AddToAttributeSet("Boundary",
|
||||
bdr_attr_sets.GetAttributeSet
|
||||
("Eastern Boundary"));
|
||||
bdr_attr_sets.AddToAttributeSet("Boundary",
|
||||
bdr_attr_sets.GetAttributeSet
|
||||
("Western Boundary"));
|
||||
}
|
||||
|
||||
// 7. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use continuous Lagrange finite elements of the specified order. If
|
||||
// order < 1, we instead use an isoparametric/isogeometric space.
|
||||
H1_FECollection fec(order, dim);
|
||||
ParFiniteElementSpace fespace(&pmesh, &fec);
|
||||
HYPRE_BigInt size = fespace.GlobalTrueVSize();
|
||||
if (Mpi::Root())
|
||||
{
|
||||
cout << "Number of finite element unknowns: " << size << endl;
|
||||
}
|
||||
|
||||
// 8. Determine the list of true (i.e. parallel conforming) essential
|
||||
// boundary dofs. In this example, the boundary conditions are defined
|
||||
// by marking all the boundary regions corresponding to the boundary
|
||||
// attributes contained in the set named "ess_name" as essential
|
||||
// (Dirichlet) and converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
if (bdr_attr_sets.AttributeSetExists(ess_name))
|
||||
{
|
||||
Array<int> ess_bdr_marker = bdr_attr_sets.GetAttributeSetMarker(ess_name);
|
||||
fespace.GetEssentialTrueDofs(ess_bdr_marker, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 9. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system, which in this case is
|
||||
// (1_s,phi_i) where phi_i are the basis functions in fespace and 1_s
|
||||
// is an indicator function equal to 1 on the region defined by the
|
||||
// named set "source_name" and zero elsewhere.
|
||||
Array<int> source_marker = attr_sets.GetAttributeSetMarker(source_name);
|
||||
|
||||
ParLinearForm b(&fespace);
|
||||
ConstantCoefficient one(1.0);
|
||||
b.AddDomainIntegrator(new DomainLFIntegrator(one), source_marker);
|
||||
b.Assemble();
|
||||
|
||||
// 10. Define the solution vector x as a parallel finite element grid
|
||||
// function corresponding to fespace. Initialize x with initial guess of
|
||||
// zero, which satisfies the boundary conditions.
|
||||
ParGridFunction x(&fespace);
|
||||
x = 0.0;
|
||||
|
||||
// 11. Set up the parallel bilinear form a(.,.) on the finite element space
|
||||
// corresponding to the Laplacian operator -Delta, by adding the
|
||||
// Diffusion domain integrator.
|
||||
ParBilinearForm a(&fespace);
|
||||
|
||||
ConstantCoefficient defaultCoef(1.0e-6);
|
||||
ConstantCoefficient baseCoef(1.0);
|
||||
ConstantCoefficient roseCoef(2.0);
|
||||
|
||||
Array<int> base_marker = attr_sets.GetAttributeSetMarker("Base");
|
||||
Array<int> rose_marker = attr_sets.GetAttributeSetMarker("Rose Even");
|
||||
|
||||
// Impose a very small diffusion coefficient across the entire mesh
|
||||
a.AddDomainIntegrator(new DiffusionIntegrator(defaultCoef));
|
||||
|
||||
// Impose an additional, stronger diffusion coefficient in select regions
|
||||
a.AddDomainIntegrator(new DiffusionIntegrator(baseCoef), base_marker);
|
||||
a.AddDomainIntegrator(new DiffusionIntegrator(roseCoef), rose_marker);
|
||||
|
||||
// 12. Assemble the parallel bilinear form and the corresponding linear
|
||||
// system, applying any necessary transformations.
|
||||
a.Assemble();
|
||||
|
||||
HypreParMatrix A;
|
||||
Vector B, X;
|
||||
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
|
||||
|
||||
// 13. Solve the system using PCG with hypre's BoomerAMG preconditioner.
|
||||
HypreBoomerAMG M(A);
|
||||
CGSolver cg(MPI_COMM_WORLD);
|
||||
cg.SetRelTol(1e-12);
|
||||
cg.SetMaxIter(2000);
|
||||
cg.SetPrintLevel(1);
|
||||
cg.SetPreconditioner(M);
|
||||
cg.SetOperator(A);
|
||||
cg.Mult(B, X);
|
||||
|
||||
// 14. Recover the parallel grid function corresponding to X. This is the
|
||||
// local finite element solution on each processor.
|
||||
a.RecoverFEMSolution(X, b, x);
|
||||
|
||||
// 15. Save the refined mesh and the solution in parallel. This output can
|
||||
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
|
||||
pmesh.Save("mesh");
|
||||
x.Save("sol");
|
||||
|
||||
// 16. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
int num_procs = Mpi::WorldSize();
|
||||
int myid = Mpi::WorldRank();
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << pmesh << x << "keys Rjmm" << flush;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+2
-2
@@ -23,11 +23,11 @@ MFEM_LIB_FILE = mfem_is_not_built
|
||||
|
||||
SEQ_EXAMPLES = ex0 ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex14 ex15 ex16 \
|
||||
ex17 ex18 ex19 ex20 ex21 ex22 ex23 ex24 ex25 ex26 ex27 ex28 ex29 ex30 \
|
||||
ex31 ex33 ex34 ex36 ex37
|
||||
ex31 ex33 ex34 ex36 ex37 ex38 ex39
|
||||
PAR_EXAMPLES = ex0p ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex8p ex9p ex10p ex11p \
|
||||
ex12p ex13p ex14p ex15p ex16p ex17p ex18p ex19p ex20p ex21p ex22p ex24p \
|
||||
ex25p ex26p ex27p ex28p ex29p ex30p ex31p ex32p ex33p ex34p ex35p ex36p \
|
||||
ex37p
|
||||
ex37p ex39p
|
||||
SEQ_DEVICE_EXAMPLES = ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26 ex34
|
||||
PAR_DEVICE_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p \
|
||||
ex24p ex25p ex26p ex34p ex35p
|
||||
|
||||
@@ -36,6 +36,7 @@ list(APPEND SRCS
|
||||
list(APPEND HDRS
|
||||
annotation.hpp
|
||||
array.hpp
|
||||
arrays_by_name.hpp
|
||||
backends.hpp
|
||||
binaryio.hpp
|
||||
cuda.hpp
|
||||
|
||||
@@ -0,0 +1,291 @@
|
||||
// Copyright (c) 2010-2024, 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.
|
||||
|
||||
#ifndef MFEM_ARRAYS_BY_NAME
|
||||
#define MFEM_ARRAYS_BY_NAME
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "array.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/**
|
||||
Container class for storing arrays indexed by strings.
|
||||
|
||||
The Array<T> objects stored within this container must all be based on the
|
||||
same underlying generic type T, which must be a trivial type, see
|
||||
`std::is_trivial`.
|
||||
|
||||
In order to provide some level of protection against typos this class will
|
||||
not create new named arrays when access to unrecognized names is requested.
|
||||
New named arrays must be explicitly created using `CreateArray()`. To
|
||||
facilitate this behavior and avoid such errors the method `EntryExists()` is
|
||||
provided.
|
||||
|
||||
This container does not store pointers to pre-existing arrays. It will copy
|
||||
or move entries as appropriate from existing Array<T> objects into new
|
||||
Array<T> objects stored within this container.
|
||||
*/
|
||||
template <class T>
|
||||
class ArraysByName
|
||||
{
|
||||
protected:
|
||||
/// Reusing STL map iterators
|
||||
using container = std::map<std::string,Array<T> >;
|
||||
using iterator = typename container::iterator;
|
||||
using const_iterator = typename container::const_iterator;
|
||||
|
||||
/// Map containing the data sorted alphabetically by name
|
||||
container data;
|
||||
|
||||
public:
|
||||
|
||||
/// Default constructor
|
||||
ArraysByName() = default;
|
||||
|
||||
/// Copy constructor: deep copy from @a src
|
||||
ArraysByName(const ArraysByName &src) = default;
|
||||
|
||||
/// Move constructor
|
||||
ArraysByName(ArraysByName &&src) noexcept = default;
|
||||
|
||||
/// Return the number of named arrays in the container
|
||||
int Size() const { return data.size(); }
|
||||
|
||||
/// Return an STL set of strings giving the names of the arrays
|
||||
inline std::set<std::string> GetNames() const;
|
||||
|
||||
/// @brief Return true if an array with the given name is present in the
|
||||
/// container
|
||||
inline bool EntryExists(const std::string &name) const;
|
||||
|
||||
/// @brief Reference access to the named entry.
|
||||
///
|
||||
/// @note Passing a name for a nonexistent array will print an error
|
||||
/// message and halt execution. This is intended to call attention to
|
||||
/// possible typos or other errors. To handle such errors more gracefully
|
||||
/// consider first calling EntryExists.
|
||||
inline Array<T> &operator[](const std::string &name);
|
||||
|
||||
/// @brief Const reference access to the named entry.
|
||||
///
|
||||
/// @note Passing a name for a nonexistent array will print an error
|
||||
/// message and halt execution. This is intended to call attention to
|
||||
/// possible typos or other errors. To handle such errors more gracefully
|
||||
/// consider first calling EntryExists.
|
||||
inline const Array<T> &operator[](const std::string &name) const;
|
||||
|
||||
/// @brief Create a new empty array with the given name
|
||||
///
|
||||
/// @note Passing a name for an already existent array will print an error
|
||||
/// message and halt execution. This is intended to call attention to
|
||||
/// possible typos or other errors. To handle such errors more gracefully
|
||||
/// consider first calling EntryExists.
|
||||
inline Array<T> &CreateArray(const std::string &name);
|
||||
|
||||
/// Delete all named arrays from the container
|
||||
inline void DeleteAll();
|
||||
|
||||
/// @brief Delete the named array from the container
|
||||
///
|
||||
/// @note Passing a name for a nonexistent array will print an error
|
||||
/// message and halt execution. This is intended to call attention to
|
||||
/// possible typos or other errors. To handle such errors more gracefully
|
||||
/// consider first calling EntryExists.
|
||||
inline void DeleteArray(const std::string &name);
|
||||
|
||||
/// Copy assignment operator: deep copy from 'src'.
|
||||
ArraysByName<T> &operator=(const ArraysByName<T> &src) = default;
|
||||
|
||||
/// Move assignment operator
|
||||
ArraysByName<T> &operator=(ArraysByName<T> &&src) noexcept = default;
|
||||
|
||||
/// @brief Print the contents of the container to an output stream
|
||||
///
|
||||
/// @note Each array will be printed on at least three lines; the name on
|
||||
/// one line, the length of the associated array, lastly the array contents
|
||||
/// with @a width entries per line. A specific number of entries per line
|
||||
/// can be used by changing the @a width argument.
|
||||
inline void Print(std::ostream &out = mfem::out, int width = -1) const;
|
||||
|
||||
/// @brief Load the contents of the container from an input stream
|
||||
///
|
||||
/// @note This method will not first empty the container. First call
|
||||
/// DeleteAll if this behavior is needed.
|
||||
void Load(std::istream &in);
|
||||
|
||||
/// Sort each named array in the container
|
||||
inline void SortAll();
|
||||
|
||||
/// @brief Remove duplicates from each, previously sorted, named array
|
||||
///
|
||||
/// @note Identical entries may exist in multiple arrays but will only occur
|
||||
/// at most once in each array.
|
||||
inline void UniqueAll();
|
||||
|
||||
/// STL-like begin. Returns pointer to the first entry of the container.
|
||||
iterator begin() { return data.begin(); }
|
||||
|
||||
/// STL-like end. Returns pointer after the last entry of the container.
|
||||
iterator end() { return data.end(); }
|
||||
|
||||
/// @brief STL-like begin. Returns const pointer to the first entry of the
|
||||
/// container.
|
||||
const_iterator begin() const { return data.cbegin(); }
|
||||
|
||||
/// @brief STL-like end. Returns const pointer after the last entry of the
|
||||
/// container.
|
||||
const_iterator end() const { return data.cend(); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline bool operator==(const ArraysByName<T> &LHS, const ArraysByName<T> &RHS)
|
||||
{
|
||||
if ( LHS.Size() != RHS.Size() ) { return false; }
|
||||
for (auto it1 = LHS.begin(), it2 = RHS.begin();
|
||||
it1 != LHS.end() && it2 != RHS.end(); it1++, it2++)
|
||||
{
|
||||
if (it1->first != it2->first) { return false; }
|
||||
if (it1->second != it2->second) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline std::set<std::string> ArraysByName<T>::GetNames() const
|
||||
{
|
||||
std::set<std::string> names;
|
||||
for (auto const &entry : data)
|
||||
{
|
||||
names.insert(entry.first);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline bool ArraysByName<T>::EntryExists(const std::string &name) const
|
||||
{
|
||||
return data.find(name) != data.end();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline Array<T> &ArraysByName<T>::operator[](const std::string &name)
|
||||
{
|
||||
MFEM_VERIFY( data.find(name) != data.end(),
|
||||
"Access to unknown named array \"" << name << "\"");
|
||||
return data[name];
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline const Array<T> &ArraysByName<T>::operator[](const std::string &name)
|
||||
const
|
||||
{
|
||||
MFEM_VERIFY( data.find(name) != data.end(),
|
||||
"Access to unknown named array \"" << name << "\"");
|
||||
return data.at(name);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline Array<T> &ArraysByName<T>::CreateArray(const std::string &name)
|
||||
{
|
||||
MFEM_VERIFY( data.find(name) == data.end(),
|
||||
"Named array \"" << name << "\" already exists");
|
||||
Array<T> empty_array;
|
||||
data.insert(std::pair<std::string,Array<T> >(name,empty_array));
|
||||
return data[name];
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void ArraysByName<T>::DeleteAll()
|
||||
{
|
||||
data.clear();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void ArraysByName<T>::DeleteArray(const std::string &name)
|
||||
{
|
||||
MFEM_VERIFY( data.find(name) != data.end(),
|
||||
"Attempting to delete unknown named array \"" << name << "\"");
|
||||
data.erase(name);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void ArraysByName<T>::SortAll()
|
||||
{
|
||||
for (auto &a : data)
|
||||
{
|
||||
a.second.Sort();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void ArraysByName<T>::UniqueAll()
|
||||
{
|
||||
for (auto &a : data)
|
||||
{
|
||||
a.second.Unique();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void ArraysByName<T>::Print(std::ostream &os, int width) const
|
||||
{
|
||||
os << data.size() << '\n';
|
||||
for (auto const &it : data)
|
||||
{
|
||||
os << '"' << it.first << '"' << '\n' << it.second.Size() << '\n';
|
||||
it.second.Print(os, width > 0 ? width : it.second.Size());
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ArraysByName<T>::Load(std::istream &in)
|
||||
{
|
||||
int NumArrays;
|
||||
in >> NumArrays;
|
||||
|
||||
std::string ArrayLine, ArrayName;
|
||||
for (int i=0; i < NumArrays; i++)
|
||||
{
|
||||
in >> std::ws;
|
||||
getline(in, ArrayLine);
|
||||
|
||||
std::size_t q0 = ArrayLine.find('"');
|
||||
std::size_t q1 = ArrayLine.rfind('"');
|
||||
|
||||
if (q0 != std::string::npos && q1 > q0)
|
||||
{
|
||||
// Locate set name between first and last double quote
|
||||
ArrayName = ArrayLine.substr(q0+1,q1-q0-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no double quotes found locate set name using white space
|
||||
q1 = ArrayLine.find(' ');
|
||||
ArrayName = ArrayLine.substr(0,q1-1);
|
||||
}
|
||||
|
||||
// Ignore the remainder of the line which may contain explanatory comments
|
||||
data[ArrayName].Load(in, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
set(SRCS
|
||||
attribute_sets.cpp
|
||||
element.cpp
|
||||
gmsh.cpp
|
||||
hexahedron.cpp
|
||||
@@ -34,6 +35,7 @@ set(SRCS
|
||||
)
|
||||
|
||||
set(HDRS
|
||||
attribute_sets.hpp
|
||||
element.hpp
|
||||
gmsh.hpp
|
||||
hexahedron.hpp
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
// Copyright (c) 2010-2024, 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 "attribute_sets.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
AttributeSets::AttributeSets(const Array<int> &attr)
|
||||
: attributes(attr)
|
||||
{}
|
||||
|
||||
void AttributeSets::Copy(AttributeSets ©) const
|
||||
{
|
||||
copy.attr_sets = attr_sets;
|
||||
}
|
||||
|
||||
bool AttributeSets::SetsExist() const
|
||||
{
|
||||
return attr_sets.Size() > 0;
|
||||
}
|
||||
|
||||
std::set<std::string> AttributeSets::GetAttributeSetNames() const
|
||||
{
|
||||
return attr_sets.GetNames();
|
||||
}
|
||||
|
||||
bool AttributeSets::AttributeSetExists(const std::string &name) const
|
||||
{
|
||||
return attr_sets.EntryExists(name);
|
||||
}
|
||||
|
||||
Array<int> & AttributeSets::CreateAttributeSet(const std::string &set_name)
|
||||
{
|
||||
return attr_sets.CreateArray(set_name);
|
||||
}
|
||||
|
||||
void AttributeSets::DeleteAttributeSet(const std::string &set_name)
|
||||
{
|
||||
attr_sets.DeleteArray(set_name);
|
||||
}
|
||||
|
||||
void AttributeSets::SetAttributeSet(const std::string &set_name,
|
||||
const Array<int> &attr)
|
||||
{
|
||||
if (!attr_sets.EntryExists(set_name))
|
||||
{
|
||||
attr_sets.CreateArray(set_name);
|
||||
}
|
||||
attr_sets[set_name] = attr;
|
||||
attr_sets[set_name].Sort();
|
||||
attr_sets[set_name].Unique();
|
||||
}
|
||||
|
||||
void AttributeSets::AddToAttributeSet(const std::string &set_name, int attr)
|
||||
{
|
||||
attr_sets[set_name].Append(attr);
|
||||
attr_sets[set_name].Sort();
|
||||
attr_sets[set_name].Unique();
|
||||
}
|
||||
|
||||
void AttributeSets::AddToAttributeSet(const std::string &set_name,
|
||||
const Array<int> &attr)
|
||||
{
|
||||
attr_sets[set_name].Append(attr);
|
||||
attr_sets[set_name].Sort();
|
||||
attr_sets[set_name].Unique();
|
||||
}
|
||||
|
||||
void AttributeSets::RemoveFromAttributeSet(const std::string &set_name,
|
||||
int attr)
|
||||
{
|
||||
if (!attr_sets.EntryExists(set_name))
|
||||
{
|
||||
mfem::err << "Unrecognized attribute set name \"" << set_name
|
||||
<< "\" in AttributeSets::RemoveFromAttributeSet" << std::endl;
|
||||
}
|
||||
|
||||
Array<int> &attr_set = attr_sets[set_name];
|
||||
|
||||
attr_set.DeleteFirst(attr);
|
||||
}
|
||||
|
||||
void AttributeSets::Print(std::ostream &os, int width) const
|
||||
{
|
||||
attr_sets.Print(os, width > 0 ? width : def_width);
|
||||
}
|
||||
|
||||
Array<int> & AttributeSets::GetAttributeSet(const std::string & set_name)
|
||||
{
|
||||
return attr_sets[set_name];
|
||||
}
|
||||
|
||||
Array<int> AttributeSets::GetAttributeSetMarker(const std::string & set_name)
|
||||
{
|
||||
return AttrToMarker(attributes.Max(), GetAttributeSet(set_name));
|
||||
}
|
||||
|
||||
Array<int> AttributeSets::AttrToMarker(int max_attr, const Array<int> &attrs)
|
||||
{
|
||||
MFEM_ASSERT(attrs.Max() <= max_attr, "Invalid attribute number present.");
|
||||
|
||||
Array<int> marker(max_attr);
|
||||
marker = 0;
|
||||
for (auto const &attr : attrs)
|
||||
{
|
||||
MFEM_VERIFY(attr > 0, "Attribute number less than one!");
|
||||
marker[attr-1] = 1;
|
||||
}
|
||||
return marker;
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -0,0 +1,156 @@
|
||||
// Copyright (c) 2010-2024, 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.
|
||||
|
||||
#ifndef MFEM_ATTRIBUTE_SETS
|
||||
#define MFEM_ATTRIBUTE_SETS
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "../general/arrays_by_name.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
class AttributeSets
|
||||
{
|
||||
private:
|
||||
const Array<int> & attributes;
|
||||
|
||||
const int def_width = 10;
|
||||
|
||||
public:
|
||||
/// Named sets of attributes
|
||||
ArraysByName<int> attr_sets;
|
||||
|
||||
AttributeSets(const Array<int> &attr);
|
||||
|
||||
/// @brief Create a copy of the internal data to the provided @a copy.
|
||||
void Copy(AttributeSets ©) const;
|
||||
|
||||
/// @brief Return true if any named sets are currently defined
|
||||
bool SetsExist() const;
|
||||
|
||||
/// @brief Return all attribute set names as an STL set
|
||||
std::set<std::string> GetAttributeSetNames() const;
|
||||
|
||||
/// @brief Return true is the named attribute set is present
|
||||
bool AttributeSetExists(const std::string &name) const;
|
||||
|
||||
/// @brief Create an empty named attribute set
|
||||
Array<int> & CreateAttributeSet(const std::string &set_name);
|
||||
|
||||
/// @brief Delete a named attribute set
|
||||
void DeleteAttributeSet(const std::string &set_name);
|
||||
|
||||
/// @brief Create a new attribute set
|
||||
/**
|
||||
@param[in] set_name The name of the new set
|
||||
@param[in] attr An array of attribute numbers making up the new set
|
||||
|
||||
@note If an attribute set matching this name already exists, that set
|
||||
will be replaced with this new attribute set.
|
||||
|
||||
@note The attribute numbers are not checked for validity or
|
||||
existence within the mesh.
|
||||
*/
|
||||
void SetAttributeSet(const std::string &set_name, const Array<int> &attr);
|
||||
|
||||
/// @brief Add a single entry to an existing attribute set
|
||||
/**
|
||||
@param[in] set_name The name of the set being augmented
|
||||
@param[in] attr A single attribute number to be inserted in the set
|
||||
|
||||
@note If the named set does not exist an error message will be printed
|
||||
and execution will halt. `AttributeSetExists()` may be used to verify
|
||||
existence of a named set.
|
||||
@note Duplicate entries will be ignored and the resulting sets will be
|
||||
sorted.
|
||||
*/
|
||||
void AddToAttributeSet(const std::string &set_name, int attr);
|
||||
|
||||
/// @brief Add an array of entries to an existing attribute set
|
||||
/**
|
||||
@param[in] set_name The name of the set being augmented
|
||||
@param[in] attr Array of attribute numbers to be inserted in the set
|
||||
|
||||
@note If the named set does not exist an error message will be printed
|
||||
and execution will halt. `AttributeSetExists()` may be used to verify
|
||||
existence of a named set.
|
||||
@note Duplicate entries will be ignored and the resulting sets will be
|
||||
sorted.
|
||||
*/
|
||||
void AddToAttributeSet(const std::string &set_name, const Array<int> &attr);
|
||||
|
||||
/// @brief Remove a single entry from an existing attribute set
|
||||
/**
|
||||
@param[in] set_name The name of the set being modified
|
||||
@param[in] attr A single attribute number to be removed from the set
|
||||
|
||||
@note If the named set does not exist an error message will be printed
|
||||
and execution will halt. `AttributeSetExists()` may be used to verify
|
||||
existence of a named set.
|
||||
@note If @a attr is not a member of the named set the set will not
|
||||
be modified and no error will occur.
|
||||
*/
|
||||
void RemoveFromAttributeSet(const std::string &set_name, int attr);
|
||||
|
||||
/// @brief Print the contents of the container to an output stream
|
||||
///
|
||||
/// @note The array entries will contain 10 entries per line. A specific
|
||||
/// number of entries per line can be used by changing the @a width argument.
|
||||
void Print(std::ostream &out = mfem::out, int width = -1) const;
|
||||
|
||||
/// @brief Access a named attribute set
|
||||
/**
|
||||
@param[in] set_name The name of the set being accessed
|
||||
|
||||
@note If the named set does not exist an error message will be printed
|
||||
and execution will halt. `AttributeSetExists()` may be used to verify
|
||||
existence of a named set.
|
||||
|
||||
@note The reference returned by this method can be invalidated by
|
||||
subsequent calls to SetAttributeSet, ClearAttributeSet, or
|
||||
RemoveFromAttributeSet. AddToAttributeSet should not invalidate this
|
||||
reference.
|
||||
*/
|
||||
Array<int> & GetAttributeSet(const std::string & set_name);
|
||||
|
||||
/// @brief Return a marker array corresponding to a named attribute set
|
||||
/**
|
||||
@param[in] set_name The name of the set being accessed
|
||||
|
||||
@note If the named set does not exist an error message will be printed
|
||||
and execution will halt. `AttributeSetExists()` may be used to verify
|
||||
existence of a named set.
|
||||
*/
|
||||
Array<int> GetAttributeSetMarker(const std::string & set_name);
|
||||
|
||||
/// @brief Prepares a marker array corresponding to an array of element
|
||||
/// attributes
|
||||
/**
|
||||
@param[in] max_attr Number of entries to create in the @a marker array
|
||||
@param[in] attrs An array of attribute numbers which should be
|
||||
activated
|
||||
|
||||
The returned marker array will be of size @a max_attr and it will contain
|
||||
only zeroes and ones. Ones indicate which attribute numbers are present
|
||||
in the @a attrs array.
|
||||
*/
|
||||
static Array<int> AttrToMarker(int max_attr, const Array<int> &attrs);
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
+37
-5
@@ -4084,6 +4084,7 @@ void Mesh::Make1D(int n, real_t sx)
|
||||
}
|
||||
|
||||
Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
|
||||
: attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
|
||||
{
|
||||
Dim = mesh.Dim;
|
||||
spaceDim = mesh.spaceDim;
|
||||
@@ -4157,6 +4158,10 @@ Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
|
||||
mesh.attributes.Copy(attributes);
|
||||
mesh.bdr_attributes.Copy(bdr_attributes);
|
||||
|
||||
// Copy attribute and bdr_attribute names
|
||||
mesh.attribute_sets.Copy(attribute_sets);
|
||||
mesh.bdr_attribute_sets.Copy(bdr_attribute_sets);
|
||||
|
||||
// Deep copy the NURBSExtension.
|
||||
#ifdef MFEM_USE_MPI
|
||||
ParNURBSExtension *pNURBSext =
|
||||
@@ -4300,6 +4305,7 @@ Mesh Mesh::MakeRefined(Mesh &orig_mesh, const Array<int> &ref_factors,
|
||||
|
||||
Mesh::Mesh(const std::string &filename, int generate_edges, int refine,
|
||||
bool fix_orientation)
|
||||
: attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
|
||||
{
|
||||
// Initialization as in the default constructor
|
||||
SetEmpty();
|
||||
@@ -4318,6 +4324,7 @@ Mesh::Mesh(const std::string &filename, int generate_edges, int refine,
|
||||
|
||||
Mesh::Mesh(std::istream &input, int generate_edges, int refine,
|
||||
bool fix_orientation)
|
||||
: attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
|
||||
{
|
||||
SetEmpty();
|
||||
Load(input, generate_edges, refine, fix_orientation);
|
||||
@@ -4353,6 +4360,7 @@ Mesh::Mesh(real_t *vertices_, int num_vertices,
|
||||
int *boundary_indices, Geometry::Type boundary_type,
|
||||
int *boundary_attributes, int num_boundary_elements,
|
||||
int dimension, int space_dimension)
|
||||
: attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
|
||||
{
|
||||
if (space_dimension == -1)
|
||||
{
|
||||
@@ -4536,6 +4544,7 @@ void Mesh::Loader(std::istream &input, int generate_edges,
|
||||
int mfem_version = 0;
|
||||
if (mesh_type == "MFEM mesh v1.0") { mfem_version = 10; } // serial
|
||||
else if (mesh_type == "MFEM mesh v1.2") { mfem_version = 12; } // parallel
|
||||
else if (mesh_type == "MFEM mesh v1.3") { mfem_version = 13; } // attr sets
|
||||
|
||||
// MFEM nonconforming mesh format
|
||||
// (NOTE: previous v1.1 is now under this branch for backward compatibility)
|
||||
@@ -4549,7 +4558,7 @@ void Mesh::Loader(std::istream &input, int generate_edges,
|
||||
// section in the stream. A user provided parse tag can also be provided
|
||||
// via the arguments. For example, if this is called from parallel mesh
|
||||
// object, it can indicate to read until parallel mesh section begins.
|
||||
if (mfem_version == 12 && parse_tag.empty())
|
||||
if (mfem_version >= 12 && parse_tag.empty())
|
||||
{
|
||||
parse_tag = "mfem_mesh_end";
|
||||
}
|
||||
@@ -4707,7 +4716,7 @@ void Mesh::Loader(std::istream &input, int generate_edges,
|
||||
|
||||
// If a parse tag was supplied, keep reading the stream until the tag is
|
||||
// encountered.
|
||||
if (mfem_version == 12)
|
||||
if (mfem_version >= 12)
|
||||
{
|
||||
string line;
|
||||
do
|
||||
@@ -4737,6 +4746,7 @@ void Mesh::Loader(std::istream &input, int generate_edges,
|
||||
}
|
||||
|
||||
Mesh::Mesh(Mesh *mesh_array[], int num_pieces)
|
||||
: attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
|
||||
{
|
||||
int i, j, ie, ib, iv, *v, nv;
|
||||
Element *el;
|
||||
@@ -4879,6 +4889,7 @@ Mesh::Mesh(Mesh *mesh_array[], int num_pieces)
|
||||
}
|
||||
|
||||
Mesh::Mesh(Mesh *orig_mesh, int ref_factor, int ref_type)
|
||||
: attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
|
||||
{
|
||||
Array<int> ref_factors(orig_mesh->GetNE());
|
||||
ref_factors = ref_factor;
|
||||
@@ -10349,6 +10360,7 @@ void Mesh::InitFromNCMesh(const NCMesh &ncmesh_)
|
||||
}
|
||||
|
||||
Mesh::Mesh(const NCMesh &ncmesh_)
|
||||
: attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
|
||||
{
|
||||
Init();
|
||||
InitTables();
|
||||
@@ -11332,8 +11344,16 @@ void Mesh::Printer(std::ostream &os, std::string section_delimiter,
|
||||
}
|
||||
|
||||
// serial/parallel conforming mesh format
|
||||
os << (section_delimiter.empty()
|
||||
? "MFEM mesh v1.0\n" : "MFEM mesh v1.2\n");
|
||||
const bool set_names = attribute_sets.SetsExist() ||
|
||||
bdr_attribute_sets.SetsExist();
|
||||
os << (!set_names && section_delimiter.empty()
|
||||
? "MFEM mesh v1.0\n" :
|
||||
(!set_names ? "MFEM mesh v1.2\n" : "MFEM mesh v1.3\n"));
|
||||
|
||||
if (set_names && section_delimiter.empty())
|
||||
{
|
||||
section_delimiter = "mfem_mesh_end";
|
||||
}
|
||||
|
||||
// optional
|
||||
if (!comments.empty()) { os << '\n' << comments << '\n'; }
|
||||
@@ -11358,12 +11378,24 @@ void Mesh::Printer(std::ostream &os, std::string section_delimiter,
|
||||
PrintElement(elements[i], os);
|
||||
}
|
||||
|
||||
if (set_names)
|
||||
{
|
||||
os << "\nattribute_sets\n";
|
||||
attribute_sets.Print(os);
|
||||
}
|
||||
|
||||
os << "\nboundary\n" << NumOfBdrElements << '\n';
|
||||
for (i = 0; i < NumOfBdrElements; i++)
|
||||
{
|
||||
PrintElement(boundary[i], os);
|
||||
}
|
||||
|
||||
if (set_names)
|
||||
{
|
||||
os << "\nbdr_attribute_sets\n";
|
||||
bdr_attribute_sets.Print(os);
|
||||
}
|
||||
|
||||
os << "\nvertices\n" << NumOfVertices << '\n';
|
||||
if (Nodes == NULL)
|
||||
{
|
||||
@@ -11387,7 +11419,7 @@ void Mesh::Printer(std::ostream &os, std::string section_delimiter,
|
||||
|
||||
if (!section_delimiter.empty())
|
||||
{
|
||||
os << section_delimiter << endl; // only with format v1.2
|
||||
os << section_delimiter << endl; // only with formats v1.2 and above
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-1
@@ -15,6 +15,7 @@
|
||||
#include "../config/config.hpp"
|
||||
#include "../general/stable3d.hpp"
|
||||
#include "../general/globals.hpp"
|
||||
#include "attribute_sets.hpp"
|
||||
#include "triangle.hpp"
|
||||
#include "tetrahedron.hpp"
|
||||
#include "vertex.hpp"
|
||||
@@ -277,6 +278,12 @@ public:
|
||||
/// A list of all unique boundary attributes used by the Mesh.
|
||||
Array<int> bdr_attributes;
|
||||
|
||||
/// Named sets of element attributes
|
||||
AttributeSets attribute_sets;
|
||||
|
||||
/// Named sets of boundary element attributes
|
||||
AttributeSets bdr_attribute_sets;
|
||||
|
||||
NURBSExtension *NURBSext; ///< Optional NURBS mesh extension.
|
||||
NCMesh *ncmesh; ///< Optional nonconforming mesh extension.
|
||||
Array<GeometricFactors*> geom_factors; ///< Optional geometric factors.
|
||||
@@ -632,7 +639,8 @@ public:
|
||||
/// a variety of common forms. For more specialized constructors see
|
||||
/// @ref mfem_Mesh_named_ctors "Named mesh constructors".
|
||||
/// @{
|
||||
Mesh() { SetEmpty(); }
|
||||
Mesh() : attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
|
||||
{ SetEmpty(); }
|
||||
|
||||
/** Copy constructor. Performs a deep copy of (almost) all data, so that the
|
||||
source mesh can be modified (e.g. deleted, refined) without affecting the
|
||||
@@ -674,6 +682,7 @@ public:
|
||||
themselves can later be added using methods from the
|
||||
@ref mfem_Mesh_construction "Mesh construction" group. */
|
||||
Mesh(int Dim_, int NVert, int NElem, int NBdrElem = 0, int spaceDim_ = -1)
|
||||
: attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
|
||||
{
|
||||
if (spaceDim_ == -1) { spaceDim_ = Dim_; }
|
||||
InitMesh(Dim_, spaceDim_, NVert, NElem, NBdrElem);
|
||||
@@ -1110,6 +1119,7 @@ public:
|
||||
Mesh(int nx, int ny, int nz, Element::Type type, bool generate_edges = false,
|
||||
real_t sx = 1.0, real_t sy = 1.0, real_t sz = 1.0,
|
||||
bool sfc_ordering = true)
|
||||
: attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
|
||||
{
|
||||
Make3D(nx, ny, nz, type, sx, sy, sz, sfc_ordering);
|
||||
Finalize(true); // refine = true
|
||||
@@ -1119,6 +1129,7 @@ public:
|
||||
MFEM_DEPRECATED
|
||||
Mesh(int nx, int ny, Element::Type type, bool generate_edges = false,
|
||||
real_t sx = 1.0, real_t sy = 1.0, bool sfc_ordering = true)
|
||||
: attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
|
||||
{
|
||||
Make2D(nx, ny, type, sx, sy, generate_edges, sfc_ordering);
|
||||
Finalize(true); // refine = true
|
||||
@@ -1127,6 +1138,7 @@ public:
|
||||
/// Deprecated: see @a MakeCartesian1D.
|
||||
MFEM_DEPRECATED
|
||||
explicit Mesh(int n, real_t sx = 1.0)
|
||||
: attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
|
||||
{
|
||||
Make1D(n, sx);
|
||||
// Finalize(); // reminder: not needed
|
||||
|
||||
+88
-2
@@ -38,8 +38,8 @@ bool Mesh::remove_unused_vertices = true;
|
||||
|
||||
void Mesh::ReadMFEMMesh(std::istream &input, int version, int &curved)
|
||||
{
|
||||
// Read MFEM mesh v1.0 or v1.2 format
|
||||
MFEM_VERIFY(version == 10 || version == 12,
|
||||
// Read MFEM mesh v1.0, v1.2, or v1.3 format
|
||||
MFEM_VERIFY(version == 10 || version == 12 || version == 13,
|
||||
"unknown MFEM mesh version");
|
||||
|
||||
string ident;
|
||||
@@ -62,6 +62,18 @@ void Mesh::ReadMFEMMesh(std::istream &input, int version, int &curved)
|
||||
elements[j] = ReadElement(input);
|
||||
}
|
||||
|
||||
if (version == 13)
|
||||
{
|
||||
skip_comment_lines(input, '#');
|
||||
input >> ident; // 'attribute_sets'
|
||||
|
||||
MFEM_VERIFY(ident == "attribute_sets", "invalid mesh file");
|
||||
|
||||
attribute_sets.attr_sets.Load(input);
|
||||
attribute_sets.attr_sets.SortAll();
|
||||
attribute_sets.attr_sets.UniqueAll();
|
||||
}
|
||||
|
||||
skip_comment_lines(input, '#');
|
||||
input >> ident; // 'boundary'
|
||||
|
||||
@@ -73,6 +85,18 @@ void Mesh::ReadMFEMMesh(std::istream &input, int version, int &curved)
|
||||
boundary[j] = ReadElement(input);
|
||||
}
|
||||
|
||||
if (version == 13)
|
||||
{
|
||||
skip_comment_lines(input, '#');
|
||||
input >> ident; // 'bdr_attribute_sets'
|
||||
|
||||
MFEM_VERIFY(ident == "bdr_attribute_sets", "invalid mesh file");
|
||||
|
||||
bdr_attribute_sets.attr_sets.Load(input);
|
||||
bdr_attribute_sets.attr_sets.SortAll();
|
||||
bdr_attribute_sets.attr_sets.UniqueAll();
|
||||
}
|
||||
|
||||
skip_comment_lines(input, '#');
|
||||
input >> ident; // 'vertices'
|
||||
|
||||
@@ -1513,6 +1537,12 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
// starting from 1, not 0)
|
||||
map<int, int> vertices_map;
|
||||
|
||||
// A map containing names of physical curves, surfaces, and volumes.
|
||||
// The first index is the dimension of the physical manifold, the second
|
||||
// index is the element attribute number of the set, and the string is
|
||||
// the assigned name.
|
||||
map<int,map<int,std::string> > phys_names_by_dim;
|
||||
|
||||
// Gmsh always outputs coordinates in 3D, but MFEM distinguishes between the
|
||||
// mesh element dimension (Dim) and the dimension of the space in which the
|
||||
// mesh is embedded (spaceDim). For example, a 2D MFEM mesh has Dim = 2 and
|
||||
@@ -2637,6 +2667,38 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
MFEM_CONTRACT_VAR(elem_domain);
|
||||
|
||||
} // section '$Elements'
|
||||
else if (buff == "$PhysicalNames") // Named element sets
|
||||
{
|
||||
int num_names = 0;
|
||||
int mdim,num;
|
||||
string name;
|
||||
input >> num_names;
|
||||
for (int i=0; i < num_names; i++)
|
||||
{
|
||||
input >> mdim >> num;
|
||||
getline(input, name);
|
||||
|
||||
// Trim leading white space
|
||||
while (!name.empty() &&
|
||||
(*name.begin() == ' ' || *name.begin() == '\t'))
|
||||
{ name.erase(0,1);}
|
||||
|
||||
// Trim trailing white space
|
||||
while (!name.empty() &&
|
||||
(*name.rbegin() == ' ' || *name.rbegin() == '\t' ||
|
||||
*name.rbegin() == '\n' || *name.rbegin() == '\r'))
|
||||
{ name.resize(name.length()-1);}
|
||||
|
||||
// Remove enclosing quotes
|
||||
if ( (*name.begin() == '"' || *name.begin() == '\'') &&
|
||||
(*name.rbegin() == '"' || *name.rbegin() == '\''))
|
||||
{
|
||||
name = name.substr(1,name.length()-2);
|
||||
}
|
||||
|
||||
phys_names_by_dim[mdim][num] = name;
|
||||
}
|
||||
}
|
||||
else if (buff == "$Periodic") // Reading master/slave node pairs
|
||||
{
|
||||
curved = 1;
|
||||
@@ -2736,6 +2798,30 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
}
|
||||
} // we reach the end of the file
|
||||
|
||||
// Process set names
|
||||
if (phys_names_by_dim.size() > 0)
|
||||
{
|
||||
// Process boundary attribute set names
|
||||
for (auto const &bdr_attr : phys_names_by_dim[Dim-1])
|
||||
{
|
||||
if (!bdr_attribute_sets.AttributeSetExists(bdr_attr.second))
|
||||
{
|
||||
bdr_attribute_sets.CreateAttributeSet(bdr_attr.second);
|
||||
}
|
||||
bdr_attribute_sets.AddToAttributeSet(bdr_attr.second, bdr_attr.first);
|
||||
}
|
||||
|
||||
// Process element attribute set names
|
||||
for (auto const &attr : phys_names_by_dim[Dim])
|
||||
{
|
||||
if (!attribute_sets.AttributeSetExists(attr.second))
|
||||
{
|
||||
attribute_sets.CreateAttributeSet(attr.second);
|
||||
}
|
||||
attribute_sets.AddToAttributeSet(attr.second, attr.first);
|
||||
}
|
||||
}
|
||||
|
||||
this->RemoveUnusedVertices();
|
||||
if (periodic)
|
||||
{
|
||||
|
||||
+42
-1
@@ -145,6 +145,10 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
|
||||
mesh.attributes.Copy(attributes);
|
||||
mesh.bdr_attributes.Copy(bdr_attributes);
|
||||
|
||||
// Copy attribute and bdr_attribute names
|
||||
mesh.attribute_sets.Copy(attribute_sets);
|
||||
mesh.bdr_attribute_sets.Copy(bdr_attribute_sets);
|
||||
|
||||
GenerateNCFaceInfo();
|
||||
}
|
||||
else // mesh.Conforming()
|
||||
@@ -181,6 +185,10 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
|
||||
mesh.attributes.Copy(attributes);
|
||||
mesh.bdr_attributes.Copy(bdr_attributes);
|
||||
|
||||
// Copy attribute and bdr_attribute names
|
||||
mesh.attribute_sets.Copy(attribute_sets);
|
||||
mesh.bdr_attribute_sets.Copy(bdr_attribute_sets);
|
||||
|
||||
NumOfEdges = NumOfFaces = 0;
|
||||
|
||||
if (Dim > 1)
|
||||
@@ -3918,6 +3926,10 @@ void ParMesh::NonconformingRefinement(const Array<Refinement> &refinements,
|
||||
attributes.Copy(pmesh2->attributes);
|
||||
bdr_attributes.Copy(pmesh2->bdr_attributes);
|
||||
|
||||
// Copy attribute and bdr_attribute names
|
||||
attribute_sets.Copy(pmesh2->attribute_sets);
|
||||
bdr_attribute_sets.Copy(pmesh2->bdr_attribute_sets);
|
||||
|
||||
// now swap the meshes, the second mesh will become the old coarse mesh
|
||||
// and this mesh will be the new fine mesh
|
||||
Mesh::Swap(*pmesh2, false);
|
||||
@@ -3976,6 +3988,10 @@ bool ParMesh::NonconformingDerefinement(Array<real_t> &elem_error,
|
||||
attributes.Copy(mesh2->attributes);
|
||||
bdr_attributes.Copy(mesh2->bdr_attributes);
|
||||
|
||||
// Copy attribute and bdr_attribute names
|
||||
attribute_sets.Copy(mesh2->attribute_sets);
|
||||
bdr_attribute_sets.Copy(mesh2->bdr_attribute_sets);
|
||||
|
||||
Mesh::Swap(*mesh2, false);
|
||||
delete mesh2;
|
||||
|
||||
@@ -4027,6 +4043,10 @@ void ParMesh::RebalanceImpl(const Array<int> *partition)
|
||||
attributes.Copy(pmesh2->attributes);
|
||||
bdr_attributes.Copy(pmesh2->bdr_attributes);
|
||||
|
||||
// Copy attribute and bdr_attribute names
|
||||
attribute_sets.Copy(pmesh2->attribute_sets);
|
||||
bdr_attribute_sets.Copy(pmesh2->bdr_attribute_sets);
|
||||
|
||||
Mesh::Swap(*pmesh2, false);
|
||||
delete pmesh2;
|
||||
|
||||
@@ -4825,7 +4845,10 @@ void ParMesh::Print(std::ostream &os, const std::string &comments) const
|
||||
}
|
||||
}
|
||||
|
||||
os << "MFEM mesh v1.0\n";
|
||||
const bool set_names = attribute_sets.SetsExist() ||
|
||||
bdr_attribute_sets.SetsExist();
|
||||
|
||||
os << (!set_names ? "MFEM mesh v1.0\n" : "MFEM mesh v1.3\n");
|
||||
|
||||
if (!comments.empty()) { os << '\n' << comments << '\n'; }
|
||||
|
||||
@@ -4848,6 +4871,12 @@ void ParMesh::Print(std::ostream &os, const std::string &comments) const
|
||||
PrintElement(elements[i], os);
|
||||
}
|
||||
|
||||
if (set_names)
|
||||
{
|
||||
os << "\nattribute_sets\n";
|
||||
attribute_sets.Print(os);
|
||||
}
|
||||
|
||||
int num_bdr_elems = NumOfBdrElements;
|
||||
if (print_shared && Dim > 1)
|
||||
{
|
||||
@@ -4876,6 +4905,13 @@ void ParMesh::Print(std::ostream &os, const std::string &comments) const
|
||||
PrintElement(faces[(*s2l_face)[i]], os);
|
||||
}
|
||||
}
|
||||
|
||||
if (set_names)
|
||||
{
|
||||
os << "\nbdr_attribute_sets\n";
|
||||
bdr_attribute_sets.Print(os);
|
||||
}
|
||||
|
||||
os << "\nvertices\n" << NumOfVertices << '\n';
|
||||
if (Nodes == NULL)
|
||||
{
|
||||
@@ -4896,6 +4932,11 @@ void ParMesh::Print(std::ostream &os, const std::string &comments) const
|
||||
os << "\nnodes\n";
|
||||
Nodes->Save(os);
|
||||
}
|
||||
|
||||
if (set_names)
|
||||
{
|
||||
os << "mfem_mesh_end\n";
|
||||
}
|
||||
}
|
||||
|
||||
void ParMesh::Save(const std::string &fname, int precision) const
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "general/error.hpp"
|
||||
#include "general/device.hpp"
|
||||
#include "general/array.hpp"
|
||||
#include "general/arrays_by_name.hpp"
|
||||
#include "general/sets.hpp"
|
||||
#include "general/hash.hpp"
|
||||
#include "general/mem_alloc.hpp"
|
||||
|
||||
@@ -18,6 +18,7 @@ include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
# for d in general linalg mesh fem enzyme; do ls -1 $d/*.cpp; done
|
||||
set(UNIT_TESTS_SRCS
|
||||
general/test_array.cpp
|
||||
general/test_arrays_by_name.cpp
|
||||
general/test_error.cpp
|
||||
general/test_mem.cpp
|
||||
general/test_text.cpp
|
||||
|
||||
@@ -25,3 +25,46 @@ TEST_CASE("Array init-list construction", "[Array]")
|
||||
REQUIRE(a[i] == b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Array entry sorting", "[Array]")
|
||||
{
|
||||
int ContigData[6] = {6, 5, 4, 3, 2, 1};
|
||||
Array<int> a(ContigData, 6);
|
||||
Array<int> b({1, 2, 3, 3, 2, 1});
|
||||
|
||||
a.Sort();
|
||||
b.Sort();
|
||||
|
||||
for (int i = 1; i < a.Size(); i++)
|
||||
{
|
||||
REQUIRE(a[i] >= a[i-1]);
|
||||
}
|
||||
|
||||
for (int i = 1; i < b.Size(); i++)
|
||||
{
|
||||
REQUIRE(b[i] >= b[i-1]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Array entry strict sorting", "[Array]")
|
||||
{
|
||||
int ContigData[6] = {6, 1, 4, 1, 2, 1};
|
||||
Array<int> a(ContigData, 6);
|
||||
Array<int> b({1, 2, 3, 3, 2, 1});
|
||||
|
||||
a.Sort();
|
||||
b.Sort();
|
||||
|
||||
a.Unique();
|
||||
b.Unique();
|
||||
|
||||
for (int i = 1; i < a.Size(); i++)
|
||||
{
|
||||
REQUIRE(a[i] > a[i-1]);
|
||||
}
|
||||
|
||||
for (int i = 1; i < b.Size(); i++)
|
||||
{
|
||||
REQUIRE(b[i] > b[i-1]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
// Copyright (c) 2010-2024, 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 "mfem.hpp"
|
||||
#include "unit_tests.hpp"
|
||||
|
||||
using namespace mfem;
|
||||
|
||||
void FillArraysByName(ArraysByName<int> &abn)
|
||||
{
|
||||
abn.CreateArray("1 potato");
|
||||
abn.CreateArray("2 potato");
|
||||
abn.CreateArray("3 potato");
|
||||
abn.CreateArray("four");
|
||||
|
||||
Array<int> a3({2, 4, 6});
|
||||
int ContigData[4] = {4, 3, 2, 1};
|
||||
Array<int> a4(ContigData, 4);
|
||||
|
||||
abn["1 potato"].SetSize(1); abn["1 potato"][0] = 100;
|
||||
abn["2 potato"].Append(5); abn["2 potato"].Append(10);
|
||||
abn["3 potato"] = a3;
|
||||
abn["four"] = a4;
|
||||
}
|
||||
|
||||
void FillNonUniqueArraysByName(ArraysByName<int> &abn)
|
||||
{
|
||||
abn.CreateArray("1 potato");
|
||||
abn.CreateArray("2 potato");
|
||||
abn.CreateArray("3 potato");
|
||||
abn.CreateArray("four");
|
||||
|
||||
Array<int> a3({2, 4, 6, 4, 2});
|
||||
int ContigData[6] = {4, 3, 3, 2, 1, 1};
|
||||
Array<int> a4(ContigData, 6);
|
||||
|
||||
abn["1 potato"].SetSize(3); abn["1 potato"] = 100;
|
||||
abn["2 potato"].Append(5); abn["2 potato"].Append(10);
|
||||
abn["2 potato"].Append(5); abn["2 potato"].Append(10);
|
||||
abn["3 potato"] = a3;
|
||||
abn["four"] = a4;
|
||||
}
|
||||
|
||||
TEST_CASE("ArraysByName range-based for loop", "[ArraysByName]")
|
||||
{
|
||||
ArraysByName<int> abn;
|
||||
|
||||
FillArraysByName(abn);
|
||||
|
||||
// Test standard Iterator
|
||||
int i = 1;
|
||||
for (auto a : abn)
|
||||
{
|
||||
REQUIRE(a.second.Size() == i);
|
||||
i++;
|
||||
}
|
||||
|
||||
// Test ConstIterator
|
||||
const ArraysByName<int> &abnc = abn;
|
||||
i = 1;
|
||||
for (auto a : abnc)
|
||||
{
|
||||
REQUIRE(a.second.Size() == i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("ArraysByName Copy Methods", "[ArraysByName]")
|
||||
{
|
||||
ArraysByName<int> abn;
|
||||
|
||||
FillArraysByName(abn);
|
||||
|
||||
// Explicit call to copy constructor
|
||||
ArraysByName<int> abn_copy1(abn);
|
||||
REQUIRE(abn == abn_copy1);
|
||||
|
||||
// Implicit call to copy constructor
|
||||
ArraysByName<int> abn_copy2 = abn;
|
||||
REQUIRE(abn == abn_copy2);
|
||||
|
||||
// Copy assignment operator
|
||||
ArraysByName<int> abn_copy3;
|
||||
abn_copy3 = abn;
|
||||
REQUIRE(abn == abn_copy3);
|
||||
|
||||
// Explicit call to move constructor
|
||||
ArraysByName<int> abn_copy4a(abn);
|
||||
ArraysByName<int> abn_copy4b(std::move(abn_copy4a));
|
||||
REQUIRE(abn == abn_copy4b);
|
||||
|
||||
// Implicit call to move constructor
|
||||
ArraysByName<int> abn_copy5a(abn);
|
||||
ArraysByName<int> abn_copy5b = std::move(abn_copy5a);
|
||||
REQUIRE(abn == abn_copy5b);
|
||||
|
||||
// Move assignment operator
|
||||
ArraysByName<int> abn_copy6a(abn);
|
||||
ArraysByName<int> abn_copy6b;
|
||||
abn_copy6b = std::move(abn_copy6a);
|
||||
REQUIRE(abn == abn_copy6b);
|
||||
}
|
||||
|
||||
TEST_CASE("ArraysByName Various Methods", "[ArraysByName]")
|
||||
{
|
||||
ArraysByName<int> abn;
|
||||
|
||||
FillArraysByName(abn);
|
||||
|
||||
// Get set names and verify that they are valid
|
||||
std::set<std::string> names = abn.GetNames();
|
||||
REQUIRE(abn.Size() == (int)names.size());
|
||||
|
||||
for (auto name : names)
|
||||
{
|
||||
REQUIRE(abn.EntryExists(name));
|
||||
}
|
||||
|
||||
// Check for existence (or not) of specific named sets
|
||||
REQUIRE(abn.EntryExists("1 potato"));
|
||||
REQUIRE(abn.EntryExists("2 potato"));
|
||||
REQUIRE(abn.EntryExists("3 potato"));
|
||||
REQUIRE(abn.EntryExists("four"));
|
||||
REQUIRE(!abn.EntryExists("5 potato"));
|
||||
|
||||
abn.CreateArray("5 potato");
|
||||
REQUIRE(abn.EntryExists("5 potato"));
|
||||
|
||||
abn.DeleteArray("5 potato");
|
||||
REQUIRE(!abn.EntryExists("5 potato"));
|
||||
|
||||
abn.DeleteAll();
|
||||
REQUIRE(!abn.EntryExists("1 potato"));
|
||||
REQUIRE(!abn.EntryExists("2 potato"));
|
||||
REQUIRE(!abn.EntryExists("3 potato"));
|
||||
REQUIRE(!abn.EntryExists("four"));
|
||||
REQUIRE(!abn.EntryExists("5 potato"));
|
||||
REQUIRE(abn.Size() == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("ArraysByName Sort/Unique Methods", "[ArraysByName]")
|
||||
{
|
||||
ArraysByName<int> abn;
|
||||
|
||||
FillNonUniqueArraysByName(abn);
|
||||
|
||||
// Verify sizes
|
||||
int i = 1;
|
||||
for (auto a : abn)
|
||||
{
|
||||
REQUIRE(a.second.Size() == i + 2);
|
||||
i++;
|
||||
}
|
||||
|
||||
// Sort entries
|
||||
abn.SortAll();
|
||||
|
||||
// Re-Verify sizes
|
||||
i = 1;
|
||||
for (auto a : abn)
|
||||
{
|
||||
REQUIRE(a.second.Size() == i + 2);
|
||||
i++;
|
||||
}
|
||||
|
||||
// Verify sorting
|
||||
for (auto a : abn)
|
||||
{
|
||||
for (int j=1; j<a.second.Size(); j++)
|
||||
{
|
||||
REQUIRE(a.second[j] >= a.second[j-1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove duplicates
|
||||
abn.UniqueAll();
|
||||
|
||||
// Verify new sizes
|
||||
i = 1;
|
||||
for (auto a : abn)
|
||||
{
|
||||
REQUIRE(a.second.Size() == i);
|
||||
i++;
|
||||
}
|
||||
|
||||
// Verify strict sorting
|
||||
for (auto a : abn)
|
||||
{
|
||||
for (int j=1; j<a.second.Size(); j++)
|
||||
{
|
||||
REQUIRE(a.second[j] > a.second[j-1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-8
@@ -31,6 +31,7 @@ SOURCE_FILES := $(filter-out \
|
||||
$(CEED_SOURCE_FILES) $(MINI_SOURCE_FILES), $(SOURCE_FILES))
|
||||
HEADER_FILES = $(SRC)catch.hpp $(SRC)unit_tests.hpp
|
||||
OBJECT_FILES = $(SOURCE_FILES:$(SRC)%.cpp=%.o)
|
||||
LIBTESTS_O = libtests.o
|
||||
DATA_DIR = data
|
||||
|
||||
SEQ_MAIN_OBJ = unit_test_main.o
|
||||
@@ -105,17 +106,17 @@ all: $(UNIT_TESTS)
|
||||
.SUFFIXES: .cpp .o
|
||||
.PHONY: all clean
|
||||
|
||||
unit_tests: $(SEQ_MAIN_OBJ) $(OBJECT_FILES) $(MFEM_LIB_FILE) $(CONFIG_MK) $(DATA_DIR)
|
||||
$(CCC) $(SEQ_MAIN_OBJ) $(OBJECT_FILES) $(MFEM_LINK_FLAGS) $(MFEM_LIBS) -o $(@)
|
||||
unit_tests: $(SEQ_MAIN_OBJ) $(LIBTESTS_O) $(MFEM_LIB_FILE) $(CONFIG_MK) $(DATA_DIR)
|
||||
$(CCC) $(SEQ_MAIN_OBJ) $(LIBTESTS_O) $(MFEM_LINK_FLAGS) $(MFEM_LIBS) -o $(@)
|
||||
|
||||
punit_tests: $(PAR_MAIN_OBJ) $(OBJECT_FILES) $(MFEM_LIB_FILE) $(CONFIG_MK) $(DATA_DIR)
|
||||
$(CCC) $(PAR_MAIN_OBJ) $(OBJECT_FILES) $(MFEM_LINK_FLAGS) $(MFEM_LIBS) -o $(@)
|
||||
punit_tests: $(PAR_MAIN_OBJ) $(LIBTESTS_O) $(MFEM_LIB_FILE) $(CONFIG_MK) $(DATA_DIR)
|
||||
$(CCC) $(PAR_MAIN_OBJ) $(LIBTESTS_O) $(MFEM_LINK_FLAGS) $(MFEM_LIBS) -o $(@)
|
||||
|
||||
cunit_tests: $(CUDA_MAIN_OBJ) $(OBJECT_FILES) $(MFEM_LIB_FILE) $(CONFIG_MK) $(DATA_DIR)
|
||||
$(CCC) $(CUDA_MAIN_OBJ) $(OBJECT_FILES) $(MFEM_LINK_FLAGS) $(MFEM_LIBS) -o $(@)
|
||||
cunit_tests: $(CUDA_MAIN_OBJ) $(LIBTESTS_O) $(MFEM_LIB_FILE) $(CONFIG_MK) $(DATA_DIR)
|
||||
$(CCC) $(CUDA_MAIN_OBJ) $(LIBTESTS_O) $(MFEM_LINK_FLAGS) $(MFEM_LIBS) -o $(@)
|
||||
|
||||
pcunit_tests: $(PCUDA_MAIN_OBJ) $(OBJECT_FILES) $(MFEM_LIB_FILE) $(CONFIG_MK) $(DATA_DIR)
|
||||
$(CCC) $(PCUDA_MAIN_OBJ) $(OBJECT_FILES) $(MFEM_LINK_FLAGS) $(MFEM_LIBS) -o $(@)
|
||||
pcunit_tests: $(PCUDA_MAIN_OBJ) $(LIBTESTS_O) $(MFEM_LIB_FILE) $(CONFIG_MK) $(DATA_DIR)
|
||||
$(CCC) $(PCUDA_MAIN_OBJ) $(LIBTESTS_O) $(MFEM_LINK_FLAGS) $(MFEM_LIBS) -o $(@)
|
||||
|
||||
ceed_tests: $(CEED_OBJ) $(MFEM_LIB_FILE) $(CONFIG_MK) $(DATA_DIR)
|
||||
$(CCC) $(CEED_OBJ) $(MFEM_LINK_FLAGS) $(MFEM_LIBS) -o $(@)
|
||||
@@ -125,6 +126,9 @@ $(DEBUG_DEVICE_TEST): $(DEBUG_DEVICE_OBJ) $(MFEM_LIB_FILE) \
|
||||
$(CCC) $(DEBUG_DEVICE_OBJ) $(MFEM_LINK_FLAGS) \
|
||||
$(MFEM_LIBS) -o $(@)
|
||||
|
||||
$(LIBTESTS_O): $(OBJECT_FILES)
|
||||
$(LD) -r $(OBJECT_FILES) -o $(@)
|
||||
|
||||
# Note: in this rule, we always use the full path to the source file as a
|
||||
# workaround for an issue with coveralls.
|
||||
$(OBJECT_FILES) $(SEQ_MAIN_OBJ) $(PAR_MAIN_OBJ) $(CUDA_MAIN_OBJ) \
|
||||
|
||||
Reference in New Issue
Block a user