xref: /honee/src/monitor_cfl.c (revision 5f46bb16c0b10bf7c44b7ec1cbefc5d9b473e8b6)
1 // SPDX-FileCopyrightText: Copyright (c) 2017-2024, HONEE contributors.
2 // SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause
3 
4 #include "../qfunctions/monitor_cfl.h"
5 #include <navierstokes.h>
6 
7 typedef struct {
8   OperatorApplyContext op_monitor_ctx;
9   Vec                  values;
10   PetscInt             num_comps;
11   PetscInt             tab_level;
12   PetscBool            is_header_written;
13 } *MonitorCflCtx;
14 
15 static PetscErrorCode MonitorCflCtxDestroy(MonitorCflCtx *monitor_ctx) {
16   MonitorCflCtx monitor_ctx_ = *monitor_ctx;
17 
18   PetscFunctionBeginUser;
19   PetscCall(OperatorApplyContextDestroy(monitor_ctx_->op_monitor_ctx));
20   PetscCall(VecDestroy(&monitor_ctx_->values));
21   PetscCall(PetscFree(monitor_ctx_));
22   *monitor_ctx = NULL;
23   PetscFunctionReturn(PETSC_SUCCESS);
24 }
25 
26 PetscErrorCode SetupMontiorCfl(TS ts, PetscViewerAndFormat *ctx) {
27   Honee                honee;
28   Ceed                 ceed;
29   CeedQFunction        qf_monitor = NULL;
30   CeedOperator         op_monitor;
31   CeedElemRestriction  elem_restr_qd, elem_restr_cfl, elem_restr_q;
32   CeedBasis            basis_q;
33   CeedVector           q_data;
34   CeedInt              num_comp_q, q_data_size;
35   DMLabel              domain_label = NULL;
36   PetscInt             label_value = 0, num_comp_cfl = 1, dim, tab_level;
37   MonitorCflCtx        monitor_ctx;
38   CeedQFunctionContext newt_qfctx;
39   PetscBool            is_ascii;
40 
41   PetscFunctionBeginUser;
42   PetscCall(PetscObjectTypeCompare((PetscObject)ctx->viewer, PETSCVIEWERASCII, &is_ascii));
43   PetscCheck(is_ascii, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Only supports ASCII viewers");
44   PetscCall(TSGetApplicationContext(ts, &honee));
45   PetscCall(DMGetDimension(honee->dm, &dim));
46   ceed = honee->ceed;
47 
48   PetscCall(PetscNew(&monitor_ctx));
49 
50   PetscCallCeed(ceed, CeedElemRestrictionGetNumComponents(honee->elem_restr_q, &num_comp_q));
51   PetscCall(QDataGet(ceed, honee->dm, domain_label, label_value, honee->elem_restr_x, honee->basis_x, honee->x_coord, &elem_restr_qd, &q_data,
52                      &q_data_size));
53   PetscCall(DMPlexCeedElemRestrictionQDataCreate(ceed, honee->dm, domain_label, label_value, 0, num_comp_cfl, &elem_restr_cfl));
54 
55   {  // Get restriction and basis from the RHS function
56     CeedOperator     *sub_ops, main_op = honee->op_ifunction ? honee->op_ifunction : honee->op_rhs_ctx->op;
57     CeedOperatorField op_field;
58     PetscInt          sub_op_index = 0;  // will be 0 for the volume op
59 
60     PetscCallCeed(ceed, CeedCompositeOperatorGetSubList(main_op, &sub_ops));
61     PetscCallCeed(ceed, CeedOperatorGetFieldByName(sub_ops[sub_op_index], "q", &op_field));
62 
63     PetscCallCeed(ceed, CeedOperatorFieldGetData(op_field, NULL, &elem_restr_q, &basis_q, NULL));
64     PetscCallCeed(ceed, CeedOperatorGetContext(sub_ops[sub_op_index], &newt_qfctx));
65   }
66 
67   switch (dim) {
68     case 2:
69       switch (honee->phys->state_var) {
70         case STATEVAR_PRIMITIVE:
71           PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, MonitorCFL_2D_Prim, MonitorCFL_2D_Prim_loc, &qf_monitor));
72           break;
73         case STATEVAR_CONSERVATIVE:
74           PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, MonitorCFL_2D_Conserv, MonitorCFL_2D_Conserv_loc, &qf_monitor));
75           break;
76         case STATEVAR_ENTROPY:
77           PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, MonitorCFL_2D_Entropy, MonitorCFL_2D_Entropy_loc, &qf_monitor));
78           break;
79       }
80       break;
81     case 3:
82       switch (honee->phys->state_var) {
83         case STATEVAR_PRIMITIVE:
84           PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, MonitorCFL_3D_Prim, MonitorCFL_3D_Prim_loc, &qf_monitor));
85           break;
86         case STATEVAR_CONSERVATIVE:
87           PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, MonitorCFL_3D_Conserv, MonitorCFL_3D_Conserv_loc, &qf_monitor));
88           break;
89         case STATEVAR_ENTROPY:
90           PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, MonitorCFL_3D_Entropy, MonitorCFL_3D_Entropy_loc, &qf_monitor));
91           break;
92       }
93       break;
94   }
95   PetscCheck(qf_monitor, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP,
96              "Could not create CFL monitor QFunction for dim %" PetscInt_FMT " and state variable %s", dim, StateVariables[honee->phys->state_var]);
97 
98   PetscBool is_advection;
99   PetscCall(PetscStrcmp("advection", honee->app_ctx->problem_name, &is_advection));
100   if (is_advection) {
101     NewtonianIdealGasContext newt_ctx;
102 
103     PetscCall(PetscNew(&newt_ctx));
104     PetscCallCeed(ceed, CeedQFunctionContextDestroy(&newt_qfctx));
105     PetscCallCeed(ceed, CeedQFunctionContextCreate(ceed, &newt_qfctx));
106     PetscCallCeed(ceed, CeedQFunctionContextSetData(newt_qfctx, CEED_MEM_HOST, CEED_USE_POINTER, sizeof(*newt_ctx), newt_ctx));
107     PetscCallCeed(ceed, CeedQFunctionContextSetDataDestroy(newt_qfctx, CEED_MEM_HOST, FreeContextPetsc));
108   }
109 
110   PetscCallCeed(ceed, CeedQFunctionSetContext(qf_monitor, newt_qfctx));
111   PetscCallCeed(ceed, CeedQFunctionAddInput(qf_monitor, "q", num_comp_q, CEED_EVAL_INTERP));
112   PetscCallCeed(ceed, CeedQFunctionAddInput(qf_monitor, "q_data", q_data_size, CEED_EVAL_NONE));
113   PetscCallCeed(ceed, CeedQFunctionAddOutput(qf_monitor, "v", num_comp_cfl, CEED_EVAL_NONE));
114 
115   PetscCallCeed(ceed, CeedOperatorCreate(ceed, qf_monitor, NULL, NULL, &op_monitor));
116   PetscCallCeed(ceed, CeedOperatorSetField(op_monitor, "q", elem_restr_q, basis_q, CEED_VECTOR_ACTIVE));
117   PetscCallCeed(ceed, CeedOperatorSetField(op_monitor, "q_data", elem_restr_qd, CEED_BASIS_NONE, q_data));
118   PetscCallCeed(ceed, CeedOperatorSetField(op_monitor, "v", elem_restr_cfl, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE));
119 
120   PetscCall(OperatorApplyContextCreate(honee->dm, NULL, ceed, op_monitor, NULL, NULL, NULL, NULL, &monitor_ctx->op_monitor_ctx));
121 
122   PetscCall(CeedOperatorCreateLocalVecs(op_monitor, DMReturnVecType(honee->dm), PETSC_COMM_SELF, NULL, &monitor_ctx->values));
123   PetscCall(VecSetBlockSize(monitor_ctx->values, num_comp_cfl));
124   monitor_ctx->num_comps = num_comp_cfl;
125   PetscCall(PetscObjectGetTabLevel((PetscObject)ts, &tab_level));
126   monitor_ctx->tab_level = tab_level + 1;
127 
128   ctx->data         = monitor_ctx;
129   ctx->data_destroy = (PetscCtxDestroyFn *)MonitorCflCtxDestroy;
130 
131   PetscCallCeed(ceed, CeedQFunctionContextDestroy(&newt_qfctx));
132   PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_qd));
133   PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_q));
134   PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_cfl));
135   PetscCallCeed(ceed, CeedBasisDestroy(&basis_q));
136   PetscCallCeed(ceed, CeedVectorDestroy(&q_data));
137   PetscCallCeed(ceed, CeedQFunctionDestroy(&qf_monitor));
138   PetscCallCeed(ceed, CeedOperatorDestroy(&op_monitor));
139   PetscFunctionReturn(PETSC_SUCCESS);
140 }
141 
142 PetscErrorCode TSMonitor_Cfl(TS ts, PetscInt step, PetscReal solution_time, Vec Q, PetscViewerAndFormat *ctx) {
143   MonitorCflCtx     monitor_ctx = (MonitorCflCtx)ctx->data;
144   Honee             honee;
145   MPI_Comm          comm;
146   TSConvergedReason reason;
147   PetscReal         part_minmax[2], global_minmax[2], dt;
148 
149   PetscFunctionBeginUser;
150   PetscCall(TSGetConvergedReason(ts, &reason));
151   if (!(step % ctx->view_interval == 0 || reason != TS_CONVERGED_ITERATING)) PetscFunctionReturn(PETSC_SUCCESS);
152   PetscCall(TSGetApplicationContext(ts, &honee));
153   PetscCall(PetscObjectGetComm((PetscObject)ts, &comm));
154 
155   PetscCall(UpdateBoundaryValues(honee, honee->Q_loc, solution_time));
156   PetscCall(DMGlobalToLocal(honee->dm, Q, INSERT_VALUES, honee->Q_loc));
157 
158   PetscCall(ApplyCeedOperatorLocalToLocal(honee->Q_loc, monitor_ctx->values, monitor_ctx->op_monitor_ctx));
159 
160   PetscCall(VecMin(monitor_ctx->values, NULL, &part_minmax[0]));
161   PetscCall(VecMax(monitor_ctx->values, NULL, &part_minmax[1]));
162   // Need to get global min/max since `values` is only the local partition
163   PetscCall(PetscGlobalMinMaxReal(comm, part_minmax, global_minmax));
164   PetscCall(TSGetTimeStep(ts, &dt));
165   global_minmax[0] *= dt;
166   global_minmax[1] *= dt;
167 
168   if (ctx->format == PETSC_VIEWER_ASCII_CSV) {
169     if (!monitor_ctx->is_header_written) {
170       char        buf[PETSC_MAX_PATH_LEN];
171       const char *buf_const;
172       time_t      t = time(NULL);
173 
174       PetscCall(PetscGetVersion(buf, sizeof(buf)));
175       PetscCall(PetscViewerASCIIPrintf(ctx->viewer, "# petsc_version: %s\n", buf));
176       PetscCall(PetscGetPetscDir(&buf_const));
177       PetscCall(PetscViewerASCIIPrintf(ctx->viewer, "# petsc_directory: %s\n", buf_const));
178       PetscCall(PetscGetArchType(buf, sizeof(buf)));
179       PetscCall(PetscViewerASCIIPrintf(ctx->viewer, "# petsc_arch: %s\n", buf));
180       if (strftime(buf, sizeof(buf), "%FT%T%z", localtime(&t)) == 0) SETERRQ(comm, PETSC_ERR_SYS, "strftime() call failed");
181       PetscCall(PetscViewerASCIIPrintf(ctx->viewer, "# date: %s\n", buf));
182       if (strftime(buf, sizeof(buf), "%Z", localtime(&t)) == 0) SETERRQ(comm, PETSC_ERR_SYS, "strftime() call failed");
183       PetscCall(PetscViewerASCIIPrintf(ctx->viewer, "# date_timezone: %s\n", buf));
184       PetscCall(PetscGetUserName(buf, sizeof(buf)));
185       PetscCall(PetscViewerASCIIPrintf(ctx->viewer, "# username: %s\n", buf));
186       PetscCall(PetscGetHostName(buf, sizeof(buf)));
187       PetscCall(PetscViewerASCIIPrintf(ctx->viewer, "# hostname: %s\n", buf));
188       PetscCall(PetscGetWorkingDirectory(buf, sizeof(buf)));
189       PetscCall(PetscViewerASCIIPrintf(ctx->viewer, "# working_directory: %s\n", buf));
190 
191       PetscCall(PetscViewerFileGetName(ctx->viewer, &buf_const));
192       PetscCall(PetscGetFullPath(buf_const, buf, sizeof(buf)));
193       PetscCall(PetscViewerASCIIPrintf(ctx->viewer, "# original_file_path: %s\n", buf));
194       PetscCall(PetscViewerASCIIPrintf(ctx->viewer, "#\n"));
195       PetscCall(PetscViewerASCIIPrintf(ctx->viewer, "step,time,mincfl,maxcfl\n"));
196       monitor_ctx->is_header_written = PETSC_TRUE;
197     }
198 
199     PetscCall(PetscViewerASCIIPrintf(ctx->viewer, "%" PetscInt_FMT ",%0.17e,", step, solution_time));
200     PetscCall(PetscViewerASCIIPrintf(ctx->viewer, "%0.17e,%0.17e", global_minmax[0], global_minmax[1]));
201     PetscCall(PetscViewerASCIIPrintf(ctx->viewer, "\n"));
202   } else {
203     PetscCall(PetscViewerASCIIAddTab(ctx->viewer, monitor_ctx->tab_level));
204     PetscCall(PetscViewerASCIIPrintf(ctx->viewer, "Min, Max CFL: %0.5g, %0.5g\n", global_minmax[0], global_minmax[1]));
205     PetscCall(PetscViewerASCIISubtractTab(ctx->viewer, monitor_ctx->tab_level));
206   }
207   PetscFunctionReturn(PETSC_SUCCESS);
208 }
209