PeriDEM 0.2.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 testTransform ()
 Perform test on Fracture class and check if bitwise functions are working correctly.
 
std::string testPeriDEM (std::string filepath)
 Tests PeriDEM model class.
 
void testUtilMethods ()
 Test methods

 
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.
 

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 163 of file testFeLib.cpp.

163 {
164
165 // compute exact integration of s^\alpha t^\beta
166 if (alpha % 2 == 0 and beta % 2 == 0)
167 return 4. / double((alpha + 1) * (beta + 1));
168 else
169 return 0.;
170}

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 172 of file testFeLib.cpp.

173 {
174
175 double I = 0.;
176 for (size_t i = 0; i <= theta + 1; i++) {
177
178 double factor_i = test::getNChooseR(theta + 1, i) /
179 (double(theta + 1) * double(i + beta + 1));
180 if (i % 2 != 0)
181 factor_i = factor_i * (-1.);
182
183 for (size_t j = 0; j <= theta + beta + 2 + 1; j++) {
184
185 double factor_j =
186 test::getNChooseR(theta + beta + 2, j) / (double(j + alpha + 1));
187 if (j % 2 != 0)
188 factor_j = factor_j * (-1.);
189
190 I += factor_i * factor_j;
191 }
192 }
193
194 return I;
195}
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 147 of file testFeLib.cpp.

147 {
148
149 // compute exact integration of s^\alpha t^\beta
150 double I = 0.;
151 for (size_t k = 0; k <= beta + 1; k++) {
152 if (k % 2 == 0)
153 I +=
154 test::getNChooseR(beta + 1, k) / double((alpha + 1 + k) * (beta + 1));
155 else
156 I -=
157 test::getNChooseR(beta + 1, k) / double((alpha + 1 + k) * (beta + 1));
158 }
159
160 return I;
161}

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 135 of file testFeLib.cpp.

135 {
136
137 if (r == 0)
138 return 1.;
139
140 double a = 1.;
141 for (size_t i = 1; i <= r; i++)
142 a *= double(n - i + 1) / double(i);
143
144 return a;
145}

Referenced by getExactIntegrationRefTet(), and getExactIntegrationRefTri().

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 << fmt::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 = fe::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 fe::createUniformMesh(&mesh, dim, box, nGridVec);
165
166 // filename for outputting
167 outMeshFilename = fmt::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 << fmt::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 geometry::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 << fmt::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 fe::metisGraphPartition("metis_recursive", nodeNeighs, nodePartitionRecursive, nPart);
217 auto t5 = steady_clock::now();
218
219 // K-way method
220 fe::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 << fmt::format("Partition (Recursive) calculation time (ms) = {}.\n", partition_recursive_time);
226 std::cout << fmt::format("Partition (KWay) calculation time (ms) = {}.\n", partition_kway_time);
227
228 // write data to file
229 outMeshFilename = outMeshFilename + fmt::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:51
A interface class writing data.
Definition writer.h:44
void createUniformMesh(fe::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:23
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 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...
int horizon
peridynamics horizon (typically taken as 2 to 4 times the mesh size)
std::string removeExtensionFromFile(std::string const &filename)
Remove extension from the filename Source - https://stackoverflow.com/a/24386991.
Definition io.h:416
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:404
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 methods.h:304

References geometry::computeNonlocalNeighborhood(), fe::createUniformMesh(), util::io::getFilenameFromPath(), fe::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 // perform basic test that shows metis is linked correctly with the code
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 198 of file testFeLib.cpp.

198{ 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 285 of file testParallelCompLib.cpp.

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

References geometry::computeNonlocalNeighborhood(), fe::createUniformMesh(), anonymous_namespace{testParallelCompLib.cpp}::exchangeDispData(), util::io::getFilenameFromPath(), fe::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 String containing various information

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 << fmt::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 << fmt::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 << fmt::format(" Comparison results: \n"
567 " nflann_brute_compare: \n{}\n",
568 nflann_brute_compare);
569
570 msg << fmt::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 << fmt::format(" Setup times (microseconds): \n"
604 " nflann_tree_set_time = {}\n",
605 nflann_tree_set_time);
606
607 msg << fmt::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 << fmt::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 String containing various information

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 << fmt::format(" Setup times (microseconds): \n"
812 " nflann_tree_set_time = {}\n",
813 nflann_tree_set_time);
814
815 msg << fmt::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 String containing various information

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
676 search_r,
677 neigh_default_brute,
678 neigh_default_brute_sq_dist);
679
681 neighSearchBruteExcludeInclude(x, xTags, search_r,
682 neigh_exclude_brute,
683 neigh_exclude_brute_sq_dist,
684 1);
685
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
701 neighSearchTreeSizet(x, nflann_nsearch,
702 search_r, neigh_default_nflann,
703 neigh_default_nflann_sq_dist);
704
705 // exclude
707 neighSearchTreeSizetExcludeInclude(x, xTags, nflann_nsearch,
708 search_r, neigh_exclude_nflann,
709 neigh_exclude_nflann_sq_dist,
710 1);
711
712 // include
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 << fmt::format(" Setup times (microseconds): \n"
734 " nflann_tree_set_time = {}\n",
735 data.d_treeBuildTime);
736
737 msg << fmt::format(" Default search times (microseconds): \n"
738 " brute_force_search_time = {}\n"
739 " nflann_tree_search_time = {}\n",
742
743 msg << fmt::format(" Exclude comparison results: \n"
744 " nflann_brute_compare: \n{}\n",
745 nflann_brute_compare_default);
746
747 msg << fmt::format(" Exclude search times (microseconds): \n"
748 " brute_force_search_time = {}\n"
749 " nflann_tree_search_time = {}\n",
752
753 msg << fmt::format(" Exclude comparison results: \n"
754 " nflann_brute_compare: \n{}\n",
755 nflann_brute_compare_exclude);
756
757 msg << fmt::format(" Include search times (microseconds): \n"
758 " brute_force_search_time = {}\n"
759 " nflann_tree_search_time = {}\n",
762
763 msg << fmt::format(" Include comparison results: \n"
764 " nflann_brute_compare: \n{}\n",
765 nflann_brute_compare_include);
766
767
768 msg << fmt::format(" Nflann all search times (microseconds): \n"
769 " default = {}\n"
770 " exclude = {}\n"
771 " include = {}\n",
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)

References anonymous_namespace{testNSearchLib.cpp}::assignRandomTags(), anonymous_namespace{testNSearchLib.cpp}::compare_results(), test::testNSearchData::d_defaultBruteSearchTime, test::testNSearchData::d_defaultNFlannSearchTime, test::testNSearchData::d_excludeBruteSearchTime, test::testNSearchData::d_excludeNFlannSearchTime, test::testNSearchData::d_includeBruteSearchTime, test::testNSearchData::d_includeNFlannSearchTime, test::testNSearchData::d_leafMaxSize, test::testNSearchData::d_numPoints, test::testNSearchData::d_numTags, test::testNSearchData::d_treeBuildTime, 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:

◆ testPeriDEM()

std::string test::testPeriDEM ( std::string  filepath)

Tests PeriDEM model class.

Parameters
filepathPath where input file can be found (expects file 'input.yaml' in the filepath)
Returns
string 'pass' if test is successful

Definition at line 23 of file testPeriDEMLib.cpp.

23 {
24
25 // current time
26 auto begin = steady_clock::now();
27
28 // read input data
29 auto *deck = new inp::Input(filepath + "/input.yaml");
30 deck->getOutputDeck()->d_path = filepath + "/out/";
31 std::cout << "filepath = " << deck->getOutputDeck()->d_path << "\n";
32
33 // check which model to run
34 if (deck->isPeriDEM()) {
35 model::DEMModel dem(deck);
36 dem.run(deck);
37 } else {
38 std::cout << "PeriDEM model not found in input file.\n";
39 return "PeriDEM not found in input file";
40 }
41
42 // get time elapsed
43 auto end = steady_clock::now();
44 double elapsed_secs = util::methods::timeDiff(begin, end, "seconds");
45
46 std::cout << "Total simulation time = " << elapsed_secs
47 << " (seconds)" << std::endl;
48
49 return "pass";
50}
A class to read input file.
Definition input.h:61
A class for discrete element particle simulation with peridynamic model
Definition demModel.h:32

References model::DEMModel::run(), and util::methods::timeDiff().

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 353 of file testFeLib.cpp.

353 {
354
355 //
356 // Test1: We test accuracy of integrals of polynomials over reference
357 // quadrangle. Reference triangle {(-1,-1), (1,-1), (1,1), (-1,1)}.
358 //
359 // Test2: We consider simple mesh in meshFeTest.txt over square domain
360 // [0,1]^2 and test the accuracy of polynomials over square domain.
361 //
362
363 // get Quadrature
364 auto quad = fe::QuadElem(n);
365
366 //
367 // Test 1
368 //
369 size_t error_test_1 = 0;
370 {
371 // T1 (reference quadrangle)
372 // get quad points at reference triangle
373 std::vector<util::Point> nodes = {
374 util::Point(-1., -1., 0.), util::Point(1., -1., 0.),
375 util::Point(1., 1., 0.), util::Point(-1., 1., 0.)};
376 std::vector<fe::QuadData> qds = quad.getQuadPoints(nodes);
377 double sum = 0.;
378 for (auto qd : qds)
379 sum += qd.d_w;
380
381 if (std::abs(sum - 4.0) > tol) {
382 std::cout << "Error in order = " << n
383 << ". Sum of quad weights is not "
384 "equal to area of reference "
385 "quadrangle.\n";
386 error_test_1++;
387 }
388
389 //
390 // test the exactness of integration for polynomial
391 //
392 for (size_t i = 0; i <= 2 * n - 1; i++)
393 for (size_t j = 0; j <= 2 * n - 1; j++) {
394
395 //
396 // when {(-1,-1), (1,-1), (1,1), (-1,1)}
397 //
398 nodes = {util::Point(-1., -1., 0.), util::Point(1., -1., 0.),
399 util::Point(1., 1., 0.), util::Point(-1., 1., 0.)};
400 qds = quad.getQuadPoints(nodes);
401 // test integration of polynomial f(s,t) = s^i t^j
402 // get the exact integration
403 double I_exact = test::getExactIntegrationRefQuad(i, j);
404 if (!checkRefIntegration(n, i, j, qds, I_exact))
405 error_test_1++;
406
407 //
408 // when {(-1,1), (-1,-1), (1,-1), (1,1)}
409 //
410 nodes = {util::Point(-1., 1., 0.), util::Point(-1., -1., 0.),
411 util::Point(1., -1., 0.), util::Point(1., 1., 0.)};
412 qds = quad.getQuadPoints(nodes);
413 //
414 // After changing the order of vertices, we have got a new
415 // triangle which is in coordinate system (x,y) and we are
416 // integrating function f(x,y) = x^i y^j
417 //
418 // The quad data we have got is such that quad point is in (x,y)
419 // coordinate, weight is such that determinant of the Jacobian is
420 // included in the weight.
421 //
422 // Thus the following method for I_approx is correct.
423 if (!checkRefIntegration(n, i, j, qds, I_exact))
424 error_test_1++;
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 if (!checkRefIntegration(n, i, j, qds, I_exact))
433 error_test_1++;
434
435 //
436 // when {(1,-1), (1,1), (-1,1), (-1,-1)}
437 //
438 nodes = {util::Point(1., -1., 0.), util::Point(1., 1., 0.),
439 util::Point(-1., 1., 0.), util::Point(-1., -1., 0.)};
440 qds = quad.getQuadPoints(nodes);
441 if (!checkRefIntegration(n, i, j, qds, I_exact))
442 error_test_1++;
443 }
444 } // Test 1
445
446 //
447 // Test 2
448 //
449 size_t error_test_2 = 0;
450 {
451 static std::vector<util::Point> nodes;
452 static std::vector<size_t> elements;
453 static size_t num_vertex = 4;
454 static size_t elem_type = util::vtk_type_quad;
455 static size_t num_elems = 0;
456 if (num_elems == 0) {
457 readNodes(filepath + "/quadMesh_nodes.csv", nodes);
458 num_elems = readElements(filepath + "/quadMesh_elements.csv", elem_type,
459 elements);
460 }
461
462 // loop over polynomials
463 for (size_t i = 0; i <= 2 * n - 1; i++)
464 for (size_t j = 0; j <= 2 * n - 1; j++) {
465
466 double I_exact = 1. / (double(i + 1) * double(j + 1));
467 double I_approx = 0.;
468 // loop over elements and compute I_approx
469 for (size_t e = 0; e < num_elems; e++) {
470 std::vector<util::Point> enodes = {
471 nodes[elements[num_vertex * e + 0]],
472 nodes[elements[num_vertex * e + 1]],
473 nodes[elements[num_vertex * e + 2]],
474 nodes[elements[num_vertex * e + 3]]};
475 std::vector<fe::QuadData> qds = quad.getQuadPoints(enodes);
476 for (auto qd : qds)
477 I_approx +=
478 qd.d_w * std::pow(qd.d_p.d_x, i) * std::pow(qd.d_p.d_y, j);
479 }
480
481 if (std::abs(I_exact - I_approx) > tol) {
482 std::cout << "Error in order = " << n
483 << ". Exact integration = " << I_exact
484 << " and approximate integration = " << I_approx
485 << " of polynomial of order (i = " << i << " + j = " << j
486 << ") = " << i + j << " over square domain [0,1]x[0,1] "
487 << "is not matching using quadrature points.\n";
488
489 error_test_2++;
490 }
491 }
492 }
493
494 if (n == 1) {
495 std::cout << "**********************************\n";
496 std::cout << "Quadrangle Quadrature Test\n";
497 std::cout << "**********************************\n";
498 }
499 std::cout << "Quad order = " << n << ". ";
500 std::cout << (error_test_1 == 0 ? "TEST 1 : PASS. " : "TEST 1 : FAIL. ");
501 std::cout << (error_test_2 == 0 ? "TEST 2 : PASS. \n" : "TEST 2 : FAIL. \n");
502}
A class for mapping and quadrature related operations for bi-linear quadrangle element.
Definition quadElem.h:64
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:39
void readNodes(const std::string &filename, std::vector< util::Point > &nodes)
Definition testFeLib.cpp:29
bool checkRefIntegration(const size_t &n, const size_t &i, const size_t &j, const std::vector< fe::QuadData > &qds, double &I_exact)
Definition testFeLib.cpp:78
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 String containing various information

Definition at line 222 of file testParallelCompLib.cpp.

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

577 {
578
579 //
580 // Test1: We test accuracy of integrals of polynomials over reference
581 // tetrahedron. Reference element {(0,0,0), (1,0,0), (0,1,0), (0,0,1)}.
582 //
583 // Test2: We consider simple mesh in meshFeTest.txt over cubic domain
584 // [0,1]^3 and test the accuracy of polynomials over cubic domain.
585 //
586
587 // get Quadrature
588 auto quad = fe::TetElem(n);
589
590 //
591 // Test 1
592 //
593 size_t error_test_1 = 0;
594 {
595 // T1 (reference triangle)
596 // get quad points at reference triangle
597 std::vector<util::Point> nodes = {util::Point(), util::Point(1., 0., 0.),
598 util::Point(0., 1., 0.),
599 util::Point(0., 0., 1.)};
600 std::vector<fe::QuadData> qds = quad.getQuadPoints(nodes);
601
602 double sum = 0.;
603 for (auto qd : qds)
604 sum += qd.d_w;
605
606 if (std::abs(sum - 1. / 6.) > tol) {
607 std::cout << "Error in order = " << n
608 << ". Sum of quad weights is not "
609 "equal to volume of reference "
610 "tetrahedron.\n";
611 error_test_1++;
612 }
613
614 //
615 // test the exactness of integration for polynomial
616 //
617 for (size_t i = 0; i <= n; i++)
618 for (size_t j = 0; j <= n; j++)
619 for (size_t k = 0; k <= n; k++) {
620
621 if (i + j + k > n)
622 continue;
623
624 //
625 // +ve order of indices are:
626 // {0,1,2,3}; {1,2,0,3}; {2,3,0,1}; {0,3,1,2}
627
628 //
629 // when {(0,0,0), (1,0,0), (0,1,0), (0,0,1)}
630 //
631 nodes = {util::Point(), util::Point(1., 0., 0.),
632 util::Point(0., 1., 0.), util::Point(0., 0., 1.)};
633 qds = quad.getQuadPoints(nodes);
634 // test integration of polynomial f(s,t) = s^i t^j
635 // get the exact integration
636 debug_id = 0;
637 double I_exact = test::getExactIntegrationRefTet(i, j, k);
638 if (!checkRefIntegration(n, i, j, k, qds, I_exact)) {
639 error_test_1++;
640 }
641
642 //
643 // when vertices are {(1,0,0), (0,1,0), (0,0,1), (0,0,0)}
644 //
645 nodes = {util::Point(1., 0., 0.), util::Point(0., 1., 0.),
646 util::Point(0., 0., 0.), util::Point(0., 0., 1.)};
647 qds = quad.getQuadPoints(nodes);
648 //
649 // After changing the order of vertices, we have got a new
650 // triangle which is in coordinate system (x,y) and we are
651 // integrating function f(x,y) = x^i y^j
652 //
653 // The quad data we have got is such that quad point is in (x,y)
654 // coordinate, weight is such that determinant of the Jacobian is
655 // included in the weight.
656 //
657 // Thus the following method for I_approx is correct.
658 debug_id = 1;
659 if (!checkRefIntegration(n, i, j, k, qds, I_exact))
660 error_test_1++;
661
662 //
663 // when vertices are {(0,1,0), (0,0,1), (0,0,0), (1,0,0)}
664 //
665 nodes = {util::Point(0., 1., 0.), util::Point(0., 0., 1.),
666 util::Point(0., 0., 0.), util::Point(1., 0., 0.)};
667 qds = quad.getQuadPoints(nodes);
668 debug_id = 2;
669 if (!checkRefIntegration(n, i, j, k, qds, I_exact))
670 error_test_1++;
671
672 //
673 // when vertices are {(0,0,1), (0,0,0), (1,0,0), (0,1,0)}
674 //
675 nodes = {util::Point(0., 0., 0.), util::Point(0., 0., 1.),
676 util::Point(1., 0., 0.), util::Point(0., 1., 0.)};
677 qds = quad.getQuadPoints(nodes);
678 debug_id = 3;
679 if (!checkRefIntegration(n, i, j, k, qds, I_exact))
680 error_test_1++;
681 }
682 } // Test 1
683
684 //
685 // Test 2
686 //
687 size_t error_test_2 = 0;
688 if (false) {
689 static std::vector<util::Point> nodes;
690 static std::vector<size_t> elements;
691 static size_t num_vertex = 4;
692 static size_t elem_type = util::vtk_type_tetra;
693 static size_t num_elems = 0;
694 if (num_elems == 0) {
695 readNodes(filepath + "tetMesh_nodes.csv", nodes);
696 num_elems = readElements(filepath + "tetMesh_elements.csv", elem_type,
697 elements);
698 }
699
700 // loop over polynomials
701 for (size_t i = 0; i <= n; i++)
702 for (size_t j = 0; j <= n; j++)
703 for (size_t k = 0; k <= n; k++) {
704
705 if (i + j + k > n)
706 continue;
707
708 double I_exact = 1. / (double(i + 1) * double(j + 1) * double(k + 1));
709 double I_approx = 0.;
710 // loop over elements and compute I_approx
711 for (size_t e = 0; e < num_elems; e++) {
712 std::vector<util::Point> enodes = {
713 nodes[elements[num_vertex * e + 0]],
714 nodes[elements[num_vertex * e + 1]],
715 nodes[elements[num_vertex * e + 2]],
716 nodes[elements[num_vertex * e + 3]]};
717 std::vector<fe::QuadData> qds = quad.getQuadPoints(enodes);
718 for (auto qd : qds) {
719 I_approx += qd.d_w * std::pow(qd.d_p.d_x, i) *
720 std::pow(qd.d_p.d_y, j) * std::pow(qd.d_p.d_z, k);
721
722 if (false) {
723
724 std::cout << "Print " << i << " " << j << " " << k << "\n";
725 std::cout << util::io::printStr(enodes) << "\n";
726 std::vector<size_t> enode_ids = {
727 elements[num_vertex * e + 0],
728 elements[num_vertex * e + 1],
729 elements[num_vertex * e + 2],
730 elements[num_vertex * e + 3]};
731 std::cout << util::io::printStr(enode_ids) << "\n";
732 std::cout << qd.printStr() << "\n";
733 }
734
735 }
736 }
737
738 if (std::abs(I_exact - I_approx) > tol) {
739 std::cout << "Error in order = " << n
740 << ". Exact integration = " << I_exact
741 << " and approximate integration = " << I_approx
742 << " of polynomial of order (i = " << i << " + j = " << j
743 << " + k = " << k << ") = " << i + j + k
744 << " over cubic domain [0,1]x[0,1]x[0,1] "
745 << "is not matching using quadrature points.\n";
746
747 error_test_2++;
748 }
749 }
750 }
751
752 if (n == 1) {
753 std::cout << "**********************************\n";
754 std::cout << "Tetrahedron Quadrature Test\n";
755 std::cout << "**********************************\n";
756 }
757 std::cout << "Quad order = " << n << ". ";
758 if (error_test_1 == 0)
759 std::cout << "TEST 1 : PASS. ";
760 else
761 std::cout << "TEST 1 : FAIL. ";
762 // if (error_test_2 == 0)
763 // std::cout << "TEST 2 : PASS. ";
764 // else
765 // std::cout << "TEST 2 : FAIL. ";
766 std::cout << "\n";
767}
A class for mapping and quadrature related operations for linear tetrahedron element.
Definition tetElem.h:141
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:54

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:

◆ testTransform()

void test::testTransform ( )

Perform test on Fracture class and check if bitwise functions are working correctly.

Definition at line 19 of file testParticleLib.cpp.

19 {
20
21 bool test_result = true;
22
23 // test translation
24 double scale = 1.0;
25 double theta = 0.;
26 auto xt = util::Point(1., 1., 0.);
27 auto t1 = particle::ParticleTransform(xt, util::Point(0., 0., 1.), theta, scale);
28
29 auto xold = util::Point(0., 0., 0.);
30 auto xnew = t1.apply(xold);
31 auto xnew_check = util::Point( xold.d_x + 1., xold.d_y + 1., xold.d_z);
32
33 std::cout << "xold = (" << xold.d_x << ", " << xold.d_y << ", " << xold.d_z
34 << "), xnew = (" << xnew.d_x << ", " << xnew.d_y << ", " << xnew.d_z
35 << "), distance = " << xnew_check.dist(xnew) << "\n";
36 if (xnew_check.dist(xnew) > 1.0E-8) {
37 std::cout << "Error\n";
38 test_result = false;
39 }
40
41 // test rotation
42 scale = 1.0;
43 theta = M_PI / 6;
44 xt = util::Point(0., 0., 0.);
45 auto t2 =
46 particle::ParticleTransform(xt, util::Point(0., 0., 1.), theta, scale);
47 xold = util::Point(0.5, 0.2, 0.);
48 xnew = t2.apply(xold);
49 xnew_check = util::Point(
50 xold.d_x * std::cos(theta) - xold.d_y * std::sin(theta),
51 xold.d_x * std::sin(theta) + xold.d_y * std::cos(theta), 0.);
52
53 std::cout << "xold = (" << xold.d_x << ", " << xold.d_y << ", " << xold.d_z
54 << "), xnew = (" << xnew.d_x << ", " << xnew.d_y << ", " << xnew.d_z
55 << "), distance = " << xnew_check.dist(xnew) << "\n";
56 if (xnew_check.dist(xnew) > 1.0E-8) {
57 std::cout << "Error\n";
58 test_result = false;
59 }
60
61 // test scale and rotation
62 scale = 0.5;
63 theta = M_PI / 3;
64 xt = util::Point(0., 0., 0.);
65 auto t3 =
66 particle::ParticleTransform(xt, util::Point(0., 0., 1.), theta,
67 scale);
68 xold = util::Point(0.2, 0.4, 0.);
69 xnew = t3.apply(xold);
70 xnew_check = util::Point(
71 scale * xold.d_x * std::cos(theta) - scale * xold.d_y * std::sin(theta),
72 scale * xold.d_x * std::sin(theta) + scale * xold.d_y * std::cos(theta), 0.);
73
74 std::cout << "xold = (" << xold.d_x << ", " << xold.d_y << ", " << xold.d_z
75 << "), xnew = (" << xnew.d_x << ", " << xnew.d_y << ", " << xnew.d_z
76 << "), distance = " << xnew_check.dist(xnew) << "\n";
77 if (xnew_check.dist(xnew) > 1.0E-8) {
78 std::cout << "Error\n";
79 test_result = false;
80 }
81}
A struct that stores transformation parameters and provides method to transform the particle....

Referenced by main().

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 200 of file testFeLib.cpp.

200 {
201
202 //
203 // Test1: We test accuracy of integrals of polynomials over reference
204 // triangle. Reference triangle {(0,0), (1,0), (0,1)}.
205 //
206 // Test2: We consider simple mesh in meshFeTest.txt over square domain
207 // [0,1]^2 and test the accuracy of polynomials over square domain.
208 //
209
210 // get Quadrature
211 auto quad = fe::TriElem(n);
212
213 //
214 // Test 1
215 //
216 size_t error_test_1 = 0;
217 {
218 // T1 (reference triangle)
219 // get quad points at reference triangle
220 std::vector<util::Point> nodes = {util::Point(), util::Point(1., 0., 0.),
221 util::Point(0., 1., 0.)};
222 std::vector<fe::QuadData> qds = quad.getQuadPoints(nodes);
223 double sum = 0.;
224 for (auto qd : qds)
225 sum += qd.d_w;
226
227 if (std::abs(sum - 0.5) > tol) {
228 std::cout << "Error in order = " << n
229 << ". Sum of quad weights is not "
230 "equal to area of reference "
231 "triangle.\n";
232 error_test_1++;
233 }
234
235 //
236 // test the exactness of integration for polynomial
237 //
238 for (size_t i = 0; i <= n; i++)
239 for (size_t j = 0; j <= n; j++) {
240
241 if (i + j > n)
242 continue;
243
244 //
245 // when {(0,0), (1,0), (0,1)}
246 //
247 nodes = {util::Point(), util::Point(1., 0., 0.),
248 util::Point(0., 1., 0.)};
249 qds = quad.getQuadPoints(nodes);
250 // test integration of polynomial f(s,t) = s^i t^j
251 // get the exact integration
252 double I_exact = test::getExactIntegrationRefTri(i, j);
253 if (!checkRefIntegration(n, i, j, qds, I_exact))
254 error_test_1++;
255
256 //
257 // when vertices are {(1,0), (0,1), (0,0)}
258 //
259 nodes = {util::Point(1., 0., 0.), util::Point(0., 1., 0.),
260 util::Point()};
261 qds = quad.getQuadPoints(nodes);
262 //
263 // After changing the order of vertices, we have got a new
264 // triangle which is in coordinate system (x,y) and we are
265 // integrating function f(x,y) = x^i y^j
266 //
267 // The quad data we have got is such that quad point is in (x,y)
268 // coordinate, weight is such that determinant of the Jacobian is
269 // included in the weight.
270 //
271 // Thus the following method for I_approx is correct.
272 if (!checkRefIntegration(n, i, j, qds, I_exact))
273 error_test_1++;
274
275 //
276 // when vertices are {(0,1), (0,0), (1,0)}
277 //
278 nodes = {util::Point(0., 1., 0.), util::Point(),
279 util::Point(1., 0., 0.)};
280 qds = quad.getQuadPoints(nodes);
281 if (!checkRefIntegration(n, i, j, qds, I_exact))
282 error_test_1++;
283 }
284 } // Test 1
285
286 //
287 // Test 2
288 //
289 size_t error_test_2 = 0;
290 {
291 static std::vector<util::Point> nodes;
292 static std::vector<size_t> elements;
293 static size_t num_vertex = 3;
294 static size_t elem_type = util::vtk_type_triangle;
295 static size_t num_elems = 0;
296 if (num_elems == 0) {
297 readNodes(filepath + "/triMesh_nodes.csv", nodes);
298 num_elems = readElements(filepath + "/triMesh_elements.csv", elem_type,
299 elements);
300 }
301
302 // loop over polynomials
303 for (size_t i = 0; i <= n; i++)
304 for (size_t j = 0; j <= n; j++) {
305
306 if (i + j > n)
307 continue;
308
309 double I_exact = 1. / (double(i + 1) * double(j + 1));
310 double I_approx = 0.;
311 // loop over elements and compute I_approx
312 for (size_t e = 0; e < num_elems; e++) {
313 std::vector<util::Point> enodes = {
314 nodes[elements[num_vertex * e + 0]],
315 nodes[elements[num_vertex * e + 1]],
316 nodes[elements[num_vertex * e + 2]]};
317 std::vector<fe::QuadData> qds = quad.getQuadPoints(enodes);
318 for (auto qd : qds)
319 I_approx +=
320 qd.d_w * std::pow(qd.d_p.d_x, i) * std::pow(qd.d_p.d_y, j);
321 }
322
323 if (std::abs(I_exact - I_approx) > tol) {
324 std::cout << "Error in order = " << n
325 << ". Exact integration = " << I_exact
326 << " and approximate integration = " << I_approx
327 << " of polynomial of order (i = " << i << " + j = " << j
328 << ") = " << i + j << " over square domain [0,1]x[0,1] "
329 << "is not matching using quadrature points.\n";
330
331 error_test_2++;
332 }
333 }
334 }
335
336 if (n == 1) {
337 std::cout << "**********************************\n";
338 std::cout << "Triangle Quadrature Test\n";
339 std::cout << "**********************************\n";
340 }
341 std::cout << "Quad order = " << n << ". ";
342 if (error_test_1 == 0)
343 std::cout << "TEST 1 : PASS. ";
344 else
345 std::cout << "TEST 1 : FAIL. ";
346 if (error_test_2 == 0)
347 std::cout << "TEST 2 : PASS. ";
348 else
349 std::cout << "TEST 2 : FAIL. ";
350 std::cout << "\n";
351}
A class for mapping and quadrature related operations for linear triangle element.
Definition triElem.h:91
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 504 of file testFeLib.cpp.

504 {
505
506 // get Quadrature
507 auto quad = fe::TriElem(n);
508
509 //
510 // Test 1
511 //
512 std::vector<util::Point> nodes = {util::Point(2., 2., 0.),
513 util::Point(4., 2., 0.),
514 util::Point(2., 4., 0.)};
515 size_t num_vertex = 3;
516 // std::vector<size_t> elements;
517 // for (size_t i = 0; i < 3 * N; i++)
518 // elements.emplace_back(i % 2);
519 std::vector<std::vector<size_t>> elements;
520 for (size_t i = 0; i < N; i++)
521 elements.emplace_back(std::vector<size_t>{0, 1, 2});
522
523 auto t11 = steady_clock::now();
524 // method 1: Compute quad points on the fly
525 // loop over elements and compute I_approx
526 double sum = 0.;
527 for (size_t e = 0; e < N; e++) {
528 // std::vector<util::Point> enodes = {nodes[elements[num_vertex * e +
529 // 0]],
530 // nodes[elements[num_vertex * e +
531 // 1]], nodes[elements[num_vertex * e
532 // + 2]]};
533 std::vector<util::Point> enodes = {
534 nodes[elements[e][0]], nodes[elements[e][1]], nodes[elements[e][2]]};
535 std::vector<fe::QuadData> qds = quad.getQuadPoints(enodes);
536 for (auto qd : qds)
537 sum += qd.d_w * (qd.d_shapes[0] + qd.d_shapes[1] + qd.d_shapes[2]);
538 }
539 auto t12 = steady_clock::now();
540
541 // method 2: Compute quad points in the beginning and use it when needed
542 size_t num_quad_pts = 0;
543 std::vector<fe::QuadData> quad_data;
544 for (size_t e = 0; e < N; e++) {
545 std::vector<fe::QuadData> qds = quad.getQuadPoints(nodes);
546 if (e == 0)
547 num_quad_pts = qds.size();
548 for (auto qd : qds)
549 quad_data.emplace_back(qd);
550 }
551
552 auto t21 = steady_clock::now();
553 sum = 0.;
554 for (size_t e = 0; e < N; e++) {
555 for (size_t q = 0; q < num_quad_pts; q++) {
556 fe::QuadData qd = quad_data[e * num_quad_pts + q];
557 sum += qd.d_w * (qd.d_shapes[0] + qd.d_shapes[1] + qd.d_shapes[2]);
558 }
559 }
560 auto t22 = steady_clock::now();
561
562 if (n == 1 and N == 1000) {
563 std::cout << "**********************************\n";
564 std::cout << "Quadrature Time Efficiency Test\n";
565 std::cout << "**********************************\n";
566 }
567 std::cout << "Quad order = " << n << ". Num Elements = " << N << ".\n ";
568 double dt_1 = util::methods::timeDiff(t12, t11, "seconds");
569 double dt_2 = util::methods::timeDiff(t21, t22, "seconds");
570 double perc = (dt_1 - dt_2) * 100. / dt_2;
571 double qpt_mem = 13 * sizeof(double);
572 double mem2 = double(quad_data.capacity() * qpt_mem) / double(1000000);
573 std::cout << " dt1 = " << dt_1 << ", dt2 = " << dt_2 << ", perc = " << perc
574 << ". Mem saved = " << mem2 << " MB.\n";
575}
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 26 of file testUtilLib.cpp.

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

Referenced by main().

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