18 PetscFunctionBeginUser;
19 PetscCheck(node_like != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
20 "Classification output is required.");
21 PetscCheck(dim >= 0 && dim < 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
22 "Dimension must be 0, 1, or 2; got %" PetscInt_FMT
".", dim);
26 *node_like = PETSC_TRUE;
29 *node_like = PETSC_FALSE;
32 *node_like = (PetscBool)(dim == 0);
35 *node_like = (PetscBool)(dim == 1);
38 *node_like = (PetscBool)(dim == 2);
43 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
44 "Component-staggered layout has no single per-dimension classification.");
46 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
47 "Unknown field layout %d.", (
int)layout);
49 PetscFunctionReturn(0);
83 const DMDALocalInfo *info = NULL;
85 PetscInt owned_start[3];
86 PetscInt owned_end[3];
87 PetscInt global_size[3];
88 PetscBool periodic[3];
90 PetscFunctionBeginUser;
92 PetscCheck(user != NULL && plan != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
93 "Block context and plan output are required.");
95 "Only the fluid mask is implemented.");
97 PetscCheck(simCtx != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
98 "Block context must carry a simulation context.");
102 PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
103 "Field '%s' is component-staggered; its components live on different face "
104 "families and cannot share one pointwise target domain.",
108 owned_start[0] = info->xs; owned_end[0] = info->xs + info->xm; global_size[0] = info->mx;
109 owned_start[1] = info->ys; owned_end[1] = info->ys + info->ym; global_size[1] = info->my;
110 owned_start[2] = info->zs; owned_end[2] = info->zs + info->zm; global_size[2] = info->mz;
114 periodic[0] = (PetscBool)(simCtx->
i_periodic != 0);
115 periodic[1] = (PetscBool)(simCtx->
j_periodic != 0);
116 periodic[2] = (PetscBool)(simCtx->
k_periodic != 0);
122 for (PetscInt dim = 0; dim < 3; ++dim) {
123 PetscBool node_like = PETSC_FALSE;
124 PetscInt layout_lo = 0;
125 PetscInt layout_hi = 0;
128 ResolveLayoutSpan(node_like, periodic[dim], global_size[dim], &layout_lo, &layout_hi);
133 plan->
start[dim] = PetscMax(owned_start[dim], layout_lo);
134 plan->
end[dim] = PetscMin(owned_end[dim], layout_hi);
138 PetscFunctionReturn(0);
211 Vec numerator, Vec denominator, Vec inclusion,
212 const PetscBool average_direction[3], MPI_Comm comm,
213 Vec ratio, PetscReal *scalar)
217 PetscInt retained_extent[3];
218 PetscInt buffer_size = 1;
219 PetscInt averaged_count = 0;
220 PetscReal ***num = NULL, ***den = NULL, ***inc = NULL, ***out = NULL, ***nvert = NULL;
221 PetscReal *num_sum = NULL, *den_sum = NULL;
223 PetscFunctionBeginUser;
225 PetscCheck(user != NULL && plan != NULL && numerator != NULL && average_direction != NULL,
226 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
227 "Context, plan, numerator, and direction selector are required.");
230 PetscCall(DMDAGetLocalInfo(da, &info));
232 retained_extent[0] = average_direction[0] ? 1 : info.mx;
233 retained_extent[1] = average_direction[1] ? 1 : info.my;
234 retained_extent[2] = average_direction[2] ? 1 : info.mz;
235 for (PetscInt axis = 0; axis < 3; axis++) {
236 if (average_direction[axis]) averaged_count++;
237 buffer_size *= retained_extent[axis];
239 PetscCheck(scalar == NULL || averaged_count == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
240 "A single averaged value exists only when every direction is averaged over; "
241 "%" PetscInt_FMT
" of 3 were selected.", averaged_count);
243 PetscCall(DMDAVecGetArrayRead(da, numerator, &num));
244 if (denominator) PetscCall(DMDAVecGetArrayRead(da, denominator, &den));
245 if (inclusion) PetscCall(DMDAVecGetArrayRead(da, inclusion, &inc));
246 if (ratio) PetscCall(DMDAVecGetArray(da, ratio, &out));
247 PetscCall(DMDAVecGetArrayRead(da, user->
lNvert, &nvert));
249 if (averaged_count == 0) {
255 for (PetscInt k = plan->
start[2]; k < plan->
end[2]; k++)
256 for (PetscInt j = plan->
start[1]; j < plan->
end[1]; j++)
257 for (PetscInt i = plan->
start[0]; i < plan->
end[0]; i++) {
258 const PetscReal divisor = denominator ? den[k][j][i] : 1.0;
261 (inc && inc[k][j][i] <= 0.0)) {
265 out[k][j][i] = (PetscAbsReal(divisor) > 0.0) ? (num[k][j][i] / divisor) : 0.0;
269 PETSC_ERR_ARG_OUTOFRANGE,
270 "Averaging over %" PetscInt_FMT
" direction(s) would need a reduction buffer "
271 "of %" PetscInt_FMT
" entries, above the %d entry limit. Average over more "
274 PetscCall(PetscCalloc2(buffer_size, &num_sum, buffer_size, &den_sum));
276 for (PetscInt k = plan->
start[2]; k < plan->
end[2]; k++)
277 for (PetscInt j = plan->
start[1]; j < plan->
end[1]; j++)
278 for (PetscInt i = plan->
start[0]; i < plan->
end[0]; i++) {
284 if (inc && inc[k][j][i] <= 0.0)
continue;
287 num_sum[slot] += num[k][j][i];
288 den_sum[slot] += denominator ? den[k][j][i] : 1.0;
291 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, num_sum, (PetscMPIInt)buffer_size,
292 MPIU_REAL, MPI_SUM, comm));
293 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, den_sum, (PetscMPIInt)buffer_size,
294 MPIU_REAL, MPI_SUM, comm));
297 for (PetscInt k = plan->
start[2]; k < plan->
end[2]; k++)
298 for (PetscInt j = plan->
start[1]; j < plan->
end[1]; j++)
299 for (PetscInt i = plan->
start[0]; i < plan->
end[0]; i++) {
300 const PetscInt slot =
SpatialAverageSlot(average_direction, retained_extent, i, j, k);
302 out[k][j][i] = (PetscAbsReal(den_sum[slot]) > 0.0)
303 ? (num_sum[slot] / den_sum[slot]) : 0.0;
307 *scalar = (PetscAbsReal(den_sum[0]) > 0.0) ? (num_sum[0] / den_sum[0]) : 0.0;
310 PetscCall(PetscFree2(num_sum, den_sum));
313 PetscCall(DMDAVecRestoreArrayRead(da, numerator, &num));
314 if (denominator) PetscCall(DMDAVecRestoreArrayRead(da, denominator, &den));
315 if (inclusion) PetscCall(DMDAVecRestoreArrayRead(da, inclusion, &inc));
316 if (ratio) PetscCall(DMDAVecRestoreArray(da, ratio, &out));
317 PetscCall(DMDAVecRestoreArrayRead(da, user->
lNvert, &nvert));
320 PetscFunctionReturn(0);