PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
Functions | Variables
test_particle_kernels.c File Reference

C unit tests for particle walking-search helpers and the initial-value expression engine. More...

#include "test_support.h"
#include "walkingsearch.h"
#include "ParticleInitialConditions.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Include dependency graph for test_particle_kernels.c:

Go to the source code of this file.

Functions

static PetscErrorCode TestCheckCellWithinLocalGrid (void)
 Tests whether a cell index lies within the local grid ownership range.
 
static PetscErrorCode TestInitializeTraversalParameters (void)
 Tests initialization of traversal parameters for particle search.
 
static PetscErrorCode TestRetrieveCurrentCell (void)
 Tests retrieval of the current cell from logical particle coordinates.
 
static PetscErrorCode TestExpressionConformance (void)
 Tests the runtime evaluator against every shared conformance case.
 
static PetscErrorCode TestExpressionRejectsOutsideLanguage (void)
 Tests that the compiler refuses what the Python validator also refuses.
 
static PetscErrorCode TestExpressionDrawsArePureAndKeyed (void)
 Tests that random draws are pure functions of their key.
 
int main (int argc, char **argv)
 Runs the unit-particles PETSc test binary.
 

Variables

static const char *const kConformanceNames [] = {"x", "y", "z"}
 

Detailed Description

C unit tests for particle walking-search helpers and the initial-value expression engine.

Definition in file test_particle_kernels.c.

Function Documentation

◆ TestCheckCellWithinLocalGrid()

static PetscErrorCode TestCheckCellWithinLocalGrid ( void  )
static

Tests whether a cell index lies within the local grid ownership range.

Definition at line 18 of file test_particle_kernels.c.

19{
20 SimCtx *simCtx = NULL;
21 UserCtx *user = NULL;
22 PetscBool within = PETSC_FALSE;
23
24 PetscFunctionBeginUser;
25 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
26
27 PetscCall(CheckCellWithinLocalGrid(user, 1, 1, 1, &within));
28 PetscCall(PicurvAssertBool(within, "cell (1,1,1) should be within the serial local grid"));
29
30 PetscCall(CheckCellWithinLocalGrid(user, 4, 1, 1, &within));
31 PetscCall(PicurvAssertBool((PetscBool)!within, "cell (4,1,1) should fall outside the valid local cell range"));
32
33 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
34 PetscFunctionReturn(0);
35}
PetscErrorCode PicurvCreateMinimalContexts(SimCtx **simCtx_out, UserCtx **user_out, PetscInt mx, PetscInt my, PetscInt mz)
Builds minimal SimCtx and UserCtx fixtures for C unit tests.
PetscErrorCode PicurvDestroyMinimalContexts(SimCtx **simCtx_ptr, UserCtx **user_ptr)
Destroys minimal SimCtx/UserCtx fixtures and all owned PETSc objects.
PetscErrorCode PicurvAssertBool(PetscBool value, const char *context)
Asserts that one boolean condition is true.
The master context for the entire simulation.
Definition variables.h:859
User-defined context containing data specific to a single computational grid level.
Definition variables.h:1074
PetscErrorCode CheckCellWithinLocalGrid(UserCtx *user, PetscInt idx, PetscInt idy, PetscInt idz, PetscBool *is_within)
Checks if the current cell indices are within the local grid boundaries.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestInitializeTraversalParameters()

static PetscErrorCode TestInitializeTraversalParameters ( void  )
static

Tests initialization of traversal parameters for particle search.

Definition at line 40 of file test_particle_kernels.c.

41{
42 SimCtx *simCtx = NULL;
43 UserCtx *user = NULL;
44 Particle particle;
45 PetscInt idx = -1, idy = -1, idz = -1, steps = -1;
46
47 PetscFunctionBeginUser;
48 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
49 PetscCall(PetscMemzero(&particle, sizeof(particle)));
50
51 particle.PID = 42;
52 particle.cell[0] = 1;
53 particle.cell[1] = 1;
54 particle.cell[2] = 1;
55
56 PetscCall(InitializeTraversalParameters(user, &particle, &idx, &idy, &idz, &steps));
57 PetscCall(PicurvAssertIntEqual(1, idx, "InitializeTraversalParameters should preserve prior i"));
58 PetscCall(PicurvAssertIntEqual(1, idy, "InitializeTraversalParameters should preserve prior j"));
59 PetscCall(PicurvAssertIntEqual(1, idz, "InitializeTraversalParameters should preserve prior k"));
60 PetscCall(PicurvAssertIntEqual(0, steps, "InitializeTraversalParameters should reset traversal steps"));
61
62 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
63 PetscFunctionReturn(0);
64}
PetscErrorCode PicurvAssertIntEqual(PetscInt expected, PetscInt actual, const char *context)
Asserts that two integer values are equal.
PetscInt cell[3]
Definition variables.h:210
PetscInt64 PID
Definition variables.h:209
Defines a particle's core properties for Lagrangian tracking.
Definition variables.h:208
PetscErrorCode InitializeTraversalParameters(UserCtx *user, Particle *particle, PetscInt *idx, PetscInt *idy, PetscInt *idz, PetscInt *traversal_steps)
Initializes traversal parameters for locating a particle.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestRetrieveCurrentCell()

static PetscErrorCode TestRetrieveCurrentCell ( void  )
static

Tests retrieval of the current cell from logical particle coordinates.

Definition at line 69 of file test_particle_kernels.c.

70{
71 SimCtx *simCtx = NULL;
72 UserCtx *user = NULL;
73 Cell cell;
74
75 PetscFunctionBeginUser;
76 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
77 PetscCall(PetscMemzero(&cell, sizeof(cell)));
78
79 PetscCall(RetrieveCurrentCell(user, 1, 1, 1, &cell));
80 PetscCall(PicurvAssertRealNear(0.25, cell.vertices[0].x, 1.0e-12, "vertex 0 x coordinate"));
81 PetscCall(PicurvAssertRealNear(0.25, cell.vertices[0].y, 1.0e-12, "vertex 0 y coordinate"));
82 PetscCall(PicurvAssertRealNear(0.25, cell.vertices[0].z, 1.0e-12, "vertex 0 z coordinate"));
83 PetscCall(PicurvAssertRealNear(0.50, cell.vertices[5].x, 1.0e-12, "vertex 5 x coordinate"));
84 PetscCall(PicurvAssertRealNear(0.50, cell.vertices[5].y, 1.0e-12, "vertex 5 y coordinate"));
85 PetscCall(PicurvAssertRealNear(0.50, cell.vertices[5].z, 1.0e-12, "vertex 5 z coordinate"));
86
87 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
88 PetscFunctionReturn(0);
89}
PetscErrorCode PicurvAssertRealNear(PetscReal expected, PetscReal actual, PetscReal tol, const char *context)
Asserts that two real values agree within tolerance.
PetscScalar x
Definition variables.h:122
PetscScalar z
Definition variables.h:122
PetscScalar y
Definition variables.h:122
Cmpnts vertices[8]
Coordinates of the eight vertices of the cell.
Definition variables.h:204
Defines the vertices of a single hexahedral grid cell.
Definition variables.h:203
PetscErrorCode RetrieveCurrentCell(UserCtx *user, PetscInt idx, PetscInt idy, PetscInt idz, Cell *cell)
Retrieves the coordinates of the eight vertices of the current cell.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestExpressionConformance()

static PetscErrorCode TestExpressionConformance ( void  )
static

Tests the runtime evaluator against every shared conformance case.

tests/fixtures/expression_conformance.txt is also evaluated by generators/ic.gen in tests/test_expression_language.py, so the two implementations of the language cannot drift apart unnoticed.

Definition at line 98 of file test_particle_kernels.c.

99{
100 FILE *file = fopen("tests/fixtures/expression_conformance.txt", "r");
101 char line[1024];
102 PetscInt cases = 0;
103
104 PetscFunctionBeginUser;
105 PetscCheck(file, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open the expression conformance cases.");
106 while (fgets(line, sizeof(line), file)) {
107 char *fields[5];
108 PetscInt count = 0;
109 PicurvExpression *expression = NULL;
110 PetscReal values[3], result = 0.0;
111
112 if (line[0] == '#' || line[0] == '\n') continue;
113 for (char *cursor = line; count < 5; ++count) {
114 fields[count] = cursor;
115 char *separator = strchr(cursor, ';');
116 if (!separator) { ++count; break; }
117 *separator = '\0';
118 cursor = separator + 1;
119 }
120 PetscCheck(count == 5, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Malformed conformance line.");
121 for (int v = 0; v < 3; ++v) values[v] = strtod(fields[v + 1], NULL);
122 PetscCall(PicurvExpressionCompile(fields[0], kConformanceNames, 3, PETSC_FALSE, &expression));
123 PetscCall(PicurvExpressionEvaluate(expression, values, NULL, &result));
124 PetscCall(PicurvAssertRealNear(strtod(fields[4], NULL), result, 1.0e-12, fields[0]));
125 PetscCall(PicurvExpressionDestroy(&expression));
126 ++cases;
127 }
128 fclose(file);
129 PetscCall(PicurvAssertBool((PetscBool)(cases >= 20), "the conformance file should hold its cases"));
130 PetscFunctionReturn(0);
131}
PetscErrorCode PicurvExpressionEvaluate(const PicurvExpression *expression, const PetscReal *values, const PicurvExpressionDrawKey *key, PetscReal *result)
Evaluate a compiled expression.
PetscErrorCode PicurvExpressionDestroy(PicurvExpression **expression)
Free a compiled expression.
PetscErrorCode PicurvExpressionCompile(const char *text, const char *const *names, PetscInt name_count, PetscBool allow_random, PicurvExpression **expression)
Compile one expression against a list of variable names.
static const char *const kConformanceNames[]
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestExpressionRejectsOutsideLanguage()

static PetscErrorCode TestExpressionRejectsOutsideLanguage ( void  )
static

Tests that the compiler refuses what the Python validator also refuses.

Definition at line 136 of file test_particle_kernels.c.

137{
138 const char *bad[] = {"0x1F", "1_000", "x // 2", "abs", "abs(1, 2)", "where(x, 1)", "foo",
139 "x +", "(x", "x y", "uniform(x)", "uniform(1.5)", "1.e", "not"};
140
141 PetscFunctionBeginUser;
142 for (size_t n = 0; n < sizeof(bad) / sizeof(bad[0]); ++n) {
143 PicurvExpression *expression = NULL;
144 PetscErrorCode refused;
145
146 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
147 refused = PicurvExpressionCompile(bad[n], kConformanceNames, 3, PETSC_TRUE, &expression);
148 PetscCall(PetscPopErrorHandler());
149 PetscCall(PicurvAssertIntEqual(PETSC_ERR_ARG_WRONG, refused, bad[n]));
150 }
151 {
152 PicurvExpression *expression = NULL;
153 PetscErrorCode refused;
154
155 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
156 refused = PicurvExpressionCompile("uniform()", kConformanceNames, 3, PETSC_FALSE, &expression);
157 PetscCall(PetscPopErrorHandler());
158 PetscCall(PicurvAssertIntEqual(PETSC_ERR_ARG_WRONG, refused, "draws need allow_random"));
159 }
160 PetscFunctionReturn(0);
161}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestExpressionDrawsArePureAndKeyed()

static PetscErrorCode TestExpressionDrawsArePureAndKeyed ( void  )
static

Tests that random draws are pure functions of their key.

The same particle always draws the same number; a different particle, event, or field default stream draws independently; an explicit stream is shared across fields; and the normal draw has zero mean and unit variance.

Definition at line 169 of file test_particle_kernels.c.

170{
171 PicurvExpression *uniform = NULL, *shared = NULL, *normal = NULL;
172 PicurvExpressionDrawKey key = {12345, 7, 0, 6};
173 PetscReal a, b, sum = 0.0, square = 0.0;
174 const PetscInt samples = 20000;
175
176 PetscFunctionBeginUser;
177 PetscCall(PicurvExpressionCompile("uniform()", kConformanceNames, 3, PETSC_TRUE, &uniform));
178 PetscCall(PicurvExpressionCompile("uniform(3)", kConformanceNames, 3, PETSC_TRUE, &shared));
179 PetscCall(PicurvExpressionCompile("normal()", kConformanceNames, 3, PETSC_TRUE, &normal));
180
181 PetscCall(PicurvExpressionEvaluate(uniform, NULL, &key, &a));
182 PetscCall(PicurvExpressionEvaluate(uniform, NULL, &key, &b));
183 PetscCall(PicurvAssertBool((PetscBool)(a == b && a >= 0.0 && a < 1.0), "a draw is pure and in [0, 1)"));
184 key.pid = 8;
185 PetscCall(PicurvExpressionEvaluate(uniform, NULL, &key, &b));
186 PetscCall(PicurvAssertBool((PetscBool)(a != b), "another particle draws independently"));
187 key.pid = 7;
188 key.salt = 1;
189 PetscCall(PicurvExpressionEvaluate(uniform, NULL, &key, &b));
190 PetscCall(PicurvAssertBool((PetscBool)(a != b), "another event draws independently"));
191 key.salt = 0;
192 key.field = 5;
193 PetscCall(PicurvExpressionEvaluate(uniform, NULL, &key, &b));
194 PetscCall(PicurvAssertBool((PetscBool)(a != b), "another field's default stream is independent"));
195 PetscCall(PicurvExpressionEvaluate(shared, NULL, &key, &a));
196 key.field = 6;
197 PetscCall(PicurvExpressionEvaluate(shared, NULL, &key, &b));
198 PetscCall(PicurvAssertBool((PetscBool)(a == b), "an explicit stream is shared across fields"));
199
200 for (PetscInt pid = 0; pid < samples; ++pid) {
201 key.pid = pid;
202 PetscCall(PicurvExpressionEvaluate(normal, NULL, &key, &a));
203 sum += a;
204 square += a * a;
205 }
206 PetscCall(PicurvAssertRealNear(0.0, sum / samples, 0.03, "normal draws have zero mean"));
207 PetscCall(PicurvAssertRealNear(1.0, square / samples, 0.04, "normal draws have unit variance"));
208
209 PetscCall(PicurvExpressionDestroy(&uniform));
210 PetscCall(PicurvExpressionDestroy(&shared));
211 PetscCall(PicurvExpressionDestroy(&normal));
212 PetscFunctionReturn(0);
213}
PetscInt64 pid
Particle identity; draws are pure functions of it.
PetscInt64 salt
Event that produced the particle: 0 for the t=0 population.
PetscInt64 field
Field whose expression draws, the default stream's namespace.
What a random draw is keyed on, besides the particle and its stream.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char **  argv 
)

Runs the unit-particles PETSc test binary.

Definition at line 219 of file test_particle_kernels.c.

220{
221 PetscErrorCode ierr;
222 const PicurvTestCase cases[] = {
223 {"check-cell-within-local-grid", TestCheckCellWithinLocalGrid},
224 {"initialize-traversal-parameters", TestInitializeTraversalParameters},
225 {"retrieve-current-cell", TestRetrieveCurrentCell},
226 {"expression-conformance", TestExpressionConformance},
227 {"expression-rejects-outside-language", TestExpressionRejectsOutsideLanguage},
228 {"expression-draws-are-pure-and-keyed", TestExpressionDrawsArePureAndKeyed},
229 };
230
231 ierr = PetscInitialize(&argc, &argv, NULL, "PICurv particle kernel tests");
232 if (ierr) {
233 return (int)ierr;
234 }
235
236 ierr = PicurvRunTests("unit-particles", cases, sizeof(cases) / sizeof(cases[0]));
237 if (ierr) {
238 PetscFinalize();
239 return (int)ierr;
240 }
241
242 ierr = PetscFinalize();
243 return (int)ierr;
244}
static PetscErrorCode TestCheckCellWithinLocalGrid(void)
Tests whether a cell index lies within the local grid ownership range.
static PetscErrorCode TestExpressionConformance(void)
Tests the runtime evaluator against every shared conformance case.
static PetscErrorCode TestExpressionRejectsOutsideLanguage(void)
Tests that the compiler refuses what the Python validator also refuses.
static PetscErrorCode TestInitializeTraversalParameters(void)
Tests initialization of traversal parameters for particle search.
static PetscErrorCode TestRetrieveCurrentCell(void)
Tests retrieval of the current cell from logical particle coordinates.
static PetscErrorCode TestExpressionDrawsArePureAndKeyed(void)
Tests that random draws are pure functions of their key.
PetscErrorCode PicurvRunTests(const char *suite_name, const PicurvTestCase *cases, size_t case_count)
Runs a named C test suite and prints pass/fail progress markers.
Named test case descriptor consumed by PicurvRunTests.
Here is the call graph for this function:

Variable Documentation

◆ kConformanceNames

const char* const kConformanceNames[] = {"x", "y", "z"}
static

Definition at line 90 of file test_particle_kernels.c.

90{"x", "y", "z"};