33 OP_ABS,
OP_COS,
OP_ERF,
OP_EXP,
OP_SIN,
OP_SQRT,
OP_TAN,
OP_TANH,
OP_COSH,
OP_SINH,
OP_LOG,
OP_FLOOR,
50 {
"abs", 1, 1,
OP_ABS, PETSC_FALSE}, {
"cos", 1, 1,
OP_COS, PETSC_FALSE},
51 {
"exp", 1, 1,
OP_EXP, PETSC_FALSE}, {
"sin", 1, 1,
OP_SIN, PETSC_FALSE},
52 {
"sqrt", 1, 1,
OP_SQRT, PETSC_FALSE}, {
"tan", 1, 1,
OP_TAN, PETSC_FALSE},
53 {
"erf", 1, 1,
OP_ERF, PETSC_FALSE}, {
"tanh", 1, 1,
OP_TANH, PETSC_FALSE},
54 {
"cosh", 1, 1,
OP_COSH, PETSC_FALSE}, {
"sinh", 1, 1,
OP_SINH, PETSC_FALSE},
55 {
"log", 1, 1,
OP_LOG, PETSC_FALSE}, {
"floor", 1, 1,
OP_FLOOR, PETSC_FALSE},
56 {
"atan2", 2, 2,
OP_ATAN2, PETSC_FALSE},
57 {
"maximum", 2, 2,
OP_MAXIMUM, PETSC_FALSE}, {
"minimum", 2, 2,
OP_MINIMUM, PETSC_FALSE},
58 {
"where", 3, 3,
OP_WHERE, PETSC_FALSE},
59 {
"besselj", 2, 2,
OP_BESSELJ, PETSC_FALSE}, {
"bessely", 2, 2,
OP_BESSELY, PETSC_FALSE},
60 {
"ber", 1, 1,
OP_BER, PETSC_FALSE}, {
"bei", 1, 1,
OP_BEI, PETSC_FALSE},
61 {
"uniform", 0, 1,
OP_UNIFORM, PETSC_TRUE}, {
"normal", 0, 1,
OP_NORMAL, PETSC_TRUE},
65#define EXPRESSION_MAX_SERIES_DEPTH 4
66#define EXPRESSION_MAX_SERIES_TERMS 1000000
111 if (!parser->
error[0]) {
112 snprintf(parser->
error,
sizeof(parser->
error),
"%s at position %zu of '%s'",
113 message, parser->
pos + 1, parser->
text);
122 while (parser->
text[parser->
pos] && isspace((
unsigned char)parser->
text[parser->
pos])) parser->
pos++;
130 size_t length = strlen(token);
134 if (isalpha((
unsigned char)token[0])) {
135 const char next = parser->
text[parser->
pos + length];
139 if ((!strcmp(token,
"*") && parser->
text[parser->
pos + 1] ==
'*') ||
140 ((!strcmp(token,
"<") || !strcmp(token,
">")) && parser->
text[parser->
pos + 1] ==
'=')) {
144 parser->
pos += length;
151 PetscInt a, PetscInt b, PetscInt c)
163 node->nchild = nchild;
168 return parser->
count++;
178 PetscReal sign = 1.0;
183 *bound = sign *
node->value;
194 PetscReal lower = 0.0, upper = 0.0;
197 const char *start = parser->
text + parser->
pos;
198 while (isalnum((
unsigned char)start[length]) || start[length] ==
'_') length++;
199 if (!length || isdigit((
unsigned char)start[0]) || length >=
sizeof(name)) {
200 ParserFail(parser,
"a series needs an index name first");
204 memcpy(name, start, length);
206 parser->
pos += length;
207 for (PetscInt v = 0; v < parser->
name_count; ++v) {
210 for (PetscInt level = 0; level < parser->
series_depth; ++level) {
216 const PetscInt lo =
ParseOr(parser);
218 const PetscInt hi =
ParseOr(parser);
221 ParserFail(parser,
"series bounds must be integer numbers");
226 ParserFail(parser,
"a series may add at most 1000000 terms");
232 const PetscInt body =
ParseOr(parser);
251 const char *start = parser->
text + parser->
pos;
253 if (isdigit((
unsigned char)*start) || (*start ==
'.' && isdigit((
unsigned char)start[1]))) {
256 while (isdigit((
unsigned char)start[length])) length++;
257 if (start[length] ==
'.') { length++;
while (isdigit((
unsigned char)start[length])) length++; }
258 if (start[length] ==
'e' || start[length] ==
'E') {
259 size_t exponent = length + 1;
260 if (start[exponent] ==
'+' || start[exponent] ==
'-') exponent++;
262 while (isdigit((
unsigned char)start[exponent])) exponent++;
265 if (isalnum((
unsigned char)start[length]) || start[length] ==
'_' || start[length] ==
'.') {
270 const PetscReal value = strtod(start, NULL);
271 parser->
pos += length;
277 if (isalpha((
unsigned char)*start) || *start ==
'_') {
280 while (isalnum((
unsigned char)start[length]) || start[length] ==
'_') length++;
282 memcpy(name, start, length);
284 if (!strcmp(name,
"and") || !strcmp(name,
"or") || !strcmp(name,
"not")) {
285 ParserFail(parser,
"operator where an operand was expected");
289 parser->
pos += length;
291 if (
Accept(parser,
"(")) {
293 if (strcmp(name,
kFunctions[f].name))
continue;
295 ParserFail(parser,
"random draws are not available in this expression");
299 PetscInt args[3] = {-1, -1, -1}, nargs = 0;
300 if (!
Accept(parser,
")")) {
303 args[nargs++] =
ParseOr(parser);
305 }
while (
Accept(parser,
","));
309 ParserFail(parser,
"wrong number of arguments");
321 stream->
value != PetscFloorReal(stream->
value)) {
322 ParserFail(parser,
"a draw's stream must be a non-negative integer literal");
339 for (PetscInt level = parser->
series_depth - 1; level >= 0; --level) {
340 if (strcmp(name, parser->
series_index[level]))
continue;
346 if (!strcmp(name,
"pi")) {
352 for (PetscInt v = 0; v < parser->
name_count; ++v) {
353 if (!strcmp(name, parser->
names[v])) {
364 if (
Accept(parser,
"(")) {
365 PetscInt inner =
ParseOr(parser);
370 ParserFail(parser,
"expected a number, name, or '('");
420 else if (
Accept(parser,
"/")) {
450 static const struct {
const char *token;
ExpressionOp op; } kComparisons[] = {
451 {
"==",
OP_EQ}, {
"!=",
OP_NE}, {
"<=",
OP_LE}, {
">=",
OP_GE}, {
"<",
OP_LT}, {
">",
OP_GT},
453 PetscInt left =
ParseSum(parser), result = -1;
457 for (
size_t c = 0; c <
sizeof(kComparisons) /
sizeof(kComparisons[0]); ++c) {
458 if (
Accept(parser, kComparisons[c].token)) { op = kComparisons[c].op;
break; }
461 const PetscInt right =
ParseSum(parser);
462 const PetscInt pair =
NewNode(parser, op, 2, left, right, -1);
463 result = (result < 0) ? pair :
NewNode(parser,
OP_AND, 2, result, pair, -1);
522 for (PetscInt c = 0; c <
node->nchild; ++c)
EmitNode(parser,
node->child[c], expression, depth);
524 instruction->
op =
node->op;
527 *depth += 1 -
node->nchild;
538 PetscInt total = (
node->op ==
OP_SUM) ? 3 : 1;
540 for (PetscInt c = 0; c <
node->nchild; ++c) total +=
CountCode(parser,
node->child[c]);
553 PetscInt root, depth = 0;
555 PetscFunctionBeginUser;
557 PetscCheck(text && expression, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Expression text and output are required.");
558 PetscCall(PetscMemzero(&parser,
sizeof(parser)));
560 parser.
names = names;
563 parser.
capacity = 4 * (PetscInt)strlen(text) + 8;
569 if (parser.
error[0]) {
570 PetscCall(PetscFree(parser.
nodes));
571 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
"Invalid expression: %s.", parser.
error);
574 PetscCall(PetscNew(expression));
575 (*expression)->length = 0;
576 PetscCall(PetscMalloc1(
CountCode(&parser, root), &(*expression)->code));
577 EmitNode(&parser, root, *expression, &depth);
578 PetscCall(PetscFree(parser.
nodes));
580 PetscFunctionReturn(0);
589 z += 0x9E3779B97F4A7C15ULL;
590 z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ULL;
591 z = (z ^ (z >> 27)) * 0x94D049BB133111EBULL;
592 return z ^ (z >> 31);
601 return (PetscReal)(hash >> 11) * (1.0 / 9007199254740992.0);
609 PetscInt64 pid, PetscInt64 salt)
625 const uint64_t stream = instruction->
arg ? (uint64_t)instruction->
value : (uint64_t)key->
field;
627 ^ (uint64_t)instruction->
op);
633 return PetscSqrtReal(-2.0 * PetscLogReal(u1)) * PetscCosReal(2.0 * PETSC_PI * u2);
643static PetscReal
Kelvin(PetscReal x, PetscBool imaginary)
646 const PetscReal abs_x = PetscAbsReal(x);
648 const PetscReal argument = abs_x / PetscSqrtReal(2.0);
649 PetscReal coefficient = 1.0, reciprocal = 1.0, total = 0.0;
650 for (PetscInt k = 0; k < 14; ++k) {
651 const PetscReal phase = argument + (0.75 * k - 0.125) * PETSC_PI;
652 total += coefficient * reciprocal * (imaginary ? PetscSinReal(phase) : PetscCosReal(phase));
653 coefficient *= -(2.0 * k + 1.0) * (2.0 * k + 1.0) / (8.0 * (k + 1.0));
657 return PetscExpReal(argument) / PetscSqrtReal(2.0 * PETSC_PI * abs_x) * total;
659 const PetscReal q = 0.0625 * x * x * x * x;
660 PetscReal term = imaginary ? 0.25 * x * x : 1.0, total = term;
662 for (PetscInt m = 1; m < 200; ++m) {
663 const PetscReal a = imaginary ? 2.0 * m : 2.0 * m - 1.0, b = a + 1.0;
664 term *= -q / (a * a * b * b);
666 if (PetscAbsReal(term) <= 1.0e-17 * PetscAbsReal(total))
break;
673static PetscReal
Bessel(PetscReal order, PetscReal x, PetscBool second)
676 if (order != PetscFloorReal(order) || PetscAbsReal(order) > 1.0e6) {
PROFILE_HELPER_END;
return NAN; }
677 const int n = (int)order;
679 return second ? (PetscReal)yn(n, (
double)x) : (PetscReal)jn(n, (
double)x);
683static PetscReal
Extreme(PetscReal a, PetscReal b, PetscBool maximum)
688 return maximum ? PetscMax(a, b) : PetscMin(a, b);
698 PetscReal stack[expression->
max_depth + 1];
702 PetscFunctionBeginUser;
704 PetscCheck(!expression->
draws || key, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
705 "An expression that draws random numbers needs a draw key.");
706 for (PetscInt i = 0; i < expression->
length; ++i) {
710 switch (instruction->
op) {
712 case OP_VAR: stack[top++] = values[instruction->
arg];
break;
714 case OP_NORMAL: stack[top++] =
Draw(key, instruction);
break;
715 case OP_NEG: stack[top - 1] = -stack[top - 1];
break;
717 case OP_NOT: stack[top - 1] = (stack[top - 1] == 0.0) ? 1.0 : 0.0;
break;
718 case OP_ABS: stack[top - 1] = PetscAbsReal(stack[top - 1]);
break;
719 case OP_COS: stack[top - 1] = PetscCosReal(stack[top - 1]);
break;
720 case OP_EXP: stack[top - 1] = PetscExpReal(stack[top - 1]);
break;
721 case OP_SIN: stack[top - 1] = PetscSinReal(stack[top - 1]);
break;
722 case OP_SQRT: stack[top - 1] = PetscSqrtReal(stack[top - 1]);
break;
723 case OP_TAN: stack[top - 1] = PetscTanReal(stack[top - 1]);
break;
724 case OP_ERF: stack[top - 1] = (PetscReal)erf((
double)stack[top - 1]);
break;
725 case OP_TANH: stack[top - 1] = PetscTanhReal(stack[top - 1]);
break;
726 case OP_COSH: stack[top - 1] = PetscCoshReal(stack[top - 1]);
break;
727 case OP_SINH: stack[top - 1] = PetscSinhReal(stack[top - 1]);
break;
728 case OP_LOG: stack[top - 1] = PetscLogReal(stack[top - 1]);
break;
729 case OP_FLOOR: stack[top - 1] = PetscFloorReal(stack[top - 1]);
break;
730 case OP_BER: stack[top - 1] =
Kelvin(stack[top - 1], PETSC_FALSE);
break;
731 case OP_BEI: stack[top - 1] =
Kelvin(stack[top - 1], PETSC_TRUE);
break;
732 case OP_LOCAL: stack[top++] = index[instruction->
arg];
break;
735 index[instruction->
arg] = instruction->
value;
741 const PetscInt body = (PetscInt)instruction->
value;
742 const PetscReal upper = expression->
code[i - body - 1].
value;
743 const PetscReal term = stack[--top];
744 stack[top - 1] += term;
745 index[instruction->
arg] += 1.0;
746 if (index[instruction->
arg] <= upper) i -= body + 1;
749 c = stack[--top]; b = stack[--top]; a = stack[top - 1];
750 stack[top - 1] = (a != 0.0) ? b : c;
753 b = stack[--top]; a = stack[top - 1];
754 switch (instruction->
op) {
755 case OP_ADD: a = a + b;
break;
756 case OP_SUB: a = a - b;
break;
757 case OP_MUL: a = a * b;
break;
758 case OP_DIV: a = a / b;
break;
760 case OP_MOD: a = (b == 0.0) ? NAN : a - b * PetscFloorReal(a / b);
break;
761 case OP_POW: a = PetscPowReal(a, b);
break;
762 case OP_EQ: a = (a == b) ? 1.0 : 0.0;
break;
763 case OP_NE: a = (a != b) ? 1.0 : 0.0;
break;
764 case OP_LT: a = (a < b) ? 1.0 : 0.0;
break;
765 case OP_LE: a = (a <= b) ? 1.0 : 0.0;
break;
766 case OP_GT: a = (a > b) ? 1.0 : 0.0;
break;
767 case OP_GE: a = (a >= b) ? 1.0 : 0.0;
break;
768 case OP_AND: a = (a != 0.0 && b != 0.0) ? 1.0 : 0.0;
break;
769 case OP_OR: a = (a != 0.0 || b != 0.0) ? 1.0 : 0.0;
break;
770 case OP_ATAN2: a = PetscAtan2Real(a, b);
break;
775 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB,
"Unknown expression opcode %d.", (
int)instruction->
op);
782 PetscFunctionReturn(0);
791 PetscFunctionBeginUser;
794 PetscCall(PetscFree((*expression)->code));
795 PetscCall(PetscFree(*expression));
797 PetscFunctionReturn(0);
807 PetscFunctionBeginUser;
810 for (PetscInt i = 0; i < expression->
length && !*uses; ++i) {
811 if (expression->
code[i].
op ==
OP_VAR && expression->
code[i].
arg == index) *uses = PETSC_TRUE;
814 PetscFunctionReturn(0);
822 "x",
"y",
"z",
"t",
"xi",
"eta",
"zeta",
"L_xi",
"L_eta",
"L_zeta",
"r"};
824#define PICURV_SOURCE_EXPRESSION_LENGTH 4096
833 static const char *
const kTime[] = {
"t"};
835 PetscBool found = PETSC_FALSE;
837 PetscFunctionBeginUser;
839 PetscCall(PetscMemzero(source,
sizeof(*source)));
840 PetscCall(PetscSNPrintf(option,
sizeof(option),
"-%s_frame", prefix));
841 PetscCall(PetscOptionsGetString(NULL, NULL, option, frame,
sizeof(frame), &found));
842 PetscCheck(found || has_data, PETSC_COMM_WORLD, PETSC_ERR_USER_INPUT,
"Velocity source option %s is required.", option);
843 if (!found) PetscCall(PetscStrncpy(frame, on_face ?
"normal" :
"cartesian",
sizeof(frame)));
848 else SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_USER_INPUT,
"%s is '%s'; expected cartesian, curvilinear, or %s.",
849 option, frame, on_face ?
"normal" :
"contravariant");
851 for (PetscInt c = 0; c < source->
count; ++c) {
852 PetscBool uses_t = PETSC_FALSE;
853 PetscCall(PetscSNPrintf(option,
sizeof(option),
"-%s_expr_%d", prefix, (
int)c));
854 PetscCall(PetscOptionsGetString(NULL, NULL, option, text,
sizeof(text), &found));
855 if (!found && has_data && c == 0) { source->
count = 0;
break; }
856 PetscCheck(found, PETSC_COMM_WORLD, PETSC_ERR_USER_INPUT,
"Velocity source option %s is required.", option);
863 PetscCall(PetscSNPrintf(option,
sizeof(option),
"-%s_bulk_velocity", prefix));
864 PetscCall(PetscOptionsGetString(NULL, NULL, option, text,
sizeof(text), &found));
865 if (!found && on_face) {
866 PetscCall(PetscSNPrintf(option,
sizeof(option),
"-%s_flow_rate", prefix));
867 PetscCall(PetscOptionsGetString(NULL, NULL, option, text,
sizeof(text), &source->
bulk_is_flow_rate));
875 PetscFunctionReturn(0);
883 const PetscReal local[3],
const char *where, PetscReal *factor)
885 PetscReal global[3], target;
887 PetscFunctionBeginUser;
889 PetscCallMPI(MPI_Allreduce(local, global, 3, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
890 PetscCheck(global[2] > 0.0, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
891 "%s has no open area or volume to set a bulk velocity on.", where);
892 PetscCheck(global[0] != 0.0, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
893 "%s: the source's mean speed is zero, so it cannot be scaled to a bulk velocity.", where);
896 *factor = (target * global[2] - global[1]) / global[0];
898 (
double)target, (
double)(global[0] / global[2]), (
double)(global[1] / global[2]), (
double)*factor);
900 PetscFunctionReturn(0);
910 PetscReal v[3] = {0.0, 0.0, 0.0};
912 PetscFunctionBeginUser;
914 for (PetscInt c = 0; c < source->
count; ++c) {
916 PetscCheck(!PetscIsInfOrNanReal(v[c]), PETSC_COMM_SELF, PETSC_ERR_FP,
917 "Velocity source value %" PetscInt_FMT
" is %g at (x, y, z) = (%g, %g, %g), t = %g.",
923 value->
x = value->
y = value->
z = 0.0;
924 for (PetscInt a = 0; a < 3; ++a) {
925 const PetscReal norm = PetscSqrtReal(edges[a].x * edges[a].x + edges[a].y * edges[a].y + edges[a].z * edges[a].z);
926 PetscCheck(norm > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
"A cell edge has zero length.");
927 value->
x += v[a] * edges[a].
x / norm;
928 value->
y += v[a] * edges[a].
y / norm;
929 value->
z += v[a] * edges[a].
z / norm;
937 PetscFunctionReturn(0);
945 PetscReal physical_time, PetscReal *factor)
947 const DMDALocalInfo *info = &user->
info;
949 const PetscInt xs = info->xs, xe = info->xs + info->xm, mx = info->mx;
950 const PetscInt ys = info->ys, ye = info->ys + info->ym, my = info->my;
951 const PetscInt zs = info->zs, ze = info->zs + info->zm, mz = info->mz;
953 const Cmpnts ***cent, ***frac, ***len, ***csi, ***eta, ***zet, ***ucat;
954 const PetscReal ***aj;
956 PetscFunctionBeginUser;
958 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Cent, ¢));
959 PetscCall(DMDAVecGetArrayRead(user->
fda, fraction, &frac));
960 PetscCall(DMDAVecGetArrayRead(user->
fda, length, &len));
961 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lCsi, &csi));
962 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lEta, &eta));
963 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lZet, &zet));
964 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lAj, &aj));
965 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucat, &ucat));
967 for (PetscInt k = (zs == 0) ? 1 : zs; k < ((ze == mz) ? mz - 1 : ze); ++k)
968 for (PetscInt j = (ys == 0) ? 1 : ys; j < ((ye == my) ? my - 1 : ye); ++j)
969 for (PetscInt i = (xs == 0) ? 1 : xs; i < ((xe == mx) ? mx - 1 : xe); ++i) {
970 const PetscReal volume = 1.0 / PetscAbsReal(aj[k][j][i]);
975 const PetscReal speed = PetscSqrtReal(v.
x * v.
x + v.
y * v.
y + v.
z * v.
z);
976 local[0] += speed * volume;
977 if (speed > 0.0) local[1] += U_ref * (ucat[k][j][i].
x * v.
x + ucat[k][j][i].
y * v.
y +
978 ucat[k][j][i].
z * v.
z) / speed * volume;
981 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucat, &ucat));
982 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lAj, &aj));
983 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lZet, &zet));
984 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lEta, &eta));
985 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lCsi, &csi));
986 PetscCall(DMDAVecRestoreArrayRead(user->
fda, length, &len));
987 PetscCall(DMDAVecRestoreArrayRead(user->
fda, fraction, &frac));
988 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Cent, ¢));
991 PetscFunctionReturn(0);
999 PetscReal physical_time, PetscReal factor, PetscBool boundary_faces)
1001 const DMDALocalInfo *info = &user->
info;
1003 const PetscInt start[3] = {info->xs, info->ys, info->zs};
1004 const PetscInt end[3] = {info->xs + info->xm, info->ys + info->ym, info->zs + info->zm};
1005 const PetscInt nodes[3] = {info->mx, info->my, info->mz};
1006 const PetscInt lo[3] = {(start[0] == 0) ? 1 : start[0], (start[1] == 0) ? 1 : start[1], (start[2] == 0) ? 1 : start[2]};
1007 const PetscInt hi[3] = {(end[0] == nodes[0]) ? nodes[0] - 1 : end[0], (end[1] == nodes[1]) ? nodes[1] - 1 : end[1],
1008 (end[2] == nodes[2]) ? nodes[2] - 1 : end[2]};
1009 const Cmpnts ***frac, ***len, ***csi, ***eta, ***zet, ***centx, ***centy, ***centz;
1010 const PetscReal ***aj;
1014 PetscFunctionBeginUser;
1016 PetscCall(DMDAVecGetArrayRead(user->
fda, fraction, &frac));
1017 PetscCall(DMDAVecGetArrayRead(user->
fda, length, &len));
1018 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lCsi, &csi));
1019 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lEta, &eta));
1020 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lZet, &zet));
1021 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lCentx, ¢x));
1022 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lCenty, ¢y));
1023 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lCentz, ¢z));
1024 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lAj, &aj));
1025 PetscCall(DMDAVecGetArray(user->
fda, user->
Ucont, &ucont));
1027 for (PetscInt k = lo[2]; k < hi[2]; ++k)
1028 for (PetscInt j = lo[1]; j < hi[1]; ++j)
1029 for (PetscInt i = lo[0]; i < hi[0]; ++i) {
1030 const PetscInt cell[3] = {i, j, k};
1031 const PetscReal lengths[3] = {len[k][j][i].
x, len[k][j][i].
y, len[k][j][i].
z};
1034 for (PetscInt a = 0; a < 3; ++a) {
1035 const PetscReal half = 0.5 * PetscSqrtReal(edges[a].x * edges[a].x + edges[a].y * edges[a].y +
1036 edges[a].z * edges[a].z) / lengths[a];
1038 const PetscInt sides = (boundary_faces && start[a] == 0 && cell[a] == 1) ? 2 : 1;
1039 for (PetscInt side = 0; side < sides; ++side) {
1040 const PetscInt offset = side ? -1 : 0;
1041 const PetscInt fi = i + (a == 0 ? offset : 0), fj = j + (a == 1 ? offset : 0), fk = k + (a == 2 ? offset : 0);
1042 const Cmpnts metric = (a == 0) ? csi[fk][fj][fi] : (a == 1) ? eta[fk][fj][fi] : zet[fk][fj][fi];
1043 const Cmpnts centre = (a == 0) ? centx[fk][fj][fi] : (a == 1) ? centy[fk][fj][fi] : centz[fk][fj][fi];
1050 flux = factor * value / (U_ref * L_ref * L_ref);
1052 const PetscReal area = PetscSqrtReal(metric.x * metric.x + metric.y * metric.y + metric.z * metric.z);
1059 flux = (factor * v.
x / U_ref) * metric.x + (factor * v.
y / U_ref) * metric.y +
1060 (factor * v.
z / U_ref) * metric.z;
1062 if (a == 0) ucont[fk][fj][fi].
x += flux;
1063 if (a == 1) ucont[fk][fj][fi].
y += flux;
1064 if (a == 2) ucont[fk][fj][fi].
z += flux;
1068 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Ucont, &ucont));
1069 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lAj, &aj));
1070 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lCentz, ¢z));
1071 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lCenty, ¢y));
1072 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lCentx, ¢x));
1073 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lZet, &zet));
1074 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lEta, &eta));
1075 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lCsi, &csi));
1076 PetscCall(DMDAVecRestoreArrayRead(user->
fda, length, &len));
1077 PetscCall(DMDAVecRestoreArrayRead(user->
fda, fraction, &frac));
1079 PetscFunctionReturn(0);
1087 PetscReal physical_time)
1089 const DMDALocalInfo *info = &user->
info;
1091 const PetscInt xs = info->xs, xe = info->xs + info->xm, mx = info->mx;
1092 const PetscInt ys = info->ys, ye = info->ys + info->ym, my = info->my;
1093 const PetscInt zs = info->zs, ze = info->zs + info->zm, mz = info->mz;
1094 const Cmpnts ***cent, ***frac, ***len;
1097 PetscFunctionBeginUser;
1099 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Cent, ¢));
1100 PetscCall(DMDAVecGetArrayRead(user->
fda, fraction, &frac));
1101 PetscCall(DMDAVecGetArrayRead(user->
fda, length, &len));
1102 PetscCall(DMDAVecGetArray(user->
da, user->
P, &p));
1104 for (PetscInt k = (zs == 0) ? 1 : zs; k < ((ze == mz) ? mz - 1 : ze); ++k)
1105 for (PetscInt j = (ys == 0) ? 1 : ys; j < ((ye == my) ? my - 1 : ye); ++j)
1106 for (PetscInt i = (xs == 0) ? 1 : xs; i < ((xe == mx) ? mx - 1 : xe); ++i) {
1110 p[k][j][i] = value / scaling->
P_ref;
1112 PetscCall(DMDAVecRestoreArray(user->
da, user->
P, &p));
1113 PetscCall(DMDAVecRestoreArrayRead(user->
fda, length, &len));
1114 PetscCall(DMDAVecRestoreArrayRead(user->
fda, fraction, &frac));
1115 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Cent, ¢));
1117 PetscFunctionReturn(0);
1127 const DMDALocalInfo *info = &user->
info;
1128 const PetscInt start[3] = {info->xs, info->ys, info->zs};
1129 const PetscInt end[3] = {info->xs + info->xm, info->ys + info->ym, info->zs + info->zm};
1130 const PetscInt nodes[3] = {info->mx, info->my, info->mz};
1132 const PetscBool negative = (PetscBool)((PetscInt)face_id % 2 == 0);
1133 PetscBool can_service = PETSC_FALSE;
1136 PetscReal face_area;
1138 PetscFunctionBeginUser;
1141 slots->
normal = (PetscInt)face_id / 2;
1142 slots->
a = (slots->
normal == 0) ? 1 : 0;
1143 slots->
b = (slots->
normal == 2) ? 1 : 2;
1144 const PetscInt normal = slots->
normal, a = slots->
a, b = slots->
b;
1146 slots->
layer = negative ? start[normal] : nodes[normal] - 2;
1147 slots->
lo[0] = (start[a] == 0) ? 1 : start[a];
1148 slots->
lo[1] = (start[b] == 0) ? 1 : start[b];
1149 slots->
n[0] = can_service ? ((end[a] == nodes[a]) ? nodes[a] - 1 : end[a]) - slots->
lo[0] : 0;
1150 slots->
n[1] = can_service ? ((end[b] == nodes[b]) ? nodes[b] - 1 : end[b]) - slots->
lo[1] : 0;
1151 n_slots = slots->
n[0] * slots->
n[1];
1152 PetscCall(PetscMalloc2(n_slots, &slots->
values, n_slots, &slots->
edges));
1156 const PetscInt cell = negative ? slots->
layer + 1 : slots->
layer;
1157 const Vec centres = (normal == 0) ? user->
lCentx : (normal == 1) ? user->
lCenty : user->
lCentz;
1158 const Cmpnts ***cent, ***frac, ***len, ***csi, ***eta, ***zet;
1159 const PetscReal ***aj;
1160 PetscCall(DMDAVecGetArrayRead(user->
fda, centres, ¢));
1161 PetscCall(DMDAVecGetArrayRead(user->
fda, fraction, &frac));
1162 PetscCall(DMDAVecGetArrayRead(user->
fda, length, &len));
1163 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lCsi, &csi));
1164 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lEta, &eta));
1165 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lZet, &zet));
1166 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lAj, &aj));
1167 for (PetscInt q = 0; q < slots->
n[1]; ++q)
1168 for (PetscInt p = 0; p < slots->
n[0]; ++p) {
1169 const PetscInt s = p + slots->
n[0] * q;
1170 PetscInt f[3], c[3];
1171 f[normal] = slots->
layer; f[a] = slots->
lo[0] + p; f[b] = slots->
lo[1] + q;
1172 c[normal] = cell; c[a] = f[a]; c[b] = f[b];
1178 const Cmpnts X = cent[f[2]][f[1]][f[0]];
1179 const PetscReal dx = X.
x - face_centre.
x, dy = X.
y - face_centre.
y, dz = X.
z - face_centre.
z;
1182 PetscCall(
ComputeCellEdgeVectors(aj[c[2]][c[1]][c[0]], csi[c[2]][c[1]][c[0]], eta[c[2]][c[1]][c[0]], zet[c[2]][c[1]][c[0]], slots->
edges[s]));
1183 const Cmpnts m = (normal == 0) ? csi[f[2]][f[1]][f[0]] : (normal == 1) ? eta[f[2]][f[1]][f[0]] : zet[f[2]][f[1]][f[0]];
1185 slots->
edges[s][normal] = through;
1187 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lAj, &aj));
1188 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lZet, &zet));
1189 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lEta, &eta));
1190 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lCsi, &csi));
1191 PetscCall(DMDAVecRestoreArrayRead(user->
fda, length, &len));
1192 PetscCall(DMDAVecRestoreArrayRead(user->
fda, fraction, &frac));
1193 PetscCall(DMDAVecRestoreArrayRead(user->
fda, centres, ¢));
1196 PetscFunctionReturn(0);
1205 PetscFunctionBeginUser;
1207 PetscCall(PetscFree2(slots->
values, slots->
edges));
1209 PetscFunctionReturn(0);
1218 PetscFunctionBeginUser;
1224 PetscFunctionReturn(0);
PetscErrorCode CanRankServiceFace(const DMDALocalInfo *info, PetscInt IM_nodes_global, PetscInt JM_nodes_global, PetscInt KM_nodes_global, BCFace face_id, PetscBool *can_service_out)
Determines if the current MPI rank owns any part of a specified global face.
PetscErrorCode ComputeCellEdgeVectors(PetscReal ajc, Cmpnts csi, Cmpnts eta, Cmpnts zet, Cmpnts edges[3])
Computes a cell's edge vectors along its three grid directions.
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) | sum(index, lo, hi, body) | (expression)
#define EXPRESSION_MAX_SERIES_TERMS
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().
uint64_t PicurvMix64(uint64_t z)
Implementation of PicurvMix64().
#define EXPRESSION_MAX_SERIES_DEPTH
Series that may nest inside one another, and terms one series may add.
PetscErrorCode PicurvExpressionDestroy(PicurvExpression **expression)
Implementation of PicurvExpressionDestroy().
PetscErrorCode PicurvSourceSetCellPressure(UserCtx *user, const PicurvExpression *pressure, Vec fraction, Vec length, PetscReal physical_time)
Implementation of PicurvSourceSetCellPressure().
PetscErrorCode PicurvVelocitySourceCreate(const char *prefix, PetscBool on_face, PetscBool has_data, PicurvVelocitySource *source)
Implementation of PicurvVelocitySourceCreate().
static PetscInt ParseUnary(ExpressionParser *parser)
Parses a sign prefix recursively and wraps the operand in a negate or identity node.
static const struct @0 kFunctions[]
Name, arity, and opcode of every callable function.
static PetscReal Bessel(PetscReal order, PetscReal x, PetscBool second)
Bessel function of the first or second kind of integer order; NaN for another order.
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).
PetscErrorCode PicurvSourceAddFluxes(UserCtx *user, const PicurvVelocitySource *source, Vec fraction, Vec length, PetscReal physical_time, PetscReal factor, PetscBool boundary_faces)
Implementation of PicurvSourceAddFluxes().
const char *const * names
PetscErrorCode PicurvSourceCellBulkFactor(UserCtx *user, const PicurvVelocitySource *source, Vec fraction, Vec length, PetscReal physical_time, PetscReal *factor)
Implementation of PicurvSourceCellBulkFactor().
static PetscReal Kelvin(PetscReal x, PetscBool imaginary)
Kelvin functions of order zero, ber(x) + i bei(x) = J0(x e^{3 pi i / 4}).
ExpressionInstruction * code
static PetscBool Accept(ExpressionParser *parser, const char *token)
Consume token if it is next, and report whether it was.
PetscErrorCode PicurvExpressionUsesVariable(const PicurvExpression *expression, PetscInt index, PetscBool *uses)
Implementation of PicurvExpressionUsesVariable().
PetscErrorCode PicurvVelocitySourceDestroy(PicurvVelocitySource *source)
Implementation of PicurvVelocitySourceDestroy().
static PetscInt ParseSeries(ExpressionParser *parser)
sum( has been read: index name, integer bounds, then the body with the index in scope.
static PetscReal Draw(const PicurvExpressionDrawKey *key, const ExpressionInstruction *instruction)
A draw keyed on the particle, the event, the stream, and the function.
static PetscReal Extreme(PetscReal a, PetscReal b, PetscBool maximum)
Maximum or minimum that propagates NaN, as numpy does.
const char *const kPicurvSourceVariableNames[PICURV_SOURCE_VAR_COUNT]
Names of PicurvSourceVariable, in order.
PetscErrorCode PicurvVelocitySourceBulkFactor(const PicurvVelocitySource *source, PetscReal physical_time, const PetscReal local[3], const char *where, PetscReal *factor)
Implementation of PicurvVelocitySourceBulkFactor().
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.
PetscReal PicurvUnitFromHash(uint64_t hash)
Implementation of PicurvUnitFromHash().
PetscErrorCode PicurvVelocitySourceEvaluate(const PicurvVelocitySource *source, const PetscReal *values, const Cmpnts edges[3], Cmpnts *value)
Implementation of PicurvVelocitySourceEvaluate().
PetscErrorCode PicurvSourceFaceSlotsCreate(UserCtx *user, BCFace face_id, Vec fraction, Vec length, PicurvSourceFaceSlots *slots)
Implementation of PicurvSourceFaceSlotsCreate().
PetscErrorCode PicurvExpressionCompile(const char *text, const char *const *names, PetscInt name_count, PetscBool allow_random, PicurvExpression **expression)
Implementation of PicurvExpressionCompile().
uint64_t PicurvParticleDrawHash(PetscInt64 seed, PicurvDrawSpace space, uint64_t stream, PetscInt64 pid, PetscInt64 salt)
Implementation of PicurvParticleDrawHash().
static PetscBool SeriesBound(const ExpressionParser *parser, PetscInt index, PetscReal *bound)
The value of a series bound: an integer literal, possibly negated or parenthesized.
#define PICURV_SOURCE_EXPRESSION_LENGTH
static PetscInt ParseSum(ExpressionParser *parser)
Parses a left-associative chain of + and -, folding each operator into a node.
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 PicurvSourceFaceSlotsDestroy(PicurvSourceFaceSlots *slots)
Implementation of PicurvSourceFaceSlotsDestroy().
static PetscInt ParsePower(ExpressionParser *parser)
Parses an atom and, when a power operator follows, appends a power node.
One tree node; children index the node pool.
Parser state: the text, a cursor, the node pool, and the names in scope.
The expression language shared by every configured field, and the keyed hashes its random draws and o...
PicurvExpression * bulk
Target mean speed [m/s] in t, or NULL.
PetscBool bulk_time_dependent
PetscInt normal
Logical axis of the face normal.
PetscInt64 pid
Particle identity; draws are pure functions of it.
PicurvDrawSpace
Disjoint key spaces of the keyed particle draws, so draws made for different purposes never coincide ...
@ PICURV_DRAW_SPACE_FIELD
An expression's default, per-field stream.
@ PICURV_DRAW_SPACE_NAMED_STREAM
uniform(k)/normal(k): a stream shared across fields.
PetscInt n[2]
Owned slots along the two tangential axes; 0 off the face.
@ PICURV_SOURCE_VAR_XI
Arc-length fraction along the xi grid line, 0 at the - face.
@ PICURV_SOURCE_VAR_T
Physical time [s].
@ PICURV_SOURCE_VAR_R
On a face, distance from the face's centre [m].
@ PICURV_SOURCE_VAR_Y
Physical y [m].
@ PICURV_SOURCE_VAR_X
Physical x of the point [m].
@ PICURV_SOURCE_VAR_COUNT
@ PICURV_SOURCE_VAR_CELL_COUNT
Variables a source reads on every target.
@ PICURV_SOURCE_VAR_Z
Physical z [m].
PetscInt b
The two tangential axes.
PetscInt layer
Index along the normal of the face's metric and flux.
PicurvExpression * component[3]
PetscBool time_dependent
Some component reads t.
PetscInt64 salt
Event that produced the particle: 0 for the t=0 population.
PetscReal(* values)[PICURV_SOURCE_VAR_COUNT]
Variables per slot; t is the caller's.
PetscInt64 field
Field whose expression draws, the default stream's namespace.
static void PicurvSourceSetVariables(PetscReal *values, Cmpnts point, Cmpnts fraction, Cmpnts length, PetscReal L_ref)
Fill a source's position and grid-line variables at one point.
PetscBool bulk_is_flow_rate
bulk is a volumetric flow rate [m^3/s] through a face instead.
Cmpnts(* edges)[3]
Directions per slot, for the curvilinear frame.
PetscInt lo[2]
First tangential indices of the owned slots.
@ PICURV_SOURCE_FRAME_NORMAL
One value: the speed into the domain through a face.
@ PICURV_SOURCE_FRAME_CONTRAVARIANT
Three values: the volume flux through the xi, eta, zeta faces; cells only.
@ PICURV_SOURCE_FRAME_CARTESIAN
Three values: x, y, z velocity components.
@ PICURV_SOURCE_FRAME_CURVILINEAR
Three values along the unit xi, eta, zeta grid-line directions.
PetscInt64 seed
Run seed (-particle_random_seed).
PetscInt count
1 for the normal frame, otherwise 3; 0 for staged data alone.
What a random draw is keyed on, besides the particle and its stream.
What a source reads at each boundary-face slot this rank owns, gathered once.
A prescribed velocity, for any target: one compiled expression per value, the frame they are in,...
Public interface for grid, solver, and metric setup routines.
PetscErrorCode CalculateFaceCenterAndArea(UserCtx *user, BCFace face_id, Cmpnts *face_center, PetscReal *face_area)
Calculates the geometric center and total area of a specified boundary face.
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...
#define PROFILE_HELPER_BEGIN
Marks the beginning of a profiled helper: timed only when enabled by name.
#define PROFILE_HELPER_END
Alias of PROFILE_FUNCTION_END for a function that began with PROFILE_HELPER_BEGIN.
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
@ LOG_DEBUG
Detailed debugging information.
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled function: an always-on aggregate timer.
SimCtx * simCtx
Back-pointer to the master simulation context.
BCFace
Identifies the six logical faces of a structured computational block.
A 3D point or vector with PetscScalar components.
User-defined context containing data specific to a single computational grid level.
A generic C-style linked list node for integers.