PeriDEM 0.3.0
PeriDEM -- Peridynamics-based high-fidelity model for granular media
Loading...
Searching...
No Matches
test Namespace Reference

Namespace to group the methods used in testing of the library. More...

Data Structures

struct  testNSearchData
 

Functions

double getExactIntegrationRefTri (size_t alpha, size_t beta)
 Computes integration of polynomial exactly over reference triangle.
 
double getExactIntegrationRefQuad (size_t alpha, size_t beta)
 Computes integration of polynomial exactly over reference quadrangle.
 
double getExactIntegrationRefTet (size_t alpha, size_t beta, size_t theta)
 Computes integration of polynomial exactly over reference tetrahedral.
 
double getNChooseR (size_t n, size_t r)
 Computes \( {n\choose r}\) "n choose r".
 
void testGraphPartitioningSimple ()
 Tests metis partitioning of graph.
 
void testGraphPartitioning (size_t nPart=4, size_t nGrid=10, size_t mHorizon=3, size_t testOption=0, std::string meshFilename="")
 Tests metis partitioning of graph from a 2-D mesh with nonlocal interaction.
 
template<int dim = 3>
std::string testNanoflann (size_t N, double L, double dL, int seed)
 Perform test on nsearch.
 
template<int dim = 3>
std::string testNanoflannExcludeInclude (size_t N, double L, double dL, int seed, testNSearchData &data)
 Perform test on nsearch.
 
std::string testNanoflannClosestPoint (size_t N, double L, double dL, int seed)
 Perform test on nsearch.
 
std::string testTaskflow (size_t N, int seed)
 Perform test on taskflow.
 
void testMPI (size_t nGrid=10, size_t mHorizon=3, size_t testOption=0, std::string meshFilename="")
 Perform parallelization test using MPI on mesh partition based on metis.
 
void testUtilMethods ()
 Test methods

 
void testContactStiffness ()
 Checks the contact-stiffness helpers are bit-for-bit what the expressions they replaced produced.
 
void testLineElem (size_t n, std::string filepath)
 Perform test on quadrature points on line elements (NOT IMPLEMENTED)
 
void testTriElem (size_t n, std::string filepath)
 Perform test on quadrature points on triangle elements.
 
void testQuadElem (size_t n, std::string filepath)
 Perform test on quadrature points on quadrangle elements.
 
void testTetElem (size_t n, std::string filepath)
 Perform test on quadrature points on tetrahedral elements.
 
void testTriElemTime (size_t n, size_t N)
 Computes the time needed when quad data for elements are stored and when they are computed as and when needed.
 
void testPatchTri ()
 Perform test on quadrature points on line elements (NOT IMPLEMENTED)
 
void testPatchQuad ()
 Perform test on quadrature points on line elements (NOT IMPLEMENTED)
 
void testPatchTet ()
 Perform test on quadrature points on line elements (NOT IMPLEMENTED)
 
void testPatchTriDistorted ()
 Perform test on quadrature points on line elements (NOT IMPLEMENTED)
 

Detailed Description

Namespace to group the methods used in testing of the library.

Function Documentation

◆ getExactIntegrationRefQuad()

double test::getExactIntegrationRefQuad ( size_t  alpha,
size_t  beta 
)

Computes integration of polynomial exactly over reference quadrangle.

Given \( f(s,t) = s^\alpha\, t^\beta \), the exact integration is given by

\[ I_{exact} = \int_0^1 \int_0^{1-s} s^\alpha\, t^\beta \, dt\, ds. \]

If either \( \alpha\) or \( \beta\) are odd number then \( I_{exact} = 0\). Otherwise, \( I_{exact} = \frac{4}{(\alpha +1) (\beta+1)} \).

Parameters
alphaPolynomial order in variable s
betaPolynomial order in variable t
Returns
I Exact integration of \( f(s,t) = s^\alpha\, t^\beta \)

Definition at line 194 of file testFeLib.cpp.

194 {
195
196 // compute exact integration of s^\alpha t^\beta
197 if (alpha % 2 == 0 and beta % 2 == 0)
198 return 4. / double((alpha + 1) * (beta + 1));
199 else
200 return 0.;
201}

Referenced by testQuadElem().

Here is the caller graph for this function:

◆ getExactIntegrationRefTet()

double test::getExactIntegrationRefTet ( size_t  alpha,
size_t  beta,
size_t  theta 
)

Computes integration of polynomial exactly over reference tetrahedral.

Parameters
alphaPolynomial order in variable s
betaPolynomial order in variable t
thetaPolynomial order in variable r
Returns
I Exact integration of \( f(s,t) = s^\alpha\, t^\beta \, r^\theta \)

Definition at line 203 of file testFeLib.cpp.

204 {
205
206 double I = 0.;
207 for (size_t i = 0; i <= theta + 1; i++) {
208
209 double factor_i = test::getNChooseR(theta + 1, i) /
210 (double(theta + 1) * double(i + beta + 1));
211 if (i % 2 != 0)
212 factor_i = factor_i * (-1.);
213
214 for (size_t j = 0; j <= theta + beta + 2 + 1; j++) {
215
216 double factor_j =
217 test::getNChooseR(theta + beta + 2, j) / (double(j + alpha + 1));
218 if (j % 2 != 0)
219 factor_j = factor_j * (-1.);
220
221 I += factor_i * factor_j;
222 }
223 }
224
225 return I;
226}
double getNChooseR(size_t n, size_t r)
Computes "n choose r".

References getNChooseR().

Referenced by testTetElem().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getExactIntegrationRefTri()

double test::getExactIntegrationRefTri ( size_t  alpha,
size_t  beta 
)

Computes integration of polynomial exactly over reference triangle.

Given \( f(s,t) = s^\alpha\, t^\beta \), the exact integration is given by

\[ I_{exact} = \int_0^1 \int_0^{1-s} s^\alpha\, t^\beta \, dt\, ds = \sum_{i=0}^{\beta+1} (-1)^i \frac{{{\beta + 1} \choose i}}{(\alpha + i +1) (\beta + 1)}, \]

where

\[ {a \choose b} = \frac{a (a-1) (a-2) ... (a-b+1)}{1*2*3 ... *b}. \]

We have \( {a \choose 0} = 1 \) so that term for \( i=0\) is not zero. Above formula gives the exact value of integral of \( f(s,t) = s^\alpha\, t^\beta \) over reference triangle.

Parameters
alphaPolynomial order in variable s
betaPolynomial order in variable t
Returns
I Exact integration of \( f(s,t) = s^\alpha\, t^\beta \)

Definition at line 178 of file testFeLib.cpp.

178 {
179
180 // compute exact integration of s^\alpha t^\beta
181 double I = 0.;
182 for (size_t k = 0; k <= beta + 1; k++) {
183 if (k % 2 == 0)
184 I +=
185 test::getNChooseR(beta + 1, k) / double((alpha + 1 + k) * (beta + 1));
186 else
187 I -=
188 test::getNChooseR(beta + 1, k) / double((alpha + 1 + k) * (beta + 1));
189 }
190
191 return I;
192}

References getNChooseR().

Referenced by testTriElem().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getNChooseR()

double test::getNChooseR ( size_t  n,
size_t  r 
)

Computes \( {n\choose r}\) "n choose r".

Computes formula

\[ {a \choose b} = \frac{a (a-1) (a-2) ... (a-b+1)}{1*2*3 ... *b}. \]

Parameters
nNumber
rNumber which is smaller or equal to n
Returns
Value Value of "n choose r"

Definition at line 166 of file testFeLib.cpp.

166 {
167
168 if (r == 0)
169 return 1.;
170
171 double a = 1.;
172 for (size_t i = 1; i <= r; i++)
173 a *= double(n - i + 1) / double(i);
174
175 return a;
176}

Referenced by getExactIntegrationRefTet(), and getExactIntegrationRefTri().

Here is the caller graph for this function:

◆ testContactStiffness()

void test::testContactStiffness ( )

Checks the contact-stiffness helpers are bit-for-bit what the expressions they replaced produced.

util::normalContactStiffness and util::selfContactStiffness replaced the same formula at nine call sites. The two differ only in the order of operations, which changes the result in the last bit, so each has to reproduce the grouping of the expression it replaced. Otherwise collecting them changes the contact force in every example.

Definition at line 115 of file testUtilLib.cpp.

115 {
116
117 // Bulk moduli and horizons that appear in the examples and tests.
118 const std::vector<double> Ks = {2.16e7, 1.0e4, 1.0e5,
119 159.2e9, 216000.0, 2.0e9, 1.23e9};
120 const std::vector<double> hs = {6.0e-4, 2.0e-4, 4.0e-4,
121 3.0e-3, 3.2e-4, 1.25e-3, 3.75e-3};
122
123 size_t n_checked = 0;
124 for (auto K1 : Ks) {
125 for (auto K2 : Ks) {
126 for (auto h : hs) {
127 // The form the example and test drivers used, at both exponents.
128 for (int p : {4, 5}) {
129 const double expected =
130 18.0 * util::harmonicMean(K1, K2) / (M_PI * std::pow(h, p));
131 const double got = util::normalContactStiffness(K1, K2, h, p);
132 if (got != expected)
133 errExit(std::format(
134 "normalContactStiffness({}, {}, {}, {}) = {:.20g}, expected "
135 "{:.20g}: the replaced expression gave a different value\n",
136 K1, K2, h, p, got, expected));
137 ++n_checked;
138 }
139 }
140 }
141 for (auto h : hs) {
142 // The form BaseParticle uses for internal contact. The grouping is
143 // (18 / (pi h^5)) * K and not 18 K / (pi h^5).
144 const double expected = (18. / (M_PI * std::pow(h, 5))) * K1;
145 const double got = util::selfContactStiffness(K1, h);
146 if (got != expected)
147 errExit(std::format(
148 "selfContactStiffness({}, {}) = {:.20g}, expected {:.20g}: the "
149 "order of operations differs from the one in BaseParticle\n",
150 K1, h, got, expected));
151 ++n_checked;
152 }
153 }
154
155 // The two forms are the same quantity because harmonicMean(K, K) == K.
156 for (auto K : Ks)
157 if (util::harmonicMean(K, K) != K)
158 errExit(std::format("harmonicMean({0}, {0}) != {0}\n", K));
159
160 // A horizon of zero divides by zero, so it is rejected instead.
161 bool threw = false;
162 try {
164 } catch (const std::exception &) {
165 threw = true;
166 }
167 if (!threw)
168 errExit("normalContactStiffness accepted a zero horizon\n");
169
170 std::cout << std::format(
171 "testContactStiffness: {} values equal to the replaced expressions\n",
172 n_checked);
173}
float K
Definition problem.py:43
Collection of methods useful in simulation.
Definition constants.h:14
double selfContactStiffness(const double &K, const double &horizon, int horizonPower=5)
Contact stiffness for a body against itself.
Definition function.cpp:148
double normalContactStiffness(const double &K1, const double &K2, const double &horizon, int horizonPower=5)
Silling normal contact stiffness from two bulk moduli and the horizon.
Definition function.cpp:139
double harmonicMean(const double &m1, const double &m2)
Definition function.cpp:135

References anonymous_namespace{testUtilLib.cpp}::errExit(), util::harmonicMean(), util::normalContactStiffness(), and util::selfContactStiffness().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ testGraphPartitioning()

void test::testGraphPartitioning ( size_t  nPart = 4,
size_t  nGrid = 10,
size_t  mHorizon = 3,
size_t  testOption = 0,
std::string  meshFilename = "" 
)

Tests metis partitioning of graph from a 2-D mesh with nonlocal interaction.

Parameters
nPartNumber of partitions
nGridNumber of element along a line (total number of elements is N*N)
mHorizonInteger factor that is used to compute nonlocal radius, i.e., horizon (epsilon = m * h, h being mesh size)
testOptionTest otion flag. 0 - use in-built uniform mesh, 1 - use user-specified mesh
meshFilenameMesh filename with relative path from the directory where test command is run

Definition at line 137 of file testMeshPartitioningLib.cpp.

137 {
138
139 std::cout << "\nMETIS_TEST\n";
140 std::cout << "\n Test the METIS library for graph partitioning for realistic mesh with nonlocal interaction.\n" ;
141 std::cout << std::format("\n Arguments: nPart = {}, nGrid = {}, mHorizon = {}\n", nPart, nGrid, mHorizon);
142
143 // create uniform mesh on domain [0, Lx]x[0, Ly]
144 auto t1 = steady_clock::now();
145
146 // empty mesh object
147 size_t dim(2);
148 auto mesh = mesh::Mesh(dim);
149 mesh.d_spatialDiscretization = "finite_difference";
150
151 // create mesh
152 std::string outMeshFilename = "";
153 if (testOption == 1) {
154 // set geometry details
155 std::pair<std::vector<double>, std::vector<double>> box;
156 std::vector<size_t> nGridVec;
157 for (size_t i=0; i<dim; i++) {
158 box.first.push_back(0.);
159 box.second.push_back(1.);
160 nGridVec.push_back(nGrid);
161 }
162
163 // call utility function to create mesh
164 mesh::createUniformMesh(&mesh, dim, box, nGridVec);
165
166 // filename for outputting
167 outMeshFilename = std::format("uniform_mesh_Lx_{}_Ly_{}_Nx_{}_Ny_{}",
168 box.second[0], box.second[1],
169 nGridVec[0], nGridVec[1]);
170 }
171 else if (testOption == 2) {
172 if (meshFilename.empty()) {
173 std::cerr << "testGraphPartitioning(): mesh filename is empty.\n";
174 exit(1);
175 }
176
177 // call in-built function of mesh to create data from file
178 mesh.createData(meshFilename);
179
180 // find the name of mesh file without path and without extension (i.e., remove .vtu/.msh/.csv extension)
181 auto f1 = util::io::getFilenameFromPath(meshFilename);
182 outMeshFilename = util::io::removeExtensionFromFile(f1);
183 }
184 else {
185 std::cerr << "testGraphPartitioning() accepts either 0 or 1 for testOption. The value "
186 << testOption << " is invalid.\n";
187 exit(1);
188 }
189
190 // set nonlocal lengthscale
191 double horizon = mHorizon*mesh.d_h;
192
193 // print mesh data and write mesh to a file
194 std::ostringstream msg;
195 msg << mesh.printStr();
196 std::cout << msg.str();
197
198 auto t2 = steady_clock::now();
199 auto setup_time = util::methods::timeDiff(t1, t2, "microseconds");
200 std::cout << std::format("Setup time (ms) = {}. \n", setup_time);
201
202 // create neighborhood of each node (to be used in metis partitioning of the graph)
203 std::vector<std::vector<size_t>> nodeNeighs(mesh.d_numNodes);
204 geom::computeNonlocalNeighborhood(mesh.d_nodes, horizon, nodeNeighs);
205 auto t3 = steady_clock::now();
206 auto neigh_time = util::methods::timeDiff(t2, t3, "microseconds");
207 std::cout << std::format("Neighborhood calculation time (ms) = {}.\n", neigh_time);
208
209 // at this stage, we have mesh and nonlocal neighborhood
210 // we are ready to cast the nonlocal neighborhood into graph and call metis for partitioning of nodes
211 std::vector<size_t> nodePartitionRecursive(mesh.d_numNodes, 0);
212 std::vector<size_t> nodePartitionKWay(mesh.d_numNodes, 0);
213
214 // recursive method
215 auto t4 = steady_clock::now();
216 mesh::metisGraphPartition("metis_recursive", nodeNeighs, nodePartitionRecursive, nPart);
217 auto t5 = steady_clock::now();
218
219 // K-way method
220 mesh::metisGraphPartition("metis_kway", nodeNeighs, nodePartitionKWay, nPart);
221 auto t6 = steady_clock::now();
222
223 auto partition_recursive_time = util::methods::timeDiff(t4, t5, "microseconds");
224 auto partition_kway_time = util::methods::timeDiff(t5, t6, "microseconds");
225 std::cout << std::format("Partition (Recursive) calculation time (ms) = {}.\n", partition_recursive_time);
226 std::cout << std::format("Partition (KWay) calculation time (ms) = {}.\n", partition_kway_time);
227
228 // write data to file
229 outMeshFilename = outMeshFilename + std::format("_mHorizon_{}_nPart_{}", mHorizon, nPart);
230 std::cout << "out mesh filename = " << outMeshFilename << std::endl;
231 auto writer = rw::writer::Writer(outMeshFilename, "vtu");
232 writer.appendMesh(&mesh.d_nodes, mesh.d_eType, &mesh.d_enc);
233 writer.appendPointData("Nodal_Volume", &mesh.d_vol);
234 writer.appendPointData("Nodal_Partition_Metis_Recursive_Index", &nodePartitionRecursive);
235 writer.appendPointData("Nodal_Partition_Metis_KWay_Index", &nodePartitionKWay);
236 writer.close();
237}
A class for mesh data.
Definition mesh.h:53
A interface class writing data.
Definition writer.h:44
void computeNonlocalNeighborhood(const std::vector< util::Point > &nodes, double horizon, std::vector< std::vector< size_t > > &nodeNeighs)
Partitions the nodes based on node neighborlist supplied. Function first creates a graph with nodes a...
Collection of methods and data related to finite element and mesh.
Definition mesh.cpp:29
void metisGraphPartition(std::string partitionMethod, const std::vector< std::vector< size_t > > &nodeNeighs, std::vector< size_t > &nodePartition, size_t nPartitions)
Partitions the nodes based on node neighborlist supplied. Function first creates a graph with nodes a...
void createUniformMesh(mesh::Mesh *mesh_p, size_t dim, std::pair< std::vector< double >, std::vector< double > > box, std::vector< size_t > nGrid)
Creates uniform mesh for rectangle/cuboid domain.
Definition meshUtil.cpp:64
std::string removeExtensionFromFile(std::string const &filename)
Remove extension from the filename Source - https://stackoverflow.com/a/24386991.
Definition io.h:339
std::string getFilenameFromPath(std::string const &path, std::string const &delims="/\\")
Get filename removing path from the string Source - https://stackoverflow.com/a/24386991.
Definition io.h:327
float timeDiff(std::chrono::steady_clock::time_point begin, std::chrono::steady_clock::time_point end, std::string unit="microseconds")
Returns difference between two times.
Definition vecMethods.h:309

References geom::computeNonlocalNeighborhood(), mesh::createUniformMesh(), util::io::getFilenameFromPath(), mesh::metisGraphPartition(), util::io::removeExtensionFromFile(), and util::methods::timeDiff().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ testGraphPartitioningSimple()

void test::testGraphPartitioningSimple ( )

Tests metis partitioning of graph.

Definition at line 126 of file testMeshPartitioningLib.cpp.

126 {
127
128 printf("\n");
129 printf("METIS_TEST\n");
130 printf(" Test the METIS library for graph partitioning (simple).\n");
131
132 // check that metis is linked and returns a partition
135}

References anonymous_namespace{testMeshPartitioningLib.cpp}::partGraphKwayTestSimple(), and anonymous_namespace{testMeshPartitioningLib.cpp}::partGraphRecursiveTestSimple().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ testLineElem()

void test::testLineElem ( size_t  n,
std::string  filepath 
)

Perform test on quadrature points on line elements (NOT IMPLEMENTED)

This function performs accuracy test of the quadrature points for integration over reference line with vertices at {-1, 1}. List of tests are as follows:

  1. Computes quadrature points of the given order, writes them to the file, and checks if the sum of quadrature weights is equal to 0.5 (area of reference triangle).

Also tests the exactness of the integration of the polynomial upto given order. Suppose \( n\) is the order of quadrature point, then we test if the integration of the function \( f(s,t) = s^\alpha\, t^\beta \) is exact for \( \alpha \) and \( \beta \) such that \( \alpha+\beta \leq n \). The exact integration of function \( f\) over reference triangle is

\[ I_{exact} = \int_0^1 \int_0^{1-s} s^\alpha\, t^\beta \, dt\, ds = \sum_{i=0}^{\beta+1} (-1)^i \frac{{{\beta + 1} \choose i}}{(\alpha + i +1) (\beta + 1)}, \]

where

\[ {a \choose b} = \frac{a (a-1) (a-2) ... (a-b+1)}{1*2*3 ... *b}. \]

We have \( {a \choose 0} = 1 \) so that term for \( i=0\) is not zero. Above formula gives the exact value of integral of \( f(s,t) = s^\alpha\, t^\beta \) over reference triangle. Approximation by quadrature point is as follows

\[ I_{approx} = \sum_{q=1}^{Q} w_q f(s_q, t_q) \]

where \(Q\) is the total number of quad points, \( w_q\) and \((s_q, t_q)\) are the \( q^{th} \) quad weight and point. In this test, we compare \( I_{exact} \) and \( I_{approx} \) and report problem if both do not match.

  1. Test the accuracy for simple quadrangle mesh on square domain [0,1]^2. Exact integration of polynomial \( f(x,y) = x^\alpha \, y^\beta \) on \([0,1]^2\) is given by

    \[ I_{exact} = \frac{1}{(\alpha+1) (\beta+1)}. \]

    We compare above with the approximation computed from the quadrature points. We consider \(\alpha + \beta \leq n \) where \( n\) is the order of approximation we are testing.
Parameters
nOrder of quadrature point approximation
filepathPath where mesh data for test can be found (expects files 'triMesh_nodes.csv' and 'triMesh_elements.csv' inside the filepath)

Definition at line 229 of file testFeLib.cpp.

229{ return; }

Referenced by main().

Here is the caller graph for this function:

◆ testMPI()

void test::testMPI ( size_t  nGrid = 10,
size_t  mHorizon = 3,
size_t  testOption = 0,
std::string  meshFilename = "" 
)

Perform parallelization test using MPI on mesh partition based on metis.

Parameters
nGridNumber of element along a line (total number of elements is N*N)
mHorizonInteger factor that is used to compute nonlocal radius, i.e., horizon (epsilon = m * h, h being mesh size)
testOptionTest otion flag. 0 - use in-built uniform mesh, 1 - use user-specified mesh
meshFilenameMesh filename with relative path from the directory where test command is run

Definition at line 284 of file testParallelCompLib.cpp.

285 {
286 int mpiSize, mpiRank;
287 MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
288 MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
289
290 // number of partitions
291 size_t nPart(mpiSize);
292
293 // create uniform mesh
294 size_t dim(2);
295 auto mesh = mesh::Mesh(dim);
296 mesh.d_spatialDiscretization = "finite_difference";
297
298 // create mesh
299 std::string outMeshFilename = "";
300 if (testOption == 1) {
301 // set geometry details
302 std::pair<std::vector<double>, std::vector<double>> box;
303 std::vector<size_t> nGridVec;
304 for (size_t i=0; i<dim; i++) {
305 box.first.push_back(0.);
306 box.second.push_back(1.);
307 nGridVec.push_back(nGrid);
308 }
309
310 // call utility function to create mesh
311 util::io::print("\n\nCreating uniform mesh\n\n");
312 mesh::createUniformMesh(&mesh, dim, box, nGridVec);
313
314 // filename for outputting
315 outMeshFilename = std::format("uniform_mesh_Lx_{}_Ly_{}_Nx_{}_Ny_{}",
316 box.second[0], box.second[1],
317 nGridVec[0], nGridVec[1]);
318 }
319 else if (testOption == 2) {
320 if (meshFilename.empty()) {
321 std::cerr << "testGraphPartitioning(): mesh filename is empty.\n";
322 exit(1);
323 }
324
325 // call in-built function of mesh to create data from file
326 util::io::print("\n\nReading mesh\n\n");
327 mesh.createData(meshFilename);
328
329 // find the name of mesh file excluding path and extension
331 }
332 else {
333 std::cerr << "testMPI() accepts either 1 or 2 for testOption. The value "
334 << testOption << " is invalid.\n";
335 exit(1);
336 }
337
338 // print mesh data and write mesh to a file
339 util::io::print(mesh.printStr());
340
341 // calculate nonlocal neighborhood
342 double horizon = mHorizon*mesh.d_h;
343 std::vector<std::vector<size_t>> nodeNeighs(mesh.d_numNodes);
344 geom::computeNonlocalNeighborhood(mesh.d_nodes, horizon, nodeNeighs);
345
346 // partition the mesh on root processor and broadcast to other processors
347 mesh.d_nodePartition.resize(mesh.d_numNodes);
348 util::io::print("\n\nCreating partition of mesh\n\n");
349 if (mpiRank == 0)
350 mesh::metisGraphPartition("metis_kway", &mesh, nodeNeighs, nPart);
351
352 util::io::print("\n\nBroadcasting partition to all processors\n\n");
353 MPI_Bcast(mesh.d_nodePartition.data(), mesh.d_numNodes,
354 MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD);
355
356
357 // Tasks:
358 // 1. Create list of ghost nodes associated to neighboring processors
359 // 2. Create a method that updates displacement of ghost nodes via MPI communication
360 // 3. Create two set of nodes owned by this processor; internal set will have nodes
361 // that do not depend on ghost nodes and boundary set that depend on ghost nodes
362
363 // store id of nodes owned by this processor
364 std::vector<size_t> ownedNodes, ownedInternalNodes, ownedBdryNodes;
365
366 // for each neighboring processor, store id of ghost nodes owned by that processor
367 std::vector<std::pair<std::vector<size_t>, std::vector<size_t>>> ghostData;
368
369 // fill the owned and ghost node vectors
370 util::io::print("\n\nCalling setupOwnerAndGhost()\n\n");
371 setupOwnerAndGhost(mpiSize, mpiRank,
372 mesh.d_nodePartition, nodeNeighs,
373 ownedNodes, ownedInternalNodes, ownedBdryNodes,
374 ghostData);
375
376 // create dummy displacement vector with random values
377 std::vector<util::Point> dispNodes(mesh.d_numNodes, util::Point(-1., -1., -1.));
378 {
379 // int seed = mpiRank;
380 // RandGenerator gen(util::get_rd_gen(seed));
381 // auto dist = util::DistributionSample<UniformDistribution>(0., 1., seed);
382 // for (auto i: ownedNodes)
383 // dispNodes[i] = util::Point(dist(), dist(), dist());
384 // assign value to owned nodes
385 for (auto i: ownedNodes)
386 dispNodes[i] = util::Point(mpiRank + 1, (mpiRank + 1)*100, (mpiRank + 1)*10000);
387 }
388
389 // MPI communication to send and receive ghost nodes data
390 printMsg("\n\nCalling exchangeDispData()\n\n", mpiRank, 0);
391 std::vector<std::pair<std::vector<util::Point>, std::vector<util::Point>>> dispGhostData;
392 exchangeDispData(mpiSize, mpiRank, ghostData, dispGhostData, dispNodes);
393
395 if (true) {
396 printMsg("\n\nDebugging dispGhostData()\n\n", mpiRank, -1);
397 bool debug_failed = false;
398 for (size_t j_proc = 0; j_proc < mpiSize; j_proc++) {
399 auto &recvIds = ghostData[j_proc].first;
400
401 if (j_proc != mpiRank and recvIds.size() != 0) {
402 for (size_t k = 0; k < recvIds.size(); k++) {
403 auto &uk = dispNodes[recvIds[k]];
404
405 // verify we received correct value of uk
406 if (uk[0] != j_proc + 1 or uk[1] != 100 * (j_proc + 1)
407 or uk[2] != 10000 * (j_proc + 1)) {
408 debug_failed = true;
409 util::io::print(std::format(" MPI exchange error: j_proc = {}, "
410 "uk = ({}, {}, {})\n", j_proc,
411 uk[0], uk[1], uk[2]),
413 }
414 }
415 }
416 } // loop over j_proc
417
418 if (debug_failed)
419 util::io::print(std::format("\n\nDEBUG failed for processor = {}\n\n", mpiRank), util::io::print_default_tab, -1);
420 else
421 util::io::print(std::format("\n\nDEBUG passed for processor = {}\n\n", mpiRank), util::io::print_default_tab, -1);
422 }
424}
void printMsg(std::string msg, int mpiRank, int printMpiRank)
void exchangeDispData(size_t mpiSize, size_t mpiRank, const std::vector< std::pair< std::vector< size_t >, std::vector< size_t > > > &ghostData, std::vector< std::pair< std::vector< util::Point >, std::vector< util::Point > > > &dispGhostData, std::vector< util::Point > &dispNodes)
void setupOwnerAndGhost(size_t mpiSize, size_t mpiRank, const std::vector< size_t > &nodePartition, const std::vector< std::vector< size_t > > &nodeNeighs, std::vector< size_t > &ownedNodes, std::vector< size_t > &ownedInternalNodes, std::vector< size_t > &ownedBdryNodes, std::vector< std::pair< std::vector< size_t >, std::vector< size_t > > > &ghostData)
const int print_default_tab
Default value of tab used in outputting formatted information.
Definition constants.h:18
void print(const T &msg, int nt=print_default_tab, int printMpiRank=print_default_mpi_rank)
Prints formatted information.
Definition io.h:171
int mpiSize()
Get size (number) of processors.
int mpiRank()
get rank (id) of this processor
A structure to represent 3d vectors.
Definition point.h:30

References geom::computeNonlocalNeighborhood(), mesh::createUniformMesh(), anonymous_namespace{testParallelCompLib.cpp}::exchangeDispData(), util::io::getFilenameFromPath(), mesh::metisGraphPartition(), util::io::print(), util::io::print_default_tab, anonymous_namespace{testParallelCompLib.cpp}::printMsg(), util::io::removeExtensionFromFile(), and anonymous_namespace{testParallelCompLib.cpp}::setupOwnerAndGhost().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ testNanoflann()

template<int dim = 3>
template std::string test::testNanoflann< 3 > ( size_t  N,
double  L,
double  dL,
int  seed 
)

Perform test on nsearch.

Parameters
Nsize of particle cloud in each dimension. total size would be N^3
LSize of unit cell to create crystal lattice point cloud
dLPerturbation of lattice sites
seedSeed
dimDimension
Returns
str Description of the search and its result

Definition at line 494 of file testNSearchLib.cpp.

494 {
495
496 if (dim < 2 or dim > 3) {
497 return "testNanoflann: only dim = 2, 3 are accepted.\n";
498 }
499
500 // create 3D lattice and perturb each lattice point
501 size_t Nx, Ny, Nz;
502 Nx = Ny = Nz = N;
503 size_t N_tot = Nx * Ny;
504 if (dim == 3)
505 N_tot = N_tot * Nz;
506
507 std::vector<util::Point> x(N_tot, util::Point());
508 lattice(L, Nx, Ny, Nz, dL, seed, x, dim);
509 std::cout << "Total points = " << x.size() << "\n";
510
511
512 if (dim == 2) {
513 std::vector<std::vector<size_t>> neigh_nflann(N_tot, std::vector<size_t>());
514 std::vector<std::vector<float>> neigh_nflann_sq_dist(N_tot,
515 std::vector<float>());
516
517 std::vector<std::vector<size_t>> neigh_nflann_3d(N_tot, std::vector<size_t>());
518 std::vector<std::vector<float>> neigh_nflann_3d_sq_dist(N_tot,
519 std::vector<float>());
520
521 std::vector<std::vector<size_t>> neigh_brute(N_tot, std::vector<size_t>());
522 std::vector<std::vector<float>> neigh_brute_sq_dist(N_tot,
523 std::vector<float>());
524
525 // brute-force search
526 double search_r = 1.5 * L;
527 auto brute_force_search_time =
528 neighSearchBrute(x, search_r, neigh_brute, neigh_brute_sq_dist);
529
530 // nanoflann tree search
531 std::unique_ptr<nsearch::NFlannSearchKd<3>> nflann_nsearch_3d
532 = std::make_unique<nsearch::NFlannSearchKd<3>>(x, 0);
533
534 std::unique_ptr<nsearch::NFlannSearchKd<dim>> nflann_nsearch
535 = std::make_unique<nsearch::NFlannSearchKd<dim>>(x, 0);
536
537 auto nflann_tree_set_time_3d = nflann_nsearch_3d->setInputCloud();
538 auto nflann_tree_search_time_3d =
539 neighSearchTreeSizet(x, nflann_nsearch_3d, search_r, neigh_nflann_3d, neigh_nflann_3d_sq_dist);
540
541 auto nflann_tree_set_time = nflann_nsearch->setInputCloud();
542 auto nflann_tree_search_time =
543 neighSearchTreeSizet(x, nflann_nsearch, search_r, neigh_nflann, neigh_nflann_sq_dist);
544
545 // Compare search results
546 auto nflann_brute_compare = compare_results(
547 neigh_nflann, neigh_brute, {"nflann_tree", "brute_force"}, -1, true);
548
549 auto nflann_brute_compare_3d = compare_results(
550 neigh_nflann_3d, neigh_brute, {"nflann_tree-3d", "brute_force"}, -1, true);
551
552 std::ostringstream msg;
553 msg << std::format(" Setup times (microseconds): \n"
554 " nflann_tree_set_time = {} \n "
555 " nflann_tree_set_time_3d = {}\n",
556 nflann_tree_set_time, nflann_tree_set_time_3d);
557
558 msg << std::format(" Search times (microseconds): \n"
559 " brute_force_search_time = {}\n"
560 " nflann_tree_search_time = {}\n"
561 " nflann_tree_search_time_3d = {}\n",
562 brute_force_search_time,
563 nflann_tree_search_time,
564 nflann_tree_search_time_3d);
565
566 msg << std::format(" Comparison results: \n"
567 " nflann_brute_compare: \n{}\n",
568 nflann_brute_compare);
569
570 msg << std::format(" Comparison results: \n"
571 " nflann_brute_compare_3d: \n{}\n",
572 nflann_brute_compare_3d);
573
574 return msg.str();
575 }
576 else if (dim == 3) {
577 std::vector<std::vector<size_t>> neigh_nflann(N_tot, std::vector<size_t>());
578 std::vector<std::vector<float>> neigh_nflann_sq_dist(N_tot,
579 std::vector<float>());
580
581 std::vector<std::vector<size_t>> neigh_brute(N_tot, std::vector<size_t>());
582 std::vector<std::vector<float>> neigh_brute_sq_dist(N_tot,
583 std::vector<float>());
584
585 // brute-force search
586 double search_r = 1.5 * L;
587 auto brute_force_search_time =
588 neighSearchBrute(x, search_r, neigh_brute, neigh_brute_sq_dist);
589
590 // nanoflann tree search
591 std::unique_ptr<nsearch::NFlannSearchKd<dim>> nflann_nsearch
592 = std::make_unique<nsearch::NFlannSearchKd<dim>>(x, 0);
593
594 auto nflann_tree_set_time = nflann_nsearch->setInputCloud();
595 auto nflann_tree_search_time =
596 neighSearchTreeSizet(x, nflann_nsearch, search_r, neigh_nflann, neigh_nflann_sq_dist);
597
598 // Compare search results
599 auto nflann_brute_compare = compare_results(
600 neigh_nflann, neigh_brute, {"nflann_tree", "brute_force"}, -1, true);
601
602 std::ostringstream msg;
603 msg << std::format(" Setup times (microseconds): \n"
604 " nflann_tree_set_time = {}\n",
605 nflann_tree_set_time);
606
607 msg << std::format(" Search times (microseconds): \n"
608 " brute_force_search_time = {}\n"
609 " nflann_tree_search_time = {}\n",
610 brute_force_search_time,
611 nflann_tree_search_time);
612
613 msg << std::format(" Comparison results: \n"
614 " nflann_brute_compare: \n{}\n",
615 nflann_brute_compare);
616
617 return msg.str();
618 }
619
620
621}
double neighSearchTreeSizet(const std::vector< util::Point > &x, const std::unique_ptr< NSearch > &nsearch, const double &r, std::vector< std::vector< size_t > > &neigh, std::vector< std::vector< float > > &neigh_sq_dist)
void lattice(double L, size_t Nx, size_t Ny, size_t Nz, double dL, int seed, std::vector< util::Point > &x, int dim=3)
std::string compare_results(const std::vector< std::vector< size_t > > &neigh1, const std::vector< std::vector< size_t > > &neigh2, std::vector< std::string > tags, int check_nodes_num=-1, bool only_err_count=false)
double neighSearchBrute(const std::vector< util::Point > &x, const double &r, std::vector< std::vector< size_t > > &neigh, std::vector< std::vector< float > > &neigh_sq_dist)

References anonymous_namespace{testNSearchLib.cpp}::compare_results(), anonymous_namespace{testNSearchLib.cpp}::lattice(), anonymous_namespace{testNSearchLib.cpp}::neighSearchBrute(), and anonymous_namespace{testNSearchLib.cpp}::neighSearchTreeSizet().

Here is the call graph for this function:

◆ testNanoflannClosestPoint()

std::string test::testNanoflannClosestPoint ( size_t  N,
double  L,
double  dL,
int  seed 
)

Perform test on nsearch.

Parameters
Nsize of particle cloud in each dimension. total size would be N^3
LSize of unit cell to create crystal lattice point cloud
dLPerturbation of lattice sites
seedSeed
Returns
str Description of the search and its result

Definition at line 781 of file testNSearchLib.cpp.

781 {
782
783 // create 3D lattice and perturb each lattice point
784 size_t Nx, Ny, Nz;
785 Nx = Ny = Nz = N;
786 size_t N_tot = Nx * Ny * Nz;
787
788 std::vector<util::Point> x(N_tot, util::Point());
789 lattice(L, Nx, Ny, Nz, dL, seed, x, 3);
790 std::cout << "Total points = " << x.size() << "\n";
791
792 // nanoflann tree search
793 auto nflann_nsearch
794 = std::make_unique<nsearch::NFlannSearchKd<3>>(x, 0);
795
796 auto nflann_tree_set_time = nflann_nsearch->setInputCloud();
797
798 std::vector<size_t> err_points;
799 std::vector<util::Point> search_points;
800 std::vector<double> err_dist;
801 auto nsearch_search_time = neighSearchTreeClosestPointSizet(
802 x, nflann_nsearch, seed, L, dL, search_points, err_points, err_dist);
803
804 // Compare search results
805 auto nflann_compare = compare_closest_point_results(x,
806 search_points,
807 err_points,
808 err_dist, false);
809
810 std::ostringstream msg;
811 msg << std::format(" Setup times (microseconds): \n"
812 " nflann_tree_set_time = {}\n",
813 nflann_tree_set_time);
814
815 msg << std::format(" Comparison results: \n"
816 " nflann_compare: \n{}\n",
817 nflann_compare);
818
819 return msg.str();
820
821
822
823}
double neighSearchTreeClosestPointSizet(const std::vector< util::Point > &x, const std::unique_ptr< NSearch > &nsearch, const int &seed, const double &L, const double &dL, std::vector< util::Point > &search_points, std::vector< size_t > &err_points, std::vector< double > &err_dist)
std::string compare_closest_point_results(const std::vector< util::Point > &x, const std::vector< util::Point > &search_points, const std::vector< size_t > &err_points, const std::vector< double > &err_dist, bool only_err_count=false)

References anonymous_namespace{testNSearchLib.cpp}::compare_closest_point_results(), anonymous_namespace{testNSearchLib.cpp}::lattice(), and anonymous_namespace{testNSearchLib.cpp}::neighSearchTreeClosestPointSizet().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ testNanoflannExcludeInclude()

template<int dim = 3>
template std::string test::testNanoflannExcludeInclude< 3 > ( size_t  N,
double  L,
double  dL,
int  seed,
testNSearchData &  data 
)

Perform test on nsearch.

Parameters
Nsize of particle cloud in each dimension. total size would be N^3
LSize of unit cell to create crystal lattice point cloud
dLPerturbation of lattice sites
seedSeed
dimDimension
dataSearch data
Returns
str Description of the search and its result

Definition at line 625 of file testNSearchLib.cpp.

626 {
627
628 if (dim < 2 or dim > 3) {
629 return "testNanoflannExcludeInclude: only dim = 2, 3 are accepted.\n";
630 }
631
632 // create 3D lattice and perturb each lattice point
633 size_t Nx, Ny, Nz;
634 Nx = Ny = Nz = N;
635 size_t N_tot = Nx * Ny;
636 if (dim == 3)
637 N_tot = N_tot * Nz;
638
639 std::vector<util::Point> x(N_tot, util::Point());
640 std::vector<size_t> xTags(N_tot, 0);
641 lattice(L, Nx, Ny, Nz, dL, seed, x, dim);
642 assignRandomTags(x, data.d_numTags, seed, xTags);
643 data.d_numPoints = x.size();
644 std::cout << "Total points = " << x.size() << "\n";
645
646 std::vector<std::vector<size_t>> neigh_default_nflann(N_tot, std::vector<size_t>());
647 std::vector<std::vector<float>> neigh_default_nflann_sq_dist(N_tot,
648 std::vector<float>());
649
650 std::vector<std::vector<size_t>> neigh_exclude_nflann(N_tot, std::vector<size_t>());
651 std::vector<std::vector<float>> neigh_exclude_nflann_sq_dist(N_tot,
652 std::vector<float>());
653
654 std::vector<std::vector<size_t>> neigh_include_nflann(N_tot, std::vector<size_t>());
655 std::vector<std::vector<float>> neigh_include_nflann_sq_dist(N_tot,
656 std::vector<float>());
657
658
659 std::vector<std::vector<size_t>> neigh_default_brute(N_tot, std::vector<size_t>());
660 std::vector<std::vector<float>> neigh_default_brute_sq_dist(N_tot,
661 std::vector<float>());
662
663 std::vector<std::vector<size_t>> neigh_exclude_brute(N_tot, std::vector<size_t>());
664 std::vector<std::vector<float>> neigh_exclude_brute_sq_dist(N_tot,
665 std::vector<float>());
666
667 std::vector<std::vector<size_t>> neigh_include_brute(N_tot, std::vector<size_t>());
668 std::vector<std::vector<float>> neigh_include_brute_sq_dist(N_tot,
669 std::vector<float>());
670
671 // brute-force search
672 double search_r = 3. * L;
673
674 data.d_defaultBruteSearchTime =
676 search_r,
677 neigh_default_brute,
678 neigh_default_brute_sq_dist);
679
680 data.d_excludeBruteSearchTime =
681 neighSearchBruteExcludeInclude(x, xTags, search_r,
682 neigh_exclude_brute,
683 neigh_exclude_brute_sq_dist,
684 1);
685
686 data.d_includeBruteSearchTime =
687 neighSearchBruteExcludeInclude(x, xTags, search_r,
688 neigh_include_brute,
689 neigh_include_brute_sq_dist,
690 2);
691
692 // nanoflann tree search
693 std::unique_ptr<nsearch::NFlannSearchKd<dim>> nflann_nsearch
694 = std::make_unique<nsearch::NFlannSearchKd<dim>>(x, 0,
695 data.d_leafMaxSize);
696
697 data.d_treeBuildTime = nflann_nsearch->setInputCloud();
698
699 // default
700 data.d_defaultNFlannSearchTime =
701 neighSearchTreeSizet(x, nflann_nsearch,
702 search_r, neigh_default_nflann,
703 neigh_default_nflann_sq_dist);
704
705 // exclude
706 data.d_excludeNFlannSearchTime =
707 neighSearchTreeSizetExcludeInclude(x, xTags, nflann_nsearch,
708 search_r, neigh_exclude_nflann,
709 neigh_exclude_nflann_sq_dist,
710 1);
711
712 // include
713 data.d_includeNFlannSearchTime =
714 neighSearchTreeSizetExcludeInclude(x, xTags, nflann_nsearch,
715 search_r, neigh_include_nflann,
716 neigh_include_nflann_sq_dist,
717 2);
718
719 // Compare search results
720 auto nflann_brute_compare_default = compare_results(
721 neigh_default_nflann, neigh_default_brute,
722 {"nflann_tree_default", "brute_force_default"}, -1, true);
723
724 auto nflann_brute_compare_exclude = compare_results(
725 neigh_exclude_nflann, neigh_exclude_brute,
726 {"nflann_tree_exclude", "brute_force_exclude"}, -1, true);
727
728 auto nflann_brute_compare_include = compare_results(
729 neigh_include_nflann, neigh_include_brute,
730 {"nflann_tree_include", "brute_force_include"}, -1, true);
731
732 std::ostringstream msg;
733 msg << std::format(" Setup times (microseconds): \n"
734 " nflann_tree_set_time = {}\n",
735 data.d_treeBuildTime);
736
737 msg << std::format(" Default search times (microseconds): \n"
738 " brute_force_search_time = {}\n"
739 " nflann_tree_search_time = {}\n",
740 data.d_defaultBruteSearchTime,
741 data.d_defaultNFlannSearchTime);
742
743 msg << std::format(" Exclude comparison results: \n"
744 " nflann_brute_compare: \n{}\n",
745 nflann_brute_compare_default);
746
747 msg << std::format(" Exclude search times (microseconds): \n"
748 " brute_force_search_time = {}\n"
749 " nflann_tree_search_time = {}\n",
750 data.d_excludeBruteSearchTime,
751 data.d_excludeNFlannSearchTime);
752
753 msg << std::format(" Exclude comparison results: \n"
754 " nflann_brute_compare: \n{}\n",
755 nflann_brute_compare_exclude);
756
757 msg << std::format(" Include search times (microseconds): \n"
758 " brute_force_search_time = {}\n"
759 " nflann_tree_search_time = {}\n",
760 data.d_includeBruteSearchTime,
761 data.d_includeNFlannSearchTime);
762
763 msg << std::format(" Include comparison results: \n"
764 " nflann_brute_compare: \n{}\n",
765 nflann_brute_compare_include);
766
767
768 msg << std::format(" Nflann all search times (microseconds): \n"
769 " default = {}\n"
770 " exclude = {}\n"
771 " include = {}\n",
772 data.d_defaultNFlannSearchTime,
773 data.d_excludeNFlannSearchTime,
774 data.d_includeNFlannSearchTime);
775
776 return msg.str();
777
778
779}
void assignRandomTags(std::vector< util::Point > &x, int numTags, int seed, std::vector< size_t > &xTags)
double neighSearchBruteExcludeInclude(const std::vector< util::Point > &x, const std::vector< size_t > &xTags, const double &r, std::vector< std::vector< size_t > > &neigh, std::vector< std::vector< float > > &neigh_sq_dist, int selection_criteria)
double neighSearchTreeSizetExcludeInclude(const std::vector< util::Point > &x, const std::vector< size_t > &xTags, const std::unique_ptr< NSearch > &nsearch, const double &r, std::vector< std::vector< size_t > > &neigh, std::vector< std::vector< float > > &neigh_sq_dist, int selection_criteria)
Definition contact.h:20

References anonymous_namespace{testNSearchLib.cpp}::assignRandomTags(), anonymous_namespace{testNSearchLib.cpp}::compare_results(), anonymous_namespace{testNSearchLib.cpp}::lattice(), anonymous_namespace{testNSearchLib.cpp}::neighSearchBrute(), anonymous_namespace{testNSearchLib.cpp}::neighSearchBruteExcludeInclude(), anonymous_namespace{testNSearchLib.cpp}::neighSearchTreeSizet(), and anonymous_namespace{testNSearchLib.cpp}::neighSearchTreeSizetExcludeInclude().

Here is the call graph for this function:

◆ testPatchQuad()

void test::testPatchQuad ( )

Perform test on quadrature points on line elements (NOT IMPLEMENTED)

This function performs accuracy test of the quadrature points for integration over reference line with vertices at {-1, 1}. List of tests are as follows:

  1. Computes quadrature points of the given order, writes them to the file, and checks if the sum of quadrature weights is equal to 0.5 (area of reference triangle).

Also tests the exactness of the integration of the polynomial upto given order. Suppose \( n\) is the order of quadrature point, then we test if the integration of the function \( f(s,t) = s^\alpha\, t^\beta \) is exact for \( \alpha \) and \( \beta \) such that \( \alpha+\beta \leq n \). The exact integration of function \( f\) over reference triangle is

\[ I_{exact} = \int_0^1 \int_0^{1-s} s^\alpha\, t^\beta \, dt\, ds = \sum_{i=0}^{\beta+1} (-1)^i \frac{{{\beta + 1} \choose i}}{(\alpha + i +1) (\beta + 1)}, \]

where

\[ {a \choose b} = \frac{a (a-1) (a-2) ... (a-b+1)}{1*2*3 ... *b}. \]

We have \( {a \choose 0} = 1 \) so that term for \( i=0\) is not zero. Above formula gives the exact value of integral of \( f(s,t) = s^\alpha\, t^\beta \) over reference triangle. Approximation by quadrature point is as follows

\[ I_{approx} = \sum_{q=1}^{Q} w_q f(s_q, t_q) \]

where \(Q\) is the total number of quad points, \( w_q\) and \((s_q, t_q)\) are the \( q^{th} \) quad weight and point. In this test, we compare \( I_{exact} \) and \( I_{approx} \) and report problem if both do not match.

  1. Test the accuracy for simple quadrangle mesh on square domain [0,1]^2. Exact integration of polynomial \( f(x,y) = x^\alpha \, y^\beta \) on \([0,1]^2\) is given by

    \[ I_{exact} = \frac{1}{(\alpha+1) (\beta+1)}. \]

    We compare above with the approximation computed from the quadrature points. We consider \(\alpha + \beta \leq n \) where \( n\) is the order of approximation we are testing.
Parameters
nOrder of quadrature point approximation
filepathPath where mesh data for test can be found (expects files 'triMesh_nodes.csv' and 'triMesh_elements.csv' inside the filepath)

Definition at line 827 of file testFeLib.cpp.

827 {
828 const double ptol = 1.0e-5;
829 fe::QuadElem quad(1);
830 const std::vector<util::Point> nodes = {
831 util::Point(0., 0., 0.), util::Point(1., 0., 0.),
832 util::Point(1., 1., 0.), util::Point(0., 1., 0.)};
833 const std::vector<util::Point> u = {
834 util::Point(0., 0., 0.), util::Point(2., 0., 0.),
835 util::Point(2., 3., 0.), util::Point(0., 3., 0.)};
836 auto qds = quad.getQuadDatas(nodes);
837 size_t nfail = 0;
838 for (const auto &qd : qds) {
839 auto e = strainFromB(fe::B(qd.d_derShapes, 2), u);
840 if (std::abs(e(0, 0) - 2.) > ptol || std::abs(e(1, 1) - 3.) > ptol ||
841 std::abs(e(0, 1)) > ptol)
842 nfail++;
843 }
844 std::cout << "**********************************\n";
845 std::cout << "Patch test (quad, linear u)\n";
846 std::cout << "**********************************\n";
847 if (nfail) {
848 std::cout << "PATCH QUAD : FAIL.\n";
849 exit(EXIT_FAILURE);
850 }
851 std::cout << "PATCH QUAD : PASS.\n";
852}
A class for mapping and quadrature related operations for bi-linear quadrangle element.
Definition quadElem.h:64
util::SymMatrix3 strainFromB(const fe::B &B, const std::vector< util::Point > &u)
Definition testFeLib.cpp:31

References fe::BaseElem::getQuadDatas(), and anonymous_namespace{testFeLib.cpp}::strainFromB().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ testPatchTet()

void test::testPatchTet ( )

Perform test on quadrature points on line elements (NOT IMPLEMENTED)

This function performs accuracy test of the quadrature points for integration over reference line with vertices at {-1, 1}. List of tests are as follows:

  1. Computes quadrature points of the given order, writes them to the file, and checks if the sum of quadrature weights is equal to 0.5 (area of reference triangle).

Also tests the exactness of the integration of the polynomial upto given order. Suppose \( n\) is the order of quadrature point, then we test if the integration of the function \( f(s,t) = s^\alpha\, t^\beta \) is exact for \( \alpha \) and \( \beta \) such that \( \alpha+\beta \leq n \). The exact integration of function \( f\) over reference triangle is

\[ I_{exact} = \int_0^1 \int_0^{1-s} s^\alpha\, t^\beta \, dt\, ds = \sum_{i=0}^{\beta+1} (-1)^i \frac{{{\beta + 1} \choose i}}{(\alpha + i +1) (\beta + 1)}, \]

where

\[ {a \choose b} = \frac{a (a-1) (a-2) ... (a-b+1)}{1*2*3 ... *b}. \]

We have \( {a \choose 0} = 1 \) so that term for \( i=0\) is not zero. Above formula gives the exact value of integral of \( f(s,t) = s^\alpha\, t^\beta \) over reference triangle. Approximation by quadrature point is as follows

\[ I_{approx} = \sum_{q=1}^{Q} w_q f(s_q, t_q) \]

where \(Q\) is the total number of quad points, \( w_q\) and \((s_q, t_q)\) are the \( q^{th} \) quad weight and point. In this test, we compare \( I_{exact} \) and \( I_{approx} \) and report problem if both do not match.

  1. Test the accuracy for simple quadrangle mesh on square domain [0,1]^2. Exact integration of polynomial \( f(x,y) = x^\alpha \, y^\beta \) on \([0,1]^2\) is given by

    \[ I_{exact} = \frac{1}{(\alpha+1) (\beta+1)}. \]

    We compare above with the approximation computed from the quadrature points. We consider \(\alpha + \beta \leq n \) where \( n\) is the order of approximation we are testing.
Parameters
nOrder of quadrature point approximation
filepathPath where mesh data for test can be found (expects files 'triMesh_nodes.csv' and 'triMesh_elements.csv' inside the filepath)

Definition at line 854 of file testFeLib.cpp.

854 {
855 const double ptol = 1.0e-5;
856 fe::TetElem tet(1);
857 const std::vector<util::Point> nodes = {
858 util::Point(0., 0., 0.), util::Point(1., 0., 0.),
859 util::Point(0., 1., 0.), util::Point(0., 0., 1.)};
860 const std::vector<util::Point> u = {
861 util::Point(0., 0., 0.), util::Point(2., 0., 0.),
862 util::Point(0., 3., 0.), util::Point(0., 0., 4.)};
863 auto qds = tet.getQuadDatas(nodes);
864 size_t nfail = 0;
865 for (const auto &qd : qds) {
866 auto e = strainFromB(fe::B(qd.d_derShapes, 3), u);
867 if (std::abs(e(0, 0) - 2.) > ptol || std::abs(e(1, 1) - 3.) > ptol ||
868 std::abs(e(2, 2) - 4.) > ptol || std::abs(e(0, 1)) > ptol ||
869 std::abs(e(0, 2)) > ptol || std::abs(e(1, 2)) > ptol)
870 nfail++;
871 }
872 std::cout << "**********************************\n";
873 std::cout << "Patch test (tet, linear u)\n";
874 std::cout << "**********************************\n";
875 if (nfail) {
876 std::cout << "PATCH TET : FAIL.\n";
877 exit(EXIT_FAILURE);
878 }
879 std::cout << "PATCH TET : PASS.\n";
880}
A class for mapping and quadrature related operations for linear tetrahedron element.
Definition tetElem.h:141

References fe::BaseElem::getQuadDatas(), and anonymous_namespace{testFeLib.cpp}::strainFromB().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ testPatchTri()

void test::testPatchTri ( )

Perform test on quadrature points on line elements (NOT IMPLEMENTED)

This function performs accuracy test of the quadrature points for integration over reference line with vertices at {-1, 1}. List of tests are as follows:

  1. Computes quadrature points of the given order, writes them to the file, and checks if the sum of quadrature weights is equal to 0.5 (area of reference triangle).

Also tests the exactness of the integration of the polynomial upto given order. Suppose \( n\) is the order of quadrature point, then we test if the integration of the function \( f(s,t) = s^\alpha\, t^\beta \) is exact for \( \alpha \) and \( \beta \) such that \( \alpha+\beta \leq n \). The exact integration of function \( f\) over reference triangle is

\[ I_{exact} = \int_0^1 \int_0^{1-s} s^\alpha\, t^\beta \, dt\, ds = \sum_{i=0}^{\beta+1} (-1)^i \frac{{{\beta + 1} \choose i}}{(\alpha + i +1) (\beta + 1)}, \]

where

\[ {a \choose b} = \frac{a (a-1) (a-2) ... (a-b+1)}{1*2*3 ... *b}. \]

We have \( {a \choose 0} = 1 \) so that term for \( i=0\) is not zero. Above formula gives the exact value of integral of \( f(s,t) = s^\alpha\, t^\beta \) over reference triangle. Approximation by quadrature point is as follows

\[ I_{approx} = \sum_{q=1}^{Q} w_q f(s_q, t_q) \]

where \(Q\) is the total number of quad points, \( w_q\) and \((s_q, t_q)\) are the \( q^{th} \) quad weight and point. In this test, we compare \( I_{exact} \) and \( I_{approx} \) and report problem if both do not match.

  1. Test the accuracy for simple quadrangle mesh on square domain [0,1]^2. Exact integration of polynomial \( f(x,y) = x^\alpha \, y^\beta \) on \([0,1]^2\) is given by

    \[ I_{exact} = \frac{1}{(\alpha+1) (\beta+1)}. \]

    We compare above with the approximation computed from the quadrature points. We consider \(\alpha + \beta \leq n \) where \( n\) is the order of approximation we are testing.
Parameters
nOrder of quadrature point approximation
filepathPath where mesh data for test can be found (expects files 'triMesh_nodes.csv' and 'triMesh_elements.csv' inside the filepath)

Definition at line 800 of file testFeLib.cpp.

800 {
801 const double ptol = 1.0e-5;
802 fe::TriElem tri(1);
803 const std::vector<util::Point> nodes = {
804 util::Point(0., 0., 0.), util::Point(1., 0., 0.),
805 util::Point(0., 1., 0.)};
806 const std::vector<util::Point> u = {
807 util::Point(0., 0., 0.), util::Point(2., 0., 0.),
808 util::Point(0., 3., 0.)};
809 auto qds = tri.getQuadDatas(nodes);
810 size_t nfail = 0;
811 for (const auto &qd : qds) {
812 auto e = strainFromB(fe::B(qd.d_derShapes, 2), u);
813 if (std::abs(e(0, 0) - 2.) > ptol || std::abs(e(1, 1) - 3.) > ptol ||
814 std::abs(e(0, 1)) > ptol)
815 nfail++;
816 }
817 std::cout << "**********************************\n";
818 std::cout << "Patch test (triangle, linear u)\n";
819 std::cout << "**********************************\n";
820 if (nfail) {
821 std::cout << "PATCH TRI : FAIL.\n";
822 exit(EXIT_FAILURE);
823 }
824 std::cout << "PATCH TRI : PASS.\n";
825}
A class for mapping and quadrature related operations for linear triangle element.
Definition triElem.h:91

References fe::BaseElem::getQuadDatas(), and anonymous_namespace{testFeLib.cpp}::strainFromB().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ testPatchTriDistorted()

void test::testPatchTriDistorted ( )

Perform test on quadrature points on line elements (NOT IMPLEMENTED)

This function performs accuracy test of the quadrature points for integration over reference line with vertices at {-1, 1}. List of tests are as follows:

  1. Computes quadrature points of the given order, writes them to the file, and checks if the sum of quadrature weights is equal to 0.5 (area of reference triangle).

Also tests the exactness of the integration of the polynomial upto given order. Suppose \( n\) is the order of quadrature point, then we test if the integration of the function \( f(s,t) = s^\alpha\, t^\beta \) is exact for \( \alpha \) and \( \beta \) such that \( \alpha+\beta \leq n \). The exact integration of function \( f\) over reference triangle is

\[ I_{exact} = \int_0^1 \int_0^{1-s} s^\alpha\, t^\beta \, dt\, ds = \sum_{i=0}^{\beta+1} (-1)^i \frac{{{\beta + 1} \choose i}}{(\alpha + i +1) (\beta + 1)}, \]

where

\[ {a \choose b} = \frac{a (a-1) (a-2) ... (a-b+1)}{1*2*3 ... *b}. \]

We have \( {a \choose 0} = 1 \) so that term for \( i=0\) is not zero. Above formula gives the exact value of integral of \( f(s,t) = s^\alpha\, t^\beta \) over reference triangle. Approximation by quadrature point is as follows

\[ I_{approx} = \sum_{q=1}^{Q} w_q f(s_q, t_q) \]

where \(Q\) is the total number of quad points, \( w_q\) and \((s_q, t_q)\) are the \( q^{th} \) quad weight and point. In this test, we compare \( I_{exact} \) and \( I_{approx} \) and report problem if both do not match.

  1. Test the accuracy for simple quadrangle mesh on square domain [0,1]^2. Exact integration of polynomial \( f(x,y) = x^\alpha \, y^\beta \) on \([0,1]^2\) is given by

    \[ I_{exact} = \frac{1}{(\alpha+1) (\beta+1)}. \]

    We compare above with the approximation computed from the quadrature points. We consider \(\alpha + \beta \leq n \) where \( n\) is the order of approximation we are testing.
Parameters
nOrder of quadrature point approximation
filepathPath where mesh data for test can be found (expects files 'triMesh_nodes.csv' and 'triMesh_elements.csv' inside the filepath)

Definition at line 882 of file testFeLib.cpp.

882 {
883 const double ptol = 1.0e-5;
884 fe::TriElem tri(1);
885 const std::vector<util::Point> nodes = {
886 util::Point(0., 0., 0.), util::Point(1.3, 0.2, 0.),
887 util::Point(0.15, 1.1, 0.)};
888 const std::vector<util::Point> u = {
889 util::Point(0., 0., 0.), util::Point(2.6, 0.6, 0.),
890 util::Point(0.3, 3.3, 0.)};
891 auto qds = tri.getQuadDatas(nodes);
892 size_t nfail = 0;
893 for (const auto &qd : qds) {
894 auto e = strainFromB(fe::B(qd.d_derShapes, 2), u);
895 if (std::abs(e(0, 0) - 2.) > ptol || std::abs(e(1, 1) - 3.) > ptol ||
896 std::abs(e(0, 1)) > ptol)
897 nfail++;
898 }
899 std::cout << "**********************************\n";
900 std::cout << "Patch test (distorted triangle, linear u)\n";
901 std::cout << "**********************************\n";
902 if (nfail) {
903 std::cout << "PATCH TRI DISTORTED : FAIL.\n";
904 exit(EXIT_FAILURE);
905 }
906 std::cout << "PATCH TRI DISTORTED : PASS.\n";
907}

References fe::BaseElem::getQuadDatas(), and anonymous_namespace{testFeLib.cpp}::strainFromB().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ testQuadElem()

void test::testQuadElem ( size_t  n,
std::string  filepath 
)

Perform test on quadrature points on quadrangle elements.

This function performs accuracy test of the quadrature points for integration over reference triangle with vertices at {(0,0), (1,0), (0,1)}. List of tests are as follows:

  1. Computes quadrature points of the given order, writes them to the file, and checks if the sum of quadrature weights is equal to 2, i.e. area of reference quadrangle element.

Also tests the exactness of the integration of the polynomial upto given order. Suppose \( n\) is the order of quadrature point, then we test if the integration of the function \( f(s,t) = s^\alpha\, t^\beta \) is exact for \( \alpha \) and \( \beta \) such that \( \alpha+\beta \leq n \). The exact integration of function \( f\) over reference triangle is

\[ I_{exact} = \int_0^1 \int_0^{1-s} s^\alpha\, t^\beta \, dt\, ds = \sum_{i=0}^{\beta+1} (-1)^i \frac{{{\beta + 1} \choose i}}{(\alpha + i +1) (\beta + 1)}, \]

where

\[ {a \choose b} = \frac{a (a-1) (a-2) ... (a-b+1)}{1*2*3 ... *b}. \]

We have \( {a \choose 0} = 1 \) so that term for \( i=0\) is not zero. Above formula gives the exact value of integral of \( f(s,t) = s^\alpha\, t^\beta \) over reference triangle. Approximation by quadrature point is as follows

\[ I_{approx} = \sum_{q=1}^{Q} w_q f(s_q, t_q) \]

where \(Q\) is the total number of quad points, \( w_q\) and \((s_q, t_q)\) are the \( q^{th} \) quad weight and point. In this test, we compare \( I_{exact} \) and \( I_{approx} \) and report problem if both do not match.

  1. Test the accuracy for simple quadrangle mesh on square domain [0,1]^2. Exact integration of polynomial \( f(x,y) = x^\alpha \, y^\beta \) on \([0,1]^2\) is given by

    \[ I_{exact} = \frac{1}{(\alpha+1) (\beta+1)}. \]

    We compare above with the approximation computed from the quadrature points. We consider \(\alpha + \beta \leq n \) where \( n\) is the order of approximation we are testing.
Parameters
nOrder of quadrature point approximation
filepathPath where mesh data for test can be found (expects files 'quadMesh_nodes.csv' and 'quadMesh_elements.csv' inside the filepath)

Definition at line 384 of file testFeLib.cpp.

384 {
385
386 //
387 // Test1: We test accuracy of integrals of polynomials over reference
388 // quadrangle. Reference triangle {(-1,-1), (1,-1), (1,1), (-1,1)}.
389 //
390 // Test2: We consider simple mesh in meshFeTest.txt over square domain
391 // [0,1]^2 and test the accuracy of polynomials over square domain.
392 //
393
394 // get Quadrature
395 auto quad = fe::QuadElem(n);
396
397 //
398 // Test 1
399 //
400 size_t error_test_1 = 0;
401 {
402 // T1 (reference quadrangle)
403 // get quad points at reference triangle
404 std::vector<util::Point> nodes = {
405 util::Point(-1., -1., 0.), util::Point(1., -1., 0.),
406 util::Point(1., 1., 0.), util::Point(-1., 1., 0.)};
407 std::vector<fe::QuadData> qds = quad.getQuadPoints(nodes);
408 double sum = 0.;
409 for (auto qd : qds)
410 sum += qd.d_w;
411
412 if (std::abs(sum - 4.0) > tol) {
413 std::cout << "Error in order = " << n
414 << ". Sum of quad weights is not "
415 "equal to area of reference "
416 "quadrangle.\n";
417 error_test_1++;
418 }
419
420 //
421 // test the exactness of integration for polynomial
422 //
423 for (size_t i = 0; i <= 2 * n - 1; i++)
424 for (size_t j = 0; j <= 2 * n - 1; j++) {
425
426 //
427 // when {(-1,-1), (1,-1), (1,1), (-1,1)}
428 //
429 nodes = {util::Point(-1., -1., 0.), util::Point(1., -1., 0.),
430 util::Point(1., 1., 0.), util::Point(-1., 1., 0.)};
431 qds = quad.getQuadPoints(nodes);
432 // test integration of polynomial f(s,t) = s^i t^j
433 // get the exact integration
434 double I_exact = test::getExactIntegrationRefQuad(i, j);
435 if (!checkRefIntegration(n, i, j, qds, I_exact))
436 error_test_1++;
437
438 //
439 // when {(-1,1), (-1,-1), (1,-1), (1,1)}
440 //
441 nodes = {util::Point(-1., 1., 0.), util::Point(-1., -1., 0.),
442 util::Point(1., -1., 0.), util::Point(1., 1., 0.)};
443 qds = quad.getQuadPoints(nodes);
444 //
445 // After changing the order of vertices, we have got a new
446 // triangle which is in coordinate system (x,y) and we are
447 // integrating function f(x,y) = x^i y^j
448 //
449 // The quad data we have got is such that quad point is in (x,y)
450 // coordinate, weight is such that determinant of the Jacobian is
451 // included in the weight.
452 //
453 // Thus the following method for I_approx is correct.
454 if (!checkRefIntegration(n, i, j, qds, I_exact))
455 error_test_1++;
456
457 //
458 // when {(1,1), (-1,1), (-1,-1), (1,-1)}
459 //
460 nodes = {util::Point(1., 1., 0.), util::Point(-1., 1., 0.),
461 util::Point(-1., -1., 0.), util::Point(1., -1., 0.)};
462 qds = quad.getQuadPoints(nodes);
463 if (!checkRefIntegration(n, i, j, qds, I_exact))
464 error_test_1++;
465
466 //
467 // when {(1,-1), (1,1), (-1,1), (-1,-1)}
468 //
469 nodes = {util::Point(1., -1., 0.), util::Point(1., 1., 0.),
470 util::Point(-1., 1., 0.), util::Point(-1., -1., 0.)};
471 qds = quad.getQuadPoints(nodes);
472 if (!checkRefIntegration(n, i, j, qds, I_exact))
473 error_test_1++;
474 }
475 } // Test 1
476
477 //
478 // Test 2
479 //
480 size_t error_test_2 = 0;
481 {
482 static std::vector<util::Point> nodes;
483 static std::vector<size_t> elements;
484 static size_t num_vertex = 4;
485 static size_t elem_type = util::vtk_type_quad;
486 static size_t num_elems = 0;
487 if (num_elems == 0) {
488 readNodes(filepath + "/quadMesh_nodes.csv", nodes);
489 num_elems = readElements(filepath + "/quadMesh_elements.csv", elem_type,
490 elements);
491 }
492
493 // loop over polynomials
494 for (size_t i = 0; i <= 2 * n - 1; i++)
495 for (size_t j = 0; j <= 2 * n - 1; j++) {
496
497 double I_exact = 1. / (double(i + 1) * double(j + 1));
498 double I_approx = 0.;
499 // loop over elements and compute I_approx
500 for (size_t e = 0; e < num_elems; e++) {
501 std::vector<util::Point> enodes = {
502 nodes[elements[num_vertex * e + 0]],
503 nodes[elements[num_vertex * e + 1]],
504 nodes[elements[num_vertex * e + 2]],
505 nodes[elements[num_vertex * e + 3]]};
506 std::vector<fe::QuadData> qds = quad.getQuadPoints(enodes);
507 for (auto qd : qds)
508 I_approx +=
509 qd.d_w * std::pow(qd.d_p.d_x, i) * std::pow(qd.d_p.d_y, j);
510 }
511
512 if (std::abs(I_exact - I_approx) > tol) {
513 std::cout << "Error in order = " << n
514 << ". Exact integration = " << I_exact
515 << " and approximate integration = " << I_approx
516 << " of polynomial of order (i = " << i << " + j = " << j
517 << ") = " << i + j << " over square domain [0,1]x[0,1] "
518 << "is not matching using quadrature points.\n";
519
520 error_test_2++;
521 }
522 }
523 }
524
525 if (n == 1) {
526 std::cout << "**********************************\n";
527 std::cout << "Quadrangle Quadrature Test\n";
528 std::cout << "**********************************\n";
529 }
530 std::cout << "Quad order = " << n << ". ";
531 std::cout << (error_test_1 == 0 ? "TEST 1 : PASS. " : "TEST 1 : FAIL. ");
532 std::cout << (error_test_2 == 0 ? "TEST 2 : PASS. \n" : "TEST 2 : FAIL. \n");
533}
static const int vtk_type_quad
Integer flag for quad element.
size_t readElements(const std::string &filename, const size_t &elem_type, std::vector< size_t > &elements)
Definition testFeLib.cpp:70
void readNodes(const std::string &filename, std::vector< util::Point > &nodes)
Definition testFeLib.cpp:60
bool checkRefIntegration(const size_t &n, const size_t &i, const size_t &j, const std::vector< fe::QuadData > &qds, double &I_exact)
double getExactIntegrationRefQuad(size_t alpha, size_t beta)
Computes integration of polynomial exactly over reference quadrangle.

References anonymous_namespace{testFeLib.cpp}::checkRefIntegration(), getExactIntegrationRefQuad(), anonymous_namespace{testFeLib.cpp}::readElements(), anonymous_namespace{testFeLib.cpp}::readNodes(), anonymous_namespace{testFeLib.cpp}::tol, and util::vtk_type_quad.

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ testTaskflow()

std::string test::testTaskflow ( size_t  N,
int  seed 
)

Perform test on taskflow.

Parameters
Nsize of vector to profile taskflow
seedSeed
Returns
str Description of the test and its result

Definition at line 221 of file testParallelCompLib.cpp.

221 {
222
223 auto nThreads = util::parallel::getNThreads();
224 util::io::print(std::format("\n\ntestTaskflow(): Number of threads = {}\n\n", nThreads));
225
226 // task: perform N computations in serial and using taskflow for_each
227
228 // generate vector of random numbers
230 auto dist = util::DistributionSample<UniformDistribution>(0., 1., seed);
231
232 std::vector<double> x(N);
233 std::vector<double> y1(N);
234 std::vector<double> y2(N);
235 std::generate(std::begin(x), std::end(x), [&] { return dist(); });
236
237 // now do serial calculation
238 auto t1 = steady_clock::now();
239 for (size_t i = 0; i < N; i++) {
240 if (x[i] < 0.5)
241 y1[i] = f1(x[i]);
242 else
243 y1[i] = f2(x[i]);
244 }
245 auto t2 = steady_clock::now();
246 auto dt12 = util::methods::timeDiff(t1, t2, "microseconds");
247
248 // now do parallel calculation using taskflow
249 tf::Executor executor(nThreads);
250 tf::Taskflow taskflow;
251
252 taskflow.for_each_index((std::size_t) 0, N, (std::size_t) 1, [&x, &y2](std::size_t i) {
253 if (x[i] < 0.5)
254 y2[i] = f1(x[i]);
255 else
256 y2[i] = f2(x[i]);
257 }
258 ); // for_each
259
260 executor.run(taskflow).get();
261 auto t3 = steady_clock::now();
262 auto dt23 = util::methods::timeDiff(t2, t3, "microseconds");
263
264 // compare results
265 double y_err = 0.;
266 for (size_t i=0; i<N; i++)
267 y_err += std::pow(y1[i] - y2[i], 2);
268
269 if (y_err > 1.e-10) {
270 std::cerr << std::format("Error: Serial and taskflow computation results do not match (squared error = {})\n",
271 y_err);
272 exit(1);
273 }
274
275 // get time
276 std::ostringstream msg;
277 msg << std::format(" Serial computation took = {}ms\n", dt12);
278 msg << std::format(" Taskflow computation took = {}ms\n", dt23);
279 msg << std::format(" Speed-up factor = {}\n\n\n", dt12/dt23);
280
281 return msg.str();
282}
Templated probability distribution.
Definition randomDist.h:90
unsigned int getNThreads()
Get number of threads to be used by taskflow.
RandGenerator get_rd_gen(int seed=-1)
Return random number generator.
Definition randomDist.h:30
std::mt19937 RandGenerator
Definition randomDist.h:16

References anonymous_namespace{testParallelCompLib.cpp}::f1(), anonymous_namespace{testParallelCompLib.cpp}::f2(), util::get_rd_gen(), util::parallel::getNThreads(), util::io::print(), and util::methods::timeDiff().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ testTetElem()

void test::testTetElem ( size_t  n,
std::string  filepath 
)

Perform test on quadrature points on tetrahedral elements.

Parameters
nOrder of quadrature point approximation
filepathPath where mesh data for test can be found (expects files 'tetMesh_nodes.csv' and 'tetMesh_elements.csv' inside the filepath)

Definition at line 608 of file testFeLib.cpp.

608 {
609
610 //
611 // Test1: We test accuracy of integrals of polynomials over reference
612 // tetrahedron. Reference element {(0,0,0), (1,0,0), (0,1,0), (0,0,1)}.
613 //
614 // Test2: We consider simple mesh in meshFeTest.txt over cubic domain
615 // [0,1]^3 and test the accuracy of polynomials over cubic domain.
616 //
617
618 // get Quadrature
619 auto quad = fe::TetElem(n);
620
621 //
622 // Test 1
623 //
624 size_t error_test_1 = 0;
625 {
626 // T1 (reference triangle)
627 // get quad points at reference triangle
628 std::vector<util::Point> nodes = {util::Point(), util::Point(1., 0., 0.),
629 util::Point(0., 1., 0.),
630 util::Point(0., 0., 1.)};
631 std::vector<fe::QuadData> qds = quad.getQuadPoints(nodes);
632
633 double sum = 0.;
634 for (auto qd : qds)
635 sum += qd.d_w;
636
637 if (std::abs(sum - 1. / 6.) > tol) {
638 std::cout << "Error in order = " << n
639 << ". Sum of quad weights is not "
640 "equal to volume of reference "
641 "tetrahedron.\n";
642 error_test_1++;
643 }
644
645 //
646 // test the exactness of integration for polynomial
647 //
648 for (size_t i = 0; i <= n; i++)
649 for (size_t j = 0; j <= n; j++)
650 for (size_t k = 0; k <= n; k++) {
651
652 if (i + j + k > n)
653 continue;
654
655 //
656 // +ve order of indices are:
657 // {0,1,2,3}; {1,2,0,3}; {2,3,0,1}; {0,3,1,2}
658
659 //
660 // when {(0,0,0), (1,0,0), (0,1,0), (0,0,1)}
661 //
662 nodes = {util::Point(), util::Point(1., 0., 0.),
663 util::Point(0., 1., 0.), util::Point(0., 0., 1.)};
664 qds = quad.getQuadPoints(nodes);
665 // test integration of polynomial f(s,t) = s^i t^j
666 // get the exact integration
667 debug_id = 0;
668 double I_exact = test::getExactIntegrationRefTet(i, j, k);
669 if (!checkRefIntegration(n, i, j, k, qds, I_exact)) {
670 error_test_1++;
671 }
672
673 //
674 // when vertices are {(1,0,0), (0,1,0), (0,0,1), (0,0,0)}
675 //
676 nodes = {util::Point(1., 0., 0.), util::Point(0., 1., 0.),
677 util::Point(0., 0., 0.), util::Point(0., 0., 1.)};
678 qds = quad.getQuadPoints(nodes);
679 //
680 // After changing the order of vertices, we have got a new
681 // triangle which is in coordinate system (x,y) and we are
682 // integrating function f(x,y) = x^i y^j
683 //
684 // The quad data we have got is such that quad point is in (x,y)
685 // coordinate, weight is such that determinant of the Jacobian is
686 // included in the weight.
687 //
688 // Thus the following method for I_approx is correct.
689 debug_id = 1;
690 if (!checkRefIntegration(n, i, j, k, qds, I_exact))
691 error_test_1++;
692
693 //
694 // when vertices are {(0,1,0), (0,0,1), (0,0,0), (1,0,0)}
695 //
696 nodes = {util::Point(0., 1., 0.), util::Point(0., 0., 1.),
697 util::Point(0., 0., 0.), util::Point(1., 0., 0.)};
698 qds = quad.getQuadPoints(nodes);
699 debug_id = 2;
700 if (!checkRefIntegration(n, i, j, k, qds, I_exact))
701 error_test_1++;
702
703 //
704 // when vertices are {(0,0,1), (0,0,0), (1,0,0), (0,1,0)}
705 //
706 nodes = {util::Point(0., 0., 0.), util::Point(0., 0., 1.),
707 util::Point(1., 0., 0.), util::Point(0., 1., 0.)};
708 qds = quad.getQuadPoints(nodes);
709 debug_id = 3;
710 if (!checkRefIntegration(n, i, j, k, qds, I_exact))
711 error_test_1++;
712 }
713 } // Test 1
714
715 //
716 // Test 2
717 //
718 size_t error_test_2 = 0;
719 if (false) {
720 static std::vector<util::Point> nodes;
721 static std::vector<size_t> elements;
722 static size_t num_vertex = 4;
723 static size_t elem_type = util::vtk_type_tetra;
724 static size_t num_elems = 0;
725 if (num_elems == 0) {
726 readNodes(filepath + "tetMesh_nodes.csv", nodes);
727 num_elems = readElements(filepath + "tetMesh_elements.csv", elem_type,
728 elements);
729 }
730
731 // loop over polynomials
732 for (size_t i = 0; i <= n; i++)
733 for (size_t j = 0; j <= n; j++)
734 for (size_t k = 0; k <= n; k++) {
735
736 if (i + j + k > n)
737 continue;
738
739 double I_exact = 1. / (double(i + 1) * double(j + 1) * double(k + 1));
740 double I_approx = 0.;
741 // loop over elements and compute I_approx
742 for (size_t e = 0; e < num_elems; e++) {
743 std::vector<util::Point> enodes = {
744 nodes[elements[num_vertex * e + 0]],
745 nodes[elements[num_vertex * e + 1]],
746 nodes[elements[num_vertex * e + 2]],
747 nodes[elements[num_vertex * e + 3]]};
748 std::vector<fe::QuadData> qds = quad.getQuadPoints(enodes);
749 for (auto qd : qds) {
750 I_approx += qd.d_w * std::pow(qd.d_p.d_x, i) *
751 std::pow(qd.d_p.d_y, j) * std::pow(qd.d_p.d_z, k);
752
753 if (false) {
754
755 std::cout << "Print " << i << " " << j << " " << k << "\n";
756 std::cout << util::io::printStr(enodes) << "\n";
757 std::vector<size_t> enode_ids = {
758 elements[num_vertex * e + 0],
759 elements[num_vertex * e + 1],
760 elements[num_vertex * e + 2],
761 elements[num_vertex * e + 3]};
762 std::cout << util::io::printStr(enode_ids) << "\n";
763 std::cout << qd.printStr() << "\n";
764 }
765
766 }
767 }
768
769 if (std::abs(I_exact - I_approx) > tol) {
770 std::cout << "Error in order = " << n
771 << ". Exact integration = " << I_exact
772 << " and approximate integration = " << I_approx
773 << " of polynomial of order (i = " << i << " + j = " << j
774 << " + k = " << k << ") = " << i + j + k
775 << " over cubic domain [0,1]x[0,1]x[0,1] "
776 << "is not matching using quadrature points.\n";
777
778 error_test_2++;
779 }
780 }
781 }
782
783 if (n == 1) {
784 std::cout << "**********************************\n";
785 std::cout << "Tetrahedron Quadrature Test\n";
786 std::cout << "**********************************\n";
787 }
788 std::cout << "Quad order = " << n << ". ";
789 if (error_test_1 == 0)
790 std::cout << "TEST 1 : PASS. ";
791 else
792 std::cout << "TEST 1 : FAIL. ";
793 // if (error_test_2 == 0)
794 // std::cout << "TEST 2 : PASS. ";
795 // else
796 // std::cout << "TEST 2 : FAIL. ";
797 std::cout << "\n";
798}
static const int vtk_type_tetra
Integer flag for tetrahedron element.
double getExactIntegrationRefTet(size_t alpha, size_t beta, size_t theta)
Computes integration of polynomial exactly over reference tetrahedral.
std::string printStr(const T &msg, int nt=print_default_tab)
Returns formatted string for output.
Definition io.h:96

References anonymous_namespace{testFeLib.cpp}::checkRefIntegration(), anonymous_namespace{testFeLib.cpp}::debug_id, getExactIntegrationRefTet(), util::io::printStr(), anonymous_namespace{testFeLib.cpp}::readElements(), anonymous_namespace{testFeLib.cpp}::readNodes(), anonymous_namespace{testFeLib.cpp}::tol, and util::vtk_type_tetra.

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ testTriElem()

void test::testTriElem ( size_t  n,
std::string  filepath 
)

Perform test on quadrature points on triangle elements.

This function performs accuracy test of the quadrature points for integration over reference triangle with vertices at {(0,0), (1,0), (0,1)}. List of tests are as follows:

  1. Computes quadrature points of the given order, writes them to the file, and checks if the sum of quadrature weights is equal to 0.5, i.e. area of reference triangle.

Also tests the exactness of the integration of the polynomial upto given order. Suppose \( n\) is the order of quadrature point, then we test if the integration of the function \( f(s,t) = s^\alpha\, t^\beta \) is exact for \( \alpha \) and \( \beta \) such that \( \alpha+\beta \leq n \). The exact integration of function \( f\) over reference triangle is

\[ I_{exact} = \int_0^1 \int_0^{1-s} s^\alpha\, t^\beta \, dt\, ds = \sum_{i=0}^{\beta+1} (-1)^i \frac{{{\beta + 1} \choose i}}{(\alpha + i +1) (\beta + 1)}, \]

where

\[ {a \choose b} = \frac{a (a-1) (a-2) ... (a-b+1)}{1*2*3 ... *b}. \]

We have \( {a \choose 0} = 1 \) so that term for \( i=0\) is not zero. Above formula gives the exact value of integral of \( f(s,t) = s^\alpha\, t^\beta \) over reference triangle. Approximation by quadrature point is as follows

\[ I_{approx} = \sum_{q=1}^{Q} w_q f(s_q, t_q) \]

where \(Q\) is the total number of quad points, \( w_q\) and \((s_q, t_q)\) are the \( q^{th} \) quad weight and point. In this test, we compare \( I_{exact} \) and \( I_{approx} \) and report problem if both do not match.

  1. Test the accuracy for simple triangular mesh on square domain [0,1]^2. Exact integration of polynomial \( f(x,y) = x^\alpha \, y^\beta \) on \([0,1]^2\) is given by

    \[ I_{exact} = \frac{1}{(\alpha+1) (\beta+1)}. \]

    We compare above with the approximation computed from the quadrature points. We consider \(\alpha + \beta \leq n \) where \( n\) is the order of approximation we are testing.
Parameters
nOrder of quadrature point approximation
filepathPath where mesh data for test can be found (expects files 'triMesh_nodes.csv' and 'triMesh_elements.csv' inside the filepath)

Definition at line 231 of file testFeLib.cpp.

231 {
232
233 //
234 // Test1: We test accuracy of integrals of polynomials over reference
235 // triangle. Reference triangle {(0,0), (1,0), (0,1)}.
236 //
237 // Test2: We consider simple mesh in meshFeTest.txt over square domain
238 // [0,1]^2 and test the accuracy of polynomials over square domain.
239 //
240
241 // get Quadrature
242 auto quad = fe::TriElem(n);
243
244 //
245 // Test 1
246 //
247 size_t error_test_1 = 0;
248 {
249 // T1 (reference triangle)
250 // get quad points at reference triangle
251 std::vector<util::Point> nodes = {util::Point(), util::Point(1., 0., 0.),
252 util::Point(0., 1., 0.)};
253 std::vector<fe::QuadData> qds = quad.getQuadPoints(nodes);
254 double sum = 0.;
255 for (auto qd : qds)
256 sum += qd.d_w;
257
258 if (std::abs(sum - 0.5) > tol) {
259 std::cout << "Error in order = " << n
260 << ". Sum of quad weights is not "
261 "equal to area of reference "
262 "triangle.\n";
263 error_test_1++;
264 }
265
266 //
267 // test the exactness of integration for polynomial
268 //
269 for (size_t i = 0; i <= n; i++)
270 for (size_t j = 0; j <= n; j++) {
271
272 if (i + j > n)
273 continue;
274
275 //
276 // when {(0,0), (1,0), (0,1)}
277 //
278 nodes = {util::Point(), util::Point(1., 0., 0.),
279 util::Point(0., 1., 0.)};
280 qds = quad.getQuadPoints(nodes);
281 // test integration of polynomial f(s,t) = s^i t^j
282 // get the exact integration
283 double I_exact = test::getExactIntegrationRefTri(i, j);
284 if (!checkRefIntegration(n, i, j, qds, I_exact))
285 error_test_1++;
286
287 //
288 // when vertices are {(1,0), (0,1), (0,0)}
289 //
290 nodes = {util::Point(1., 0., 0.), util::Point(0., 1., 0.),
291 util::Point()};
292 qds = quad.getQuadPoints(nodes);
293 //
294 // After changing the order of vertices, we have got a new
295 // triangle which is in coordinate system (x,y) and we are
296 // integrating function f(x,y) = x^i y^j
297 //
298 // The quad data we have got is such that quad point is in (x,y)
299 // coordinate, weight is such that determinant of the Jacobian is
300 // included in the weight.
301 //
302 // Thus the following method for I_approx is correct.
303 if (!checkRefIntegration(n, i, j, qds, I_exact))
304 error_test_1++;
305
306 //
307 // when vertices are {(0,1), (0,0), (1,0)}
308 //
309 nodes = {util::Point(0., 1., 0.), util::Point(),
310 util::Point(1., 0., 0.)};
311 qds = quad.getQuadPoints(nodes);
312 if (!checkRefIntegration(n, i, j, qds, I_exact))
313 error_test_1++;
314 }
315 } // Test 1
316
317 //
318 // Test 2
319 //
320 size_t error_test_2 = 0;
321 {
322 static std::vector<util::Point> nodes;
323 static std::vector<size_t> elements;
324 static size_t num_vertex = 3;
325 static size_t elem_type = util::vtk_type_triangle;
326 static size_t num_elems = 0;
327 if (num_elems == 0) {
328 readNodes(filepath + "/triMesh_nodes.csv", nodes);
329 num_elems = readElements(filepath + "/triMesh_elements.csv", elem_type,
330 elements);
331 }
332
333 // loop over polynomials
334 for (size_t i = 0; i <= n; i++)
335 for (size_t j = 0; j <= n; j++) {
336
337 if (i + j > n)
338 continue;
339
340 double I_exact = 1. / (double(i + 1) * double(j + 1));
341 double I_approx = 0.;
342 // loop over elements and compute I_approx
343 for (size_t e = 0; e < num_elems; e++) {
344 std::vector<util::Point> enodes = {
345 nodes[elements[num_vertex * e + 0]],
346 nodes[elements[num_vertex * e + 1]],
347 nodes[elements[num_vertex * e + 2]]};
348 std::vector<fe::QuadData> qds = quad.getQuadPoints(enodes);
349 for (auto qd : qds)
350 I_approx +=
351 qd.d_w * std::pow(qd.d_p.d_x, i) * std::pow(qd.d_p.d_y, j);
352 }
353
354 if (std::abs(I_exact - I_approx) > tol) {
355 std::cout << "Error in order = " << n
356 << ". Exact integration = " << I_exact
357 << " and approximate integration = " << I_approx
358 << " of polynomial of order (i = " << i << " + j = " << j
359 << ") = " << i + j << " over square domain [0,1]x[0,1] "
360 << "is not matching using quadrature points.\n";
361
362 error_test_2++;
363 }
364 }
365 }
366
367 if (n == 1) {
368 std::cout << "**********************************\n";
369 std::cout << "Triangle Quadrature Test\n";
370 std::cout << "**********************************\n";
371 }
372 std::cout << "Quad order = " << n << ". ";
373 if (error_test_1 == 0)
374 std::cout << "TEST 1 : PASS. ";
375 else
376 std::cout << "TEST 1 : FAIL. ";
377 if (error_test_2 == 0)
378 std::cout << "TEST 2 : PASS. ";
379 else
380 std::cout << "TEST 2 : FAIL. ";
381 std::cout << "\n";
382}
static const int vtk_type_triangle
Integer flag for triangle element.
double getExactIntegrationRefTri(size_t alpha, size_t beta)
Computes integration of polynomial exactly over reference triangle.

References anonymous_namespace{testFeLib.cpp}::checkRefIntegration(), getExactIntegrationRefTri(), anonymous_namespace{testFeLib.cpp}::readElements(), anonymous_namespace{testFeLib.cpp}::readNodes(), anonymous_namespace{testFeLib.cpp}::tol, and util::vtk_type_triangle.

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ testTriElemTime()

void test::testTriElemTime ( size_t  n,
size_t  N 
)

Computes the time needed when quad data for elements are stored and when they are computed as and when needed.

This function allocates dummy elements and test how much time it is required to do computation when the quad data are stored for each element and when the quad data are computed.

Parameters
nOrder of quadrature point approximation
NNumber of elements on which this test is performed

Definition at line 535 of file testFeLib.cpp.

535 {
536
537 // get Quadrature
538 auto quad = fe::TriElem(n);
539
540 //
541 // Test 1
542 //
543 std::vector<util::Point> nodes = {util::Point(2., 2., 0.),
544 util::Point(4., 2., 0.),
545 util::Point(2., 4., 0.)};
546 size_t num_vertex = 3;
547 // std::vector<size_t> elements;
548 // for (size_t i = 0; i < 3 * N; i++)
549 // elements.emplace_back(i % 2);
550 std::vector<std::vector<size_t>> elements;
551 for (size_t i = 0; i < N; i++)
552 elements.emplace_back(std::vector<size_t>{0, 1, 2});
553
554 auto t11 = steady_clock::now();
555 // method 1: Compute quad points at each call
556 // loop over elements and compute I_approx
557 double sum = 0.;
558 for (size_t e = 0; e < N; e++) {
559 // std::vector<util::Point> enodes = {nodes[elements[num_vertex * e +
560 // 0]],
561 // nodes[elements[num_vertex * e +
562 // 1]], nodes[elements[num_vertex * e
563 // + 2]]};
564 std::vector<util::Point> enodes = {
565 nodes[elements[e][0]], nodes[elements[e][1]], nodes[elements[e][2]]};
566 std::vector<fe::QuadData> qds = quad.getQuadPoints(enodes);
567 for (auto qd : qds)
568 sum += qd.d_w * (qd.d_shapes[0] + qd.d_shapes[1] + qd.d_shapes[2]);
569 }
570 auto t12 = steady_clock::now();
571
572 // method 2: Compute quad points in the beginning and use it when needed
573 size_t num_quad_pts = 0;
574 std::vector<fe::QuadData> quad_data;
575 for (size_t e = 0; e < N; e++) {
576 std::vector<fe::QuadData> qds = quad.getQuadPoints(nodes);
577 if (e == 0)
578 num_quad_pts = qds.size();
579 for (auto qd : qds)
580 quad_data.emplace_back(qd);
581 }
582
583 auto t21 = steady_clock::now();
584 sum = 0.;
585 for (size_t e = 0; e < N; e++) {
586 for (size_t q = 0; q < num_quad_pts; q++) {
587 fe::QuadData qd = quad_data[e * num_quad_pts + q];
588 sum += qd.d_w * (qd.d_shapes[0] + qd.d_shapes[1] + qd.d_shapes[2]);
589 }
590 }
591 auto t22 = steady_clock::now();
592
593 if (n == 1 and N == 1000) {
594 std::cout << "**********************************\n";
595 std::cout << "Quadrature Time Efficiency Test\n";
596 std::cout << "**********************************\n";
597 }
598 std::cout << "Quad order = " << n << ". Num Elements = " << N << ".\n ";
599 double dt_1 = util::methods::timeDiff(t12, t11, "seconds");
600 double dt_2 = util::methods::timeDiff(t21, t22, "seconds");
601 double perc = (dt_1 - dt_2) * 100. / dt_2;
602 double qpt_mem = 13 * sizeof(double);
603 double mem2 = double(quad_data.capacity() * qpt_mem) / double(1000000);
604 std::cout << " dt1 = " << dt_1 << ", dt2 = " << dt_2 << ", perc = " << perc
605 << ". Mem saved = " << mem2 << " MB.\n";
606}
A struct to store the quadrature data. List of data are.
Definition quadData.h:23
std::vector< double > d_shapes
Value of shape functions at quad point p.
Definition quadData.h:37
double d_w
Quadrature weight.
Definition quadData.h:26

References fe::QuadData::d_shapes, fe::QuadData::d_w, and util::methods::timeDiff().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ testUtilMethods()

void test::testUtilMethods ( )

Test methods

Definition at line 29 of file testUtilLib.cpp.

29 {
30
31 const double tol = 1.e-10;
32
33 //
34 {
35 std::pair<util::Point, util::Point> box = {util::Point(),
36 util::Point(1., 1., 1.)};
37 auto corner_pts = geom::getCornerPoints(3, box);
38 auto edges = geom::getEdges(3, box);
39 auto xc = geom::getCenter(3, box);
40
41 for (size_t i=0; i<2; i++)
42 for (size_t j=0; j<2; j++)
43 for (size_t k=0; k<2; k++) {
44
45 auto p = util::Point(double(i), double(j), double(k));
46 bool found_p = false;
47 for (auto q : corner_pts) {
48 if (q.dist(p) < tol)
49 found_p = true;
50 }
51 if (!found_p)
52 errExit(std::format("Error: Can not find corner point {}\n", p.printStr()));
53 }
54
55 if (xc.dist(util::Point(0.5, 0.5, 0.5)) > tol)
56 errExit("Error: getCenter()\n");
57 }
58
59 //
60 {
61 if (std::abs(geom::triangleArea(util::Point(0., 0., 0.), util::Point(2., 0., 0.), util::Point(1., 1., 0.)) - 1.) > tol)
62 errExit("Error: triangleArea()\n");
63 }
64
65 //
66 {
67 std::vector<double> x = {1., 0., 0.};
68 std::vector<double> y_check = {1./std::sqrt(2.), -1./std::sqrt(2.), 0.};
69 auto y = util::rotateCW2D(x, M_PI * 0.25);
70 if (util::methods::l2Dist(y_check, y) > tol)
71 errExit("Error: rotateCW2D()\n");
72
73 if (util::Point(y_check).dist(util::rotateCW2D(util::Point(x), M_PI * 0.25)) > tol)
74 errExit("Error: rotateCW2D()\n");
75
76 y_check = {1./std::sqrt(2.), 1./std::sqrt(2.), 0.};
77 y = util::rotateACW2D(x, M_PI * 0.25);
78 if (util::methods::l2Dist(y_check, y) > tol)
79 errExit("Error: rotateACW2D()\n");
80 }
81
82 //
83 {
84 auto x = util::Point(1., 0., 0.);
85 auto a = util::Point(0., 0., 1.);
86 auto y_check = util::Point(0., 1., 0.);
87 auto y = util::rotate(x, M_PI * 0.5, a);
88 if (y_check.dist(y) > tol)
89 errExit(std::format("Error: rotate(). y_check = {}, y = {}\n", y_check.printStr(), y.printStr()));
90
91 x = util::Point(1., 1., 1.);
92 y_check = util::Point(-1., 1., 1.);
93 y = util::rotate(x, M_PI * 0.5, a);
94 if (y_check.dist(y) > tol)
95 errExit(std::format("Error: rotate(). y_check = {}, y = {}\n", y_check.printStr(), y.printStr()));
96 }
97
98 //
99 {
100 auto x1 = util::Point(1., 1., 0.);
101 auto x2 = util::Point(1., 0., 0.);
102 if (std::abs(M_PI*0.25 - util::angle(x1, x2)) > tol)
103 errExit("Error: angle()\n");
104
105 x2 = util::Point(0., 0., 1.);
106 if (std::abs(M_PI*0.5 - util::angle(x1, x2)) > tol)
107 errExit("Error: angle()\n");
108
109 x2 = util::Point(0., 1., 1.);
110 if (std::abs(M_PI/3. - util::angle(x1, x2)) > tol)
111 errExit("Error: angle()\n");
112 }
113}
util::Point getCenter(size_t dim, const std::pair< util::Point, util::Point > &box)
Returns center point.
std::vector< std::pair< util::Point, util::Point > > getEdges(size_t dim, const std::pair< util::Point, util::Point > &box)
Returns all corner points in the box.
std::vector< util::Point > getCornerPoints(size_t dim, const std::pair< util::Point, util::Point > &box)
Returns all corner points in the box.
double triangleArea(const util::Point &x1, const util::Point &x2, const util::Point &x3)
Compute area of triangle.
T l2Dist(const std::vector< T > &x1, const std::vector< T > &x2)
Computes l2 distance between two vectors.
Definition vecMethods.h:395
double angle(util::Point a, util::Point b)
Computes angle between two vectors.
std::vector< double > rotateACW2D(const std::vector< double > &x, const double &theta)
Rotates a vector in xy-plane in anti-clockwise direction.
std::vector< double > rotateCW2D(const std::vector< double > &x, const double &theta)
Rotates a vector in xy-plane in clockwise direction.
util::Point rotate(const util::Point &p, const double &theta, const util::Point &axis)
Returns the vector after rotating by desired angle.

References util::angle(), anonymous_namespace{testUtilLib.cpp}::errExit(), geom::getCenter(), geom::getCornerPoints(), geom::getEdges(), util::methods::l2Dist(), util::rotate(), util::rotateACW2D(), util::rotateCW2D(), and geom::triangleArea().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function: