42 {
"abs", 1, 1,
OP_ABS, PETSC_FALSE}, {
"cos", 1, 1,
OP_COS, PETSC_FALSE},
43 {
"exp", 1, 1,
OP_EXP, PETSC_FALSE}, {
"sin", 1, 1,
OP_SIN, PETSC_FALSE},
44 {
"sqrt", 1, 1,
OP_SQRT, PETSC_FALSE}, {
"tan", 1, 1,
OP_TAN, PETSC_FALSE},
45 {
"maximum", 2, 2,
OP_MAXIMUM, PETSC_FALSE}, {
"minimum", 2, 2,
OP_MINIMUM, PETSC_FALSE},
46 {
"where", 3, 3,
OP_WHERE, PETSC_FALSE},
47 {
"uniform", 0, 1,
OP_UNIFORM, PETSC_TRUE}, {
"normal", 0, 1,
OP_NORMAL, PETSC_TRUE},
89 if (!parser->
error[0]) {
90 snprintf(parser->
error,
sizeof(parser->
error),
"%s at position %zu of '%s'",
91 message, parser->
pos + 1, parser->
text);
98 while (parser->
text[parser->
pos] && isspace((
unsigned char)parser->
text[parser->
pos])) parser->
pos++;
104 size_t length = strlen(token);
107 if (strncmp(parser->
text + parser->
pos, token, length) != 0)
return PETSC_FALSE;
108 if (isalpha((
unsigned char)token[0])) {
109 const char next = parser->
text[parser->
pos + length];
110 if (isalnum((
unsigned char)next) || next ==
'_')
return PETSC_FALSE;
113 if ((!strcmp(token,
"*") && parser->
text[parser->
pos + 1] ==
'*') ||
114 ((!strcmp(token,
"<") || !strcmp(token,
">")) && parser->
text[parser->
pos + 1] ==
'=')) {
117 parser->
pos += length;
123 PetscInt a, PetscInt b, PetscInt c)
125 if (parser->
error[0])
return -1;
133 node->nchild = nchild;
137 return parser->
count++;
146 const char *start = parser->
text + parser->
pos;
148 if (isdigit((
unsigned char)*start) || (*start ==
'.' && isdigit((
unsigned char)start[1]))) {
151 while (isdigit((
unsigned char)start[length])) length++;
152 if (start[length] ==
'.') { length++;
while (isdigit((
unsigned char)start[length])) length++; }
153 if (start[length] ==
'e' || start[length] ==
'E') {
154 size_t exponent = length + 1;
155 if (start[exponent] ==
'+' || start[exponent] ==
'-') exponent++;
156 if (!isdigit((
unsigned char)start[exponent])) {
ParserFail(parser,
"malformed number");
return -1; }
157 while (isdigit((
unsigned char)start[exponent])) exponent++;
160 if (isalnum((
unsigned char)start[length]) || start[length] ==
'_' || start[length] ==
'.') {
164 const PetscReal value = strtod(start, NULL);
165 parser->
pos += length;
170 if (isalpha((
unsigned char)*start) || *start ==
'_') {
173 while (isalnum((
unsigned char)start[length]) || start[length] ==
'_') length++;
174 if (length >=
sizeof(name)) {
ParserFail(parser,
"name is too long");
return -1; }
175 memcpy(name, start, length);
177 if (!strcmp(name,
"and") || !strcmp(name,
"or") || !strcmp(name,
"not")) {
178 ParserFail(parser,
"operator where an operand was expected");
181 parser->
pos += length;
182 if (
Accept(parser,
"(")) {
184 if (strcmp(name,
kFunctions[f].name))
continue;
186 ParserFail(parser,
"random draws are not available in this expression");
189 PetscInt args[3] = {-1, -1, -1}, nargs = 0;
190 if (!
Accept(parser,
")")) {
192 if (nargs == 3) {
ParserFail(parser,
"too many arguments");
return -1; }
193 args[nargs++] =
ParseOr(parser);
194 if (parser->
error[0])
return -1;
195 }
while (
Accept(parser,
","));
196 if (!
Accept(parser,
")")) {
ParserFail(parser,
"expected ')'");
return -1; }
199 ParserFail(parser,
"wrong number of arguments");
206 if (
node < 0)
return -1;
210 stream->
value != PetscFloorReal(stream->
value)) {
211 ParserFail(parser,
"a draw's stream must be a non-negative integer literal");
224 if (!strcmp(name,
"pi")) {
229 for (PetscInt v = 0; v < parser->
name_count; ++v) {
230 if (!strcmp(name, parser->
names[v])) {
239 if (
Accept(parser,
"(")) {
240 PetscInt inner =
ParseOr(parser);
241 if (!
Accept(parser,
")")) {
ParserFail(parser,
"expected ')'");
return -1; }
244 ParserFail(parser,
"expected a number, name, or '('");
288 else if (
Accept(parser,
"/")) {
289 if (parser->
text[parser->
pos] ==
'/') {
ParserFail(parser,
"'//' is not supported");
return -1; }
314 static const struct {
const char *token;
ExpressionOp op; } kComparisons[] = {
315 {
"==",
OP_EQ}, {
"!=",
OP_NE}, {
"<=",
OP_LE}, {
">=",
OP_GE}, {
"<",
OP_LT}, {
">",
OP_GT},
317 PetscInt left =
ParseSum(parser), result = -1;
321 for (
size_t c = 0; c <
sizeof(kComparisons) /
sizeof(kComparisons[0]); ++c) {
322 if (
Accept(parser, kComparisons[c].token)) { op = kComparisons[c].op;
break; }
324 if (op ==
OP_CONST)
return (result < 0) ? left : result;
325 const PetscInt right =
ParseSum(parser);
326 const PetscInt pair =
NewNode(parser, op, 2, left, right, -1);
327 result = (result < 0) ? pair :
NewNode(parser,
OP_AND, 2, result, pair, -1);
361 for (PetscInt c = 0; c <
node->nchild; ++c)
EmitNode(parser,
node->child[c], expression, depth);
363 instruction->
op =
node->op;
366 *depth += 1 -
node->nchild;
377 for (PetscInt c = 0; c <
node->nchild; ++c) total +=
CountCode(parser,
node->child[c]);
389 PetscInt root, depth = 0;
391 PetscFunctionBeginUser;
392 PetscCheck(text && expression, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Expression text and output are required.");
393 PetscCall(PetscMemzero(&parser,
sizeof(parser)));
395 parser.
names = names;
398 parser.
capacity = 4 * (PetscInt)strlen(text) + 8;
404 if (parser.
error[0]) {
405 PetscCall(PetscFree(parser.
nodes));
406 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
"Invalid expression: %s.", parser.
error);
409 PetscCall(PetscNew(expression));
410 (*expression)->length = 0;
411 PetscCall(PetscMalloc1(
CountCode(&parser, root), &(*expression)->code));
412 EmitNode(&parser, root, *expression, &depth);
413 PetscCall(PetscFree(parser.
nodes));
414 PetscFunctionReturn(0);
420 z += 0x9E3779B97F4A7C15ULL;
421 z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ULL;
422 z = (z ^ (z >> 27)) * 0x94D049BB133111EBULL;
423 return z ^ (z >> 31);
429 return (PetscReal)(hash >> 11) * (1.0 / 9007199254740992.0);
437 const uint64_t space = instruction->
arg ? 1u : 0u;
438 const uint64_t stream = instruction->
arg ? (uint64_t)instruction->
value : (uint64_t)key->
field;
439 uint64_t hash =
Mix64((uint64_t)key->
seed);
440 hash =
Mix64(hash ^ space);
441 hash =
Mix64(hash ^ stream);
442 hash =
Mix64(hash ^ (uint64_t)key->
pid);
443 hash =
Mix64(hash ^ (uint64_t)key->
salt);
444 hash =
Mix64(hash ^ (uint64_t)instruction->
op);
449 return PetscSqrtReal(-2.0 * PetscLogReal(u1)) * PetscCosReal(2.0 * PETSC_PI * u2);
453static PetscReal
Extreme(PetscReal a, PetscReal b, PetscBool maximum)
455 if (PetscIsNanReal(a) || PetscIsNanReal(b))
return NAN;
456 return maximum ? PetscMax(a, b) : PetscMin(a, b);
466 PetscReal stack[expression->
max_depth + 1];
469 PetscFunctionBeginUser;
470 PetscCheck(!expression->
draws || key, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
471 "An expression that draws random numbers needs a draw key.");
472 for (PetscInt i = 0; i < expression->
length; ++i) {
476 switch (instruction->
op) {
478 case OP_VAR: stack[top++] = values[instruction->
arg];
break;
480 case OP_NORMAL: stack[top++] =
Draw(key, instruction);
break;
481 case OP_NEG: stack[top - 1] = -stack[top - 1];
break;
483 case OP_NOT: stack[top - 1] = (stack[top - 1] == 0.0) ? 1.0 : 0.0;
break;
484 case OP_ABS: stack[top - 1] = PetscAbsReal(stack[top - 1]);
break;
485 case OP_COS: stack[top - 1] = PetscCosReal(stack[top - 1]);
break;
486 case OP_EXP: stack[top - 1] = PetscExpReal(stack[top - 1]);
break;
487 case OP_SIN: stack[top - 1] = PetscSinReal(stack[top - 1]);
break;
488 case OP_SQRT: stack[top - 1] = PetscSqrtReal(stack[top - 1]);
break;
489 case OP_TAN: stack[top - 1] = PetscTanReal(stack[top - 1]);
break;
491 c = stack[--top]; b = stack[--top]; a = stack[top - 1];
492 stack[top - 1] = (a != 0.0) ? b : c;
495 b = stack[--top]; a = stack[top - 1];
496 switch (instruction->
op) {
497 case OP_ADD: a = a + b;
break;
498 case OP_SUB: a = a - b;
break;
499 case OP_MUL: a = a * b;
break;
500 case OP_DIV: a = a / b;
break;
502 case OP_MOD: a = (b == 0.0) ? NAN : a - b * PetscFloorReal(a / b);
break;
503 case OP_POW: a = PetscPowReal(a, b);
break;
504 case OP_EQ: a = (a == b) ? 1.0 : 0.0;
break;
505 case OP_NE: a = (a != b) ? 1.0 : 0.0;
break;
506 case OP_LT: a = (a < b) ? 1.0 : 0.0;
break;
507 case OP_LE: a = (a <= b) ? 1.0 : 0.0;
break;
508 case OP_GT: a = (a > b) ? 1.0 : 0.0;
break;
509 case OP_GE: a = (a >= b) ? 1.0 : 0.0;
break;
510 case OP_AND: a = (a != 0.0 && b != 0.0) ? 1.0 : 0.0;
break;
511 case OP_OR: a = (a != 0.0 || b != 0.0) ? 1.0 : 0.0;
break;
514 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB,
"Unknown expression opcode %d.", (
int)instruction->
op);
520 PetscFunctionReturn(0);
529 PetscFunctionBeginUser;
530 if (!expression || !*expression) PetscFunctionReturn(0);
531 PetscCall(PetscFree((*expression)->code));
532 PetscCall(PetscFree(*expression));
533 PetscFunctionReturn(0);
542#define PARTICLE_VARIABLE_COUNT ((PetscInt)(sizeof(kParticleVariables) / sizeof(kParticleVariables[0])))
543#define PARTICLE_FIELD_MAX_COMPONENTS 3
544#define PARTICLE_FIELD_EXPRESSION_LENGTH 4096
545#define PARTICLE_FIELD_HISTOGRAM_BINS 10
566 PetscBool found = PETSC_FALSE;
569 PetscFunctionBeginUser;
570 PetscCheck(plan, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Plan output is required.");
572 PetscCall(PetscSNPrintf(option,
sizeof(option),
"-particle_fields_count"));
573 PetscCall(PetscOptionsGetInt(NULL, NULL, option, &count, &found));
574 if (!found || count == 0) PetscFunctionReturn(0);
578 PetscCall(PetscNew(plan));
579 PetscCall(PetscCalloc1(count, &(*plan)->bindings));
580 (*plan)->count = count;
581 for (PetscInt i = 0; i < count; ++i) {
586 PetscCall(PetscSNPrintf(option,
sizeof(option),
"-particle_fields_%" PetscInt_FMT
"_name", i));
587 PetscCall(PetscOptionsGetString(NULL, NULL, option, name,
sizeof(name), &found));
588 PetscCheck(found, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
"%s is missing.", option);
593 "Particle field '%s' cannot be given an initial value: the runtime sets it from the "
594 "Eulerian fields or from particle location.", name);
596 PETSC_COMM_WORLD, PETSC_ERR_PLIB,
"Settable particle field '%s' must be a real quantity.", name);
597 for (PetscInt j = 0; j < i; ++j) {
598 PetscCheck((*plan)->bindings[j].field != binding->
field, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
599 "Particle field '%s' is configured twice.", name);
603 "Particle field '%s' has more components than an initial value supports.", name);
604 for (PetscInt c = 0; c < binding->
components; ++c) {
607 PetscCall(PetscSNPrintf(option,
sizeof(option),
"-particle_fields_%" PetscInt_FMT
"_expr_%" PetscInt_FMT, i, c));
608 PetscCall(PetscOptionsGetString(NULL, NULL, option, text,
sizeof(text), &found));
609 PetscCheck(found, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
"%s is missing.", option);
614 PetscFunctionReturn(0);
620 PetscMPIInt size = 1;
622 PetscFunctionBeginUser;
623 PetscCheck(simCtx->
bboxlist, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
624 "Rank bounding boxes are needed before a particle initial value is applied.");
625 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
628 for (PetscInt r = 1; r < (PetscInt)size * simCtx->
block_number; ++r) {
636 PetscFunctionReturn(0);
640static PetscReal
Normalized(PetscReal value, PetscReal lower, PetscReal upper)
642 return (upper > lower) ? (value - lower) / (upper - lower) : 0.0;
653 const PetscReal *positions = NULL;
654 const PetscInt64 *pids = NULL;
657 PetscFunctionBeginUser;
658 if (!plan || end <= first) PetscFunctionReturn(0);
659 PetscCheck(user && user->
swarm && event, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Swarm and event are required.");
665 for (PetscInt b = 0; b < plan->
count; ++b) {
668 PetscReal *field = NULL, scale = 1.0;
673 PetscCall(DMSwarmGetField(user->
swarm, descriptor->
canonical_name, NULL, NULL, (
void **)&field));
674 for (PetscInt p = first; p < end; ++p) {
675 const PetscReal *position = &positions[3 * p];
676 const PetscReal values[] = {
686 for (PetscInt c = 0; c < binding->
components; ++c) {
687 PetscReal value = 0.0;
690 PetscCheck(!PetscIsInfOrNanReal(value), PETSC_COMM_SELF, PETSC_ERR_FP,
691 "The initial value of '%s' is not finite for particle %lld at (%g, %g, %g).",
692 descriptor->
canonical_name, (
long long)pids[p], (
double)values[0],
693 (
double)values[1], (
double)values[2]);
694 field[binding->
components * p + c] = value / scale;
697 PetscCall(DMSwarmRestoreField(user->
swarm, descriptor->
canonical_name, NULL, NULL, (
void **)&field));
701 PetscFunctionReturn(0);
714 PetscFunctionBeginUser;
715 if (!plan) PetscFunctionReturn(0);
717 PetscCall(DMSwarmGetLocalSize(user->
swarm, &nlocal));
718 if (simCtx->
rank == 0) {
719 char path[PETSC_MAX_PATH_LEN];
721 PetscCall(PetscSNPrintf(path,
sizeof(path),
"%s/particle_initial_fields.csv", simCtx->
analysis_dir));
722 csv = fopen(path,
"w");
726 fprintf(csv,
"field,component,count,mean,variance,min,max");
732 for (PetscInt b = 0; b < plan->
count; ++b) {
735 const PetscReal *field = NULL;
736 PetscReal scale = 1.0;
740 PetscCall(DMSwarmGetField(user->
swarm, descriptor->
canonical_name, NULL, NULL, (
void **)&field));
741 for (PetscInt c = 0; c < binding->
components; ++c) {
743 PetscReal sums[3] = {0.0, 0.0, 0.0}, extremes[2] = {PETSC_MAX_REAL, PETSC_MAX_REAL};
746 for (PetscInt p = 0; p < nlocal; ++p) {
747 const PetscReal value = field[binding->
components * p + c] * scale;
750 sums[2] += value * value;
751 extremes[0] = PetscMin(extremes[0], value);
752 extremes[1] = PetscMin(extremes[1], -value);
754 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, sums, 3, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
755 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, extremes, 2, MPIU_REAL, MPI_MIN, PETSC_COMM_WORLD));
756 const PetscReal count = sums[0], lowest = extremes[0], highest = -extremes[1];
757 const PetscReal mean = (count > 0.0) ? sums[1] / count : 0.0;
758 const PetscReal variance = (count > 0.0) ? PetscMax(sums[2] / count - mean * mean, 0.0) : 0.0;
761 for (PetscInt p = 0; p < nlocal; ++p) {
762 const PetscReal value = field[binding->
components * p + c] * scale;
763 PetscInt bin = (PetscInt)((value - lowest) / width);
769 "[Particle IC] %s[%" PetscInt_FMT
"]: n=%.0f mean=%.6g var=%.6g min=%.6g max=%.6g\n",
770 descriptor->
canonical_name, c, (
double)count, (
double)mean, (
double)variance,
771 (
double)(count > 0.0 ? lowest : 0.0), (
double)(count > 0.0 ? highest : 0.0));
773 fprintf(csv,
"%s,%d,%.0f,%.10e,%.10e,%.10e,%.10e", descriptor->
canonical_name, (
int)c,
774 (
double)count, (
double)mean, (
double)variance,
775 (
double)(count > 0.0 ? lowest : 0.0), (
double)(count > 0.0 ? highest : 0.0));
780 PetscCall(DMSwarmRestoreField(user->
swarm, descriptor->
canonical_name, NULL, NULL, (
void **)&field));
782 if (csv) fclose(csv);
783 PetscFunctionReturn(0);
792 PetscFunctionBeginUser;
793 if (!plan || !*plan) PetscFunctionReturn(0);
794 for (PetscInt b = 0; b < (*plan)->count; ++b) {
799 PetscCall(PetscFree((*plan)->bindings));
800 PetscCall(PetscFree(*plan));
801 PetscFunctionReturn(0);
static const char *const kParticleVariables[]
Names a particle expression may use, in the order their values are supplied.
static PetscErrorCode DomainBounds(const SimCtx *simCtx, Cmpnts *lower, Cmpnts *upper)
Global domain bounds, in solver units, from the replicated rank bounding boxes.
static void EmitNode(const ExpressionParser *parser, PetscInt index, PicurvExpression *expression, PetscInt *depth)
Emit postfix code for a subtree and track the stack depth it needs.
static PetscInt ParseComparison(ExpressionParser *parser)
sum (comparison sum)*; a chain a < b < c is (a < b) and (b < c).
static PetscInt ParseAtom(ExpressionParser *parser)
number | name | name(args) | (expression)
#define PARTICLE_VARIABLE_COUNT
static void SkipSpace(ExpressionParser *parser)
Skip whitespace before the next token.
PetscErrorCode PicurvExpressionEvaluate(const PicurvExpression *expression, const PetscReal *values, const PicurvExpressionDrawKey *key, PetscReal *result)
Implementation of PicurvExpressionEvaluate().
PetscErrorCode PicurvExpressionDestroy(PicurvExpression **expression)
Implementation of PicurvExpressionDestroy().
ParticleFieldBinding * bindings
PetscErrorCode ParticleFieldPlanCreate(ParticleFieldPlan **plan)
Implementation of ParticleFieldPlanCreate().
PetscErrorCode ParticleFieldPlanSummarize(UserCtx *user, const ParticleFieldPlan *plan)
Implementation of ParticleFieldPlanSummarize().
#define PARTICLE_FIELD_MAX_COMPONENTS
static PetscInt ParseUnary(ExpressionParser *parser)
Parses a sign prefix recursively and wraps the operand in a negate or identity node.
static PetscInt ParseNot(ExpressionParser *parser)
'not' not | comparison
static PetscInt CountCode(const ExpressionParser *parser, PetscInt index)
Count the instructions a subtree emits (shared subtrees count per use).
#define PARTICLE_FIELD_HISTOGRAM_BINS
const char *const * names
static uint64_t Mix64(uint64_t z)
splitmix64 finalizer: a bijective mix of 64 bits.
static const struct @1 kFunctions[]
Name, arity, and opcode of every callable function.
ExpressionInstruction * code
static PetscBool Accept(ExpressionParser *parser, const char *token)
Consume token if it is next, and report whether it was.
PicurvExpression * component[3]
static PetscReal Draw(const PicurvExpressionDrawKey *key, const ExpressionInstruction *instruction)
A draw keyed on the particle, the event, the stream, and the function.
PetscErrorCode ParticleFieldPlanDestroy(ParticleFieldPlan **plan)
Implementation of ParticleFieldPlanDestroy().
static PetscReal Extreme(PetscReal a, PetscReal b, PetscBool maximum)
Maximum or minimum that propagates NaN, as numpy does.
static void ParserFail(ExpressionParser *parser, const char *message)
Record the first parse error with its position; later ones are consequences.
static PetscInt NewNode(ExpressionParser *parser, ExpressionOp op, PetscInt nchild, PetscInt a, PetscInt b, PetscInt c)
Append a node to the pool and return its index, or -1 once an error is set.
PetscErrorCode PicurvExpressionCompile(const char *text, const char *const *names, PetscInt name_count, PetscBool allow_random, PicurvExpression **expression)
Implementation of PicurvExpressionCompile().
static PetscInt ParseSum(ExpressionParser *parser)
Parses a left-associative chain of + and -, folding each operator into a node.
static PetscReal UnitFromHash(uint64_t hash)
Uniform on [0, 1) from the top 53 bits of a hash.
static PetscInt ParseTerm(ExpressionParser *parser)
Parses a left-associative chain of *, /, %, folding each operator into a node.
static PetscInt ParseOr(ExpressionParser *parser)
and ('or' and)*
static PetscInt ParseAnd(ExpressionParser *parser)
not ('and' not)*
PetscErrorCode ParticleFieldPlanApply(UserCtx *user, const ParticleFieldPlan *plan, const ParticleFieldEvent *event, PetscInt first, PetscInt end)
Implementation of ParticleFieldPlanApply().
static PetscReal Normalized(PetscReal value, PetscReal lower, PetscReal upper)
Position within the domain along one axis, in [0, 1]; 0 across a flat axis.
static PetscInt ParsePower(ExpressionParser *parser)
Parses an atom and, when a power operator follows, appends a power node.
#define PARTICLE_FIELD_EXPRESSION_LENGTH
One tree node; children index the node pool.
Parser state: the text, a cursor, the node pool, and the names in scope.
One configured field: its identity and one expression per component.
Configured initial values of particle-carried fields, and the expression language that defines them.
PetscInt64 pid
Particle identity; draws are pure functions of it.
PetscInt64 salt
Event identity keying random draws: 0 for the t=0 population.
PetscInt64 salt
Event that produced the particle: 0 for the t=0 population.
PetscInt64 field
Field whose expression draws, the default stream's namespace.
PetscReal physical_time
Time, in seconds, the evaluated particles appear at.
PetscInt64 seed
Run seed (-particle_random_seed).
When and why a plan is applied.
What a random draw is keyed on, besides the particle and its stream.
@ FIELD_DIMENSION_FIXED
The exponents are the field's dimension.
PetscErrorCode FieldDimensionReferenceScale(const ScalingCtx *scaling, FieldDimension dimension, PetscReal *scale)
Return the factor that turns a solver value of one dimension into physical units.
Logging utilities and macros for PETSc-based applications.
#define GLOBAL
Scope for global logging across all processes.
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
@ LOG_INFO
Informational messages about program execution.
@ LOG_WARNING
Non-critical issues that warrant attention.
const char * ParticleFieldName(ParticleFieldId field_id)
Return the canonical PETSc DMSwarm name for an ID.
ParticleFieldId
Compile-time identity for a persistent solver-particle field.
@ PARTICLE_FIELD_ID_POSITION
@ PARTICLE_FIELD_ID_COUNT
unsigned int capabilities
PetscErrorCode ParticleFieldIdFromName(const char *field_name, ParticleFieldId *field_id)
Resolve a canonical name or registered alias at a text-ingress boundary.
@ PARTICLE_FIELD_CAPABILITY_USER_INITIALIZE
The particle carries the value, so a configured initial value survives: nothing re-derives it from th...
PetscErrorCode ParticleFieldGetDescriptor(ParticleFieldId field_id, const ParticleFieldDescriptor **descriptor)
Return immutable metadata for a valid particle field ID.
const char * canonical_name
Immutable metadata for one persistent particle field.
SimCtx * simCtx
Back-pointer to the master simulation context.
Cmpnts max_coords
Maximum x, y, z coordinates of the bounding box.
Cmpnts min_coords
Minimum x, y, z coordinates of the bounding box.
char analysis_dir[PETSC_MAX_PATH_LEN]
PetscInt particleRandomSeed
Base seed for every particle RNG stream (-particle_random_seed).
A 3D point or vector with PetscScalar components.
The master context for the entire simulation.
User-defined context containing data specific to a single computational grid level.
A generic C-style linked list node for integers.