xref: /libCEED/examples/fluids/src/misc.c (revision daadeac6547c0bce0e170b8a41c931051f52e9a3)
1 // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3 //
4 // SPDX-License-Identifier: BSD-2-Clause
5 //
6 // This file is part of CEED:  http://github.com/ceed
7 
8 /// @file
9 /// Miscellaneous utility functions
10 
11 #include "../navierstokes.h"
12 
13 PetscErrorCode ICs_FixMultiplicity(DM dm, CeedData ceed_data, User user, Vec Q_loc, Vec Q, CeedScalar time) {
14   PetscFunctionBeginUser;
15 
16   // ---------------------------------------------------------------------------
17   // Update time for evaluation
18   // ---------------------------------------------------------------------------
19   if (user->phys->ics_time_label) CeedOperatorContextSetDouble(ceed_data->op_ics, user->phys->ics_time_label, &time);
20 
21   // ---------------------------------------------------------------------------
22   // ICs
23   // ---------------------------------------------------------------------------
24   // -- CEED Restriction
25   CeedVector q0_ceed;
26   CeedElemRestrictionCreateVector(ceed_data->elem_restr_q, &q0_ceed, NULL);
27 
28   // -- Place PETSc vector in CEED vector
29   CeedScalar  *q0;
30   PetscMemType q0_mem_type;
31   PetscCall(VecGetArrayAndMemType(Q_loc, (PetscScalar **)&q0, &q0_mem_type));
32   CeedVectorSetArray(q0_ceed, MemTypeP2C(q0_mem_type), CEED_USE_POINTER, q0);
33 
34   // -- Apply CEED Operator
35   CeedOperatorApply(ceed_data->op_ics, ceed_data->x_coord, q0_ceed, CEED_REQUEST_IMMEDIATE);
36 
37   // -- Restore vectors
38   CeedVectorTakeArray(q0_ceed, MemTypeP2C(q0_mem_type), NULL);
39   PetscCall(VecRestoreArrayReadAndMemType(Q_loc, (const PetscScalar **)&q0));
40 
41   // -- Local-to-Global
42   PetscCall(VecZeroEntries(Q));
43   PetscCall(DMLocalToGlobal(dm, Q_loc, ADD_VALUES, Q));
44 
45   // ---------------------------------------------------------------------------
46   // Fix multiplicity for output of ICs
47   // ---------------------------------------------------------------------------
48   // -- CEED Restriction
49   CeedVector mult_vec;
50   CeedElemRestrictionCreateVector(ceed_data->elem_restr_q, &mult_vec, NULL);
51 
52   // -- Place PETSc vector in CEED vector
53   CeedScalar  *mult;
54   PetscMemType m_mem_type;
55   Vec          multiplicity_loc;
56   PetscCall(DMGetLocalVector(dm, &multiplicity_loc));
57   PetscCall(VecGetArrayAndMemType(multiplicity_loc, (PetscScalar **)&mult, &m_mem_type));
58   CeedVectorSetArray(mult_vec, MemTypeP2C(m_mem_type), CEED_USE_POINTER, mult);
59 
60   // -- Get multiplicity
61   CeedElemRestrictionGetMultiplicity(ceed_data->elem_restr_q, mult_vec);
62 
63   // -- Restore vectors
64   CeedVectorTakeArray(mult_vec, MemTypeP2C(m_mem_type), NULL);
65   PetscCall(VecRestoreArrayReadAndMemType(multiplicity_loc, (const PetscScalar **)&mult));
66 
67   // -- Local-to-Global
68   Vec multiplicity;
69   PetscCall(DMGetGlobalVector(dm, &multiplicity));
70   PetscCall(VecZeroEntries(multiplicity));
71   PetscCall(DMLocalToGlobal(dm, multiplicity_loc, ADD_VALUES, multiplicity));
72 
73   // -- Fix multiplicity
74   PetscCall(VecPointwiseDivide(Q, Q, multiplicity));
75   PetscCall(VecPointwiseDivide(Q_loc, Q_loc, multiplicity_loc));
76 
77   // -- Restore vectors
78   PetscCall(DMRestoreLocalVector(dm, &multiplicity_loc));
79   PetscCall(DMRestoreGlobalVector(dm, &multiplicity));
80 
81   // Cleanup
82   CeedVectorDestroy(&mult_vec);
83   CeedVectorDestroy(&q0_ceed);
84 
85   PetscFunctionReturn(0);
86 }
87 
88 PetscErrorCode DMPlexInsertBoundaryValues_NS(DM dm, PetscBool insert_essential, Vec Q_loc, PetscReal time, Vec face_geom_FVM, Vec cell_geom_FVM,
89                                              Vec grad_FVM) {
90   Vec Qbc, boundary_mask;
91   PetscFunctionBegin;
92 
93   // Mask (zero) Dirichlet entries
94   PetscCall(DMGetNamedLocalVector(dm, "boundary mask", &boundary_mask));
95   PetscCall(VecPointwiseMult(Q_loc, Q_loc, boundary_mask));
96   PetscCall(DMRestoreNamedLocalVector(dm, "boundary mask", &boundary_mask));
97 
98   PetscCall(DMGetNamedLocalVector(dm, "Qbc", &Qbc));
99   PetscCall(VecAXPY(Q_loc, 1., Qbc));
100   PetscCall(DMRestoreNamedLocalVector(dm, "Qbc", &Qbc));
101 
102   PetscFunctionReturn(0);
103 }
104 
105 // Compare reference solution values with current test run for CI
106 PetscErrorCode RegressionTests_NS(AppCtx app_ctx, Vec Q) {
107   Vec         Qref;
108   PetscViewer viewer;
109   PetscReal   error, Qrefnorm;
110   PetscFunctionBegin;
111 
112   // Read reference file
113   PetscCall(VecDuplicate(Q, &Qref));
114   PetscCall(PetscViewerBinaryOpen(PetscObjectComm((PetscObject)Q), app_ctx->file_path, FILE_MODE_READ, &viewer));
115   PetscCall(VecLoad(Qref, viewer));
116 
117   // Compute error with respect to reference solution
118   PetscCall(VecAXPY(Q, -1.0, Qref));
119   PetscCall(VecNorm(Qref, NORM_MAX, &Qrefnorm));
120   PetscCall(VecScale(Q, 1. / Qrefnorm));
121   PetscCall(VecNorm(Q, NORM_MAX, &error));
122 
123   // Check error
124   if (error > app_ctx->test_tol) {
125     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test failed with error norm %g\n", (double)error));
126   }
127 
128   // Cleanup
129   PetscCall(PetscViewerDestroy(&viewer));
130   PetscCall(VecDestroy(&Qref));
131 
132   PetscFunctionReturn(0);
133 }
134 
135 // Get error for problems with exact solutions
136 PetscErrorCode GetError_NS(CeedData ceed_data, DM dm, User user, Vec Q, PetscScalar final_time) {
137   PetscInt  loc_nodes;
138   Vec       Q_exact, Q_exact_loc;
139   PetscReal rel_error, norm_error, norm_exact;
140   PetscFunctionBegin;
141 
142   // Get exact solution at final time
143   PetscCall(DMCreateGlobalVector(dm, &Q_exact));
144   PetscCall(DMGetLocalVector(dm, &Q_exact_loc));
145   PetscCall(VecGetSize(Q_exact_loc, &loc_nodes));
146   PetscCall(ICs_FixMultiplicity(dm, ceed_data, user, Q_exact_loc, Q_exact, final_time));
147 
148   // Get |exact solution - obtained solution|
149   PetscCall(VecNorm(Q_exact, NORM_1, &norm_exact));
150   PetscCall(VecAXPY(Q, -1.0, Q_exact));
151   PetscCall(VecNorm(Q, NORM_1, &norm_error));
152 
153   // Compute relative error
154   rel_error = norm_error / norm_exact;
155 
156   // Output relative error
157   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Relative Error: %g\n", (double)rel_error));
158   // Cleanup
159   PetscCall(DMRestoreLocalVector(dm, &Q_exact_loc));
160   PetscCall(VecDestroy(&Q_exact));
161 
162   PetscFunctionReturn(0);
163 }
164 
165 // Post-processing
166 PetscErrorCode PostProcess_NS(TS ts, CeedData ceed_data, DM dm, ProblemData *problem, User user, Vec Q, PetscScalar final_time) {
167   PetscInt steps;
168   PetscFunctionBegin;
169 
170   // Print relative error
171   if (problem->non_zero_time && !user->app_ctx->test_mode) {
172     PetscCall(GetError_NS(ceed_data, dm, user, Q, final_time));
173   }
174 
175   // Print final time and number of steps
176   PetscCall(TSGetStepNumber(ts, &steps));
177   if (!user->app_ctx->test_mode) {
178     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Time integrator took %" PetscInt_FMT " time steps to reach final time %g\n", steps, (double)final_time));
179   }
180 
181   // Output numerical values from command line
182   PetscCall(VecViewFromOptions(Q, NULL, "-vec_view"));
183 
184   // Compare reference solution values with current test run for CI
185   if (user->app_ctx->test_mode) {
186     PetscCall(RegressionTests_NS(user->app_ctx, Q));
187   }
188 
189   PetscFunctionReturn(0);
190 }
191 
192 // Gather initial Q values in case of continuation of simulation
193 PetscErrorCode SetupICsFromBinary(MPI_Comm comm, AppCtx app_ctx, Vec Q) {
194   PetscViewer viewer;
195 
196   PetscFunctionBegin;
197 
198   // Read input
199   PetscCall(PetscViewerBinaryOpen(comm, app_ctx->cont_file, FILE_MODE_READ, &viewer));
200 
201   // Load Q from existent solution
202   PetscCall(VecLoad(Q, viewer));
203 
204   // Cleanup
205   PetscCall(PetscViewerDestroy(&viewer));
206 
207   PetscFunctionReturn(0);
208 }
209 
210 // Record boundary values from initial condition
211 PetscErrorCode SetBCsFromICs_NS(DM dm, Vec Q, Vec Q_loc) {
212   Vec Qbc, boundary_mask;
213   PetscFunctionBegin;
214 
215   PetscCall(DMGetNamedLocalVector(dm, "Qbc", &Qbc));
216   PetscCall(VecCopy(Q_loc, Qbc));
217   PetscCall(VecZeroEntries(Q_loc));
218   PetscCall(DMGlobalToLocal(dm, Q, INSERT_VALUES, Q_loc));
219   PetscCall(VecAXPY(Qbc, -1., Q_loc));
220   PetscCall(DMRestoreNamedLocalVector(dm, "Qbc", &Qbc));
221   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", DMPlexInsertBoundaryValues_NS));
222 
223   PetscCall(DMGetNamedLocalVector(dm, "boundary mask", &boundary_mask));
224   PetscCall(DMGetGlobalVector(dm, &Q));
225   PetscCall(VecZeroEntries(boundary_mask));
226   PetscCall(VecSet(Q, 1.0));
227   PetscCall(DMGlobalToLocal(dm, Q, INSERT_VALUES, boundary_mask));
228   PetscCall(DMRestoreNamedLocalVector(dm, "boundary mask", &boundary_mask));
229 
230   PetscFunctionReturn(0);
231 }
232 
233 // Free a plain data context that was allocated using PETSc; returning libCEED error codes
234 int FreeContextPetsc(void *data) {
235   if (PetscFree(data)) return CeedError(NULL, CEED_ERROR_ACCESS, "PetscFree failed");
236   return CEED_ERROR_SUCCESS;
237 }
238