xref: /libCEED/examples/solids/src/misc.c (revision 2b730f8b5a9c809740a0b3b302db43a719c636b1)
13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
33d8e8822SJeremy L Thompson //
43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
53d8e8822SJeremy L Thompson //
63d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
73d8e8822SJeremy L Thompson 
8ccaff030SJeremy L Thompson /// @file
9ccaff030SJeremy L Thompson /// Helper functions for solid mechanics example using PETSc
10ccaff030SJeremy L Thompson 
115754ecacSJeremy L Thompson #include "../include/misc.h"
12*2b730f8bSJeremy L Thompson 
135754ecacSJeremy L Thompson #include "../include/utils.h"
14ccaff030SJeremy L Thompson 
15ccaff030SJeremy L Thompson // -----------------------------------------------------------------------------
16ccaff030SJeremy L Thompson // Create libCEED operator context
17ccaff030SJeremy L Thompson // -----------------------------------------------------------------------------
18ccaff030SJeremy L Thompson // Setup context data for Jacobian evaluation
19*2b730f8bSJeremy L Thompson PetscErrorCode SetupJacobianCtx(MPI_Comm comm, AppCtx app_ctx, DM dm, Vec V, Vec V_loc, CeedData ceed_data, Ceed ceed, CeedQFunctionContext ctx_phys,
20*2b730f8bSJeremy L Thompson                                 CeedQFunctionContext ctx_phys_smoother, UserMult jacobian_ctx) {
21ccaff030SJeremy L Thompson   PetscFunctionBeginUser;
22ccaff030SJeremy L Thompson 
23ccaff030SJeremy L Thompson   // PETSc objects
24d1d35e2fSjeremylt   jacobian_ctx->comm = comm;
25d1d35e2fSjeremylt   jacobian_ctx->dm   = dm;
26ccaff030SJeremy L Thompson 
27ccaff030SJeremy L Thompson   // Work vectors
28d1d35e2fSjeremylt   jacobian_ctx->X_loc = V_loc;
29*2b730f8bSJeremy L Thompson   PetscCall(VecDuplicate(V_loc, &jacobian_ctx->Y_loc));
30d1d35e2fSjeremylt   jacobian_ctx->x_ceed = ceed_data->x_ceed;
31d1d35e2fSjeremylt   jacobian_ctx->y_ceed = ceed_data->y_ceed;
32ccaff030SJeremy L Thompson 
33ccaff030SJeremy L Thompson   // libCEED operator
345754ecacSJeremy L Thompson   jacobian_ctx->op = ceed_data->op_jacobian;
355754ecacSJeremy L Thompson   jacobian_ctx->qf = ceed_data->qf_jacobian;
36ccaff030SJeremy L Thompson 
37ccaff030SJeremy L Thompson   // Ceed
38d1d35e2fSjeremylt   jacobian_ctx->ceed = ceed;
39ccaff030SJeremy L Thompson 
40f7b4142eSJeremy L Thompson   // Physics
41d1d35e2fSjeremylt   jacobian_ctx->ctx_phys          = ctx_phys;
42d1d35e2fSjeremylt   jacobian_ctx->ctx_phys_smoother = ctx_phys_smoother;
43ccaff030SJeremy L Thompson   PetscFunctionReturn(0);
44ccaff030SJeremy L Thompson };
45ccaff030SJeremy L Thompson 
46ccaff030SJeremy L Thompson // Setup context data for prolongation and restriction operators
47*2b730f8bSJeremy L Thompson PetscErrorCode SetupProlongRestrictCtx(MPI_Comm comm, AppCtx app_ctx, DM dm_c, DM dm_f, Vec V_f, Vec V_loc_c, Vec V_loc_f, CeedData ceed_data_c,
48*2b730f8bSJeremy L Thompson                                        CeedData ceed_data_f, Ceed ceed, UserMultProlongRestr prolong_restr_ctx) {
49ccaff030SJeremy L Thompson   PetscFunctionBeginUser;
50ccaff030SJeremy L Thompson 
51ccaff030SJeremy L Thompson   // PETSc objects
52d1d35e2fSjeremylt   prolong_restr_ctx->comm = comm;
53d1d35e2fSjeremylt   prolong_restr_ctx->dm_c = dm_c;
54d1d35e2fSjeremylt   prolong_restr_ctx->dm_f = dm_f;
55ccaff030SJeremy L Thompson 
56ccaff030SJeremy L Thompson   // Work vectors
57d1d35e2fSjeremylt   prolong_restr_ctx->loc_vec_c  = V_loc_c;
58d1d35e2fSjeremylt   prolong_restr_ctx->loc_vec_f  = V_loc_f;
59d1d35e2fSjeremylt   prolong_restr_ctx->ceed_vec_c = ceed_data_c->x_ceed;
60d1d35e2fSjeremylt   prolong_restr_ctx->ceed_vec_f = ceed_data_f->x_ceed;
61ccaff030SJeremy L Thompson 
62ccaff030SJeremy L Thompson   // libCEED operators
63d1d35e2fSjeremylt   prolong_restr_ctx->op_prolong  = ceed_data_f->op_prolong;
64d1d35e2fSjeremylt   prolong_restr_ctx->op_restrict = ceed_data_f->op_restrict;
65ccaff030SJeremy L Thompson 
66ccaff030SJeremy L Thompson   // Ceed
67d1d35e2fSjeremylt   prolong_restr_ctx->ceed = ceed;
68ccaff030SJeremy L Thompson   PetscFunctionReturn(0);
69ccaff030SJeremy L Thompson };
70ccaff030SJeremy L Thompson 
71ccaff030SJeremy L Thompson // -----------------------------------------------------------------------------
72ccaff030SJeremy L Thompson // Jacobian setup
73ccaff030SJeremy L Thompson // -----------------------------------------------------------------------------
74d1d35e2fSjeremylt PetscErrorCode FormJacobian(SNES snes, Vec U, Mat J, Mat J_pre, void *ctx) {
75ccaff030SJeremy L Thompson   PetscFunctionBeginUser;
76ccaff030SJeremy L Thompson 
77ccaff030SJeremy L Thompson   // Context data
78d1d35e2fSjeremylt   FormJacobCtx form_jacob_ctx = (FormJacobCtx)ctx;
79d1d35e2fSjeremylt   PetscInt     num_levels     = form_jacob_ctx->num_levels;
80d1d35e2fSjeremylt   Mat         *jacob_mat      = form_jacob_ctx->jacob_mat;
81ccaff030SJeremy L Thompson 
82e3e3df41Sjeremylt   // Update Jacobian on each level
83d1d35e2fSjeremylt   for (PetscInt level = 0; level < num_levels; level++) {
84*2b730f8bSJeremy L Thompson     PetscCall(MatAssemblyBegin(jacob_mat[level], MAT_FINAL_ASSEMBLY));
85*2b730f8bSJeremy L Thompson     PetscCall(MatAssemblyEnd(jacob_mat[level], MAT_FINAL_ASSEMBLY));
86ccaff030SJeremy L Thompson   }
87ccaff030SJeremy L Thompson 
88ccaff030SJeremy L Thompson   // Form coarse assembled matrix
89*2b730f8bSJeremy L Thompson   CeedOperatorLinearAssemble(form_jacob_ctx->op_coarse, form_jacob_ctx->coo_values);
9017f0843fSJeremy L Thompson   const CeedScalar *values;
9117f0843fSJeremy L Thompson   CeedVectorGetArrayRead(form_jacob_ctx->coo_values, CEED_MEM_HOST, &values);
92*2b730f8bSJeremy L Thompson   PetscCall(MatSetValuesCOO(form_jacob_ctx->jacob_mat_coarse, values, ADD_VALUES));
9317f0843fSJeremy L Thompson   CeedVectorRestoreArrayRead(form_jacob_ctx->coo_values, &values);
94ccaff030SJeremy L Thompson 
95d1d35e2fSjeremylt   // J_pre might be AIJ (e.g., when using coloring), so we need to assemble it
96*2b730f8bSJeremy L Thompson   PetscCall(MatAssemblyBegin(J_pre, MAT_FINAL_ASSEMBLY));
97*2b730f8bSJeremy L Thompson   PetscCall(MatAssemblyEnd(J_pre, MAT_FINAL_ASSEMBLY));
98d1d35e2fSjeremylt   if (J != J_pre) {
99*2b730f8bSJeremy L Thompson     PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
100*2b730f8bSJeremy L Thompson     PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
1010e0d204cSJed Brown   }
102ccaff030SJeremy L Thompson   PetscFunctionReturn(0);
103ccaff030SJeremy L Thompson };
104ccaff030SJeremy L Thompson 
105ccaff030SJeremy L Thompson // -----------------------------------------------------------------------------
106ccaff030SJeremy L Thompson // Output solution for visualization
107ccaff030SJeremy L Thompson // -----------------------------------------------------------------------------
108*2b730f8bSJeremy L Thompson PetscErrorCode ViewSolution(MPI_Comm comm, AppCtx app_ctx, Vec U, PetscInt increment, PetscScalar load_increment) {
109ccaff030SJeremy L Thompson   DM          dm;
110ccaff030SJeremy L Thompson   PetscViewer viewer;
111d1d35e2fSjeremylt   char        output_filename[PETSC_MAX_PATH_LEN];
112d99129b9SLeila Ghaffari   PetscMPIInt rank;
113ccaff030SJeremy L Thompson 
114ccaff030SJeremy L Thompson   PetscFunctionBeginUser;
115ccaff030SJeremy L Thompson 
116d99129b9SLeila Ghaffari   // Create output directory
117d99129b9SLeila Ghaffari   MPI_Comm_rank(comm, &rank);
118*2b730f8bSJeremy L Thompson   if (!rank) {
119*2b730f8bSJeremy L Thompson     PetscCall(PetscMkdir(app_ctx->output_dir));
120*2b730f8bSJeremy L Thompson   }
121d99129b9SLeila Ghaffari 
122ccaff030SJeremy L Thompson   // Build file name
123*2b730f8bSJeremy L Thompson   PetscCall(PetscSNPrintf(output_filename, sizeof output_filename, "%s/solution-%03" PetscInt_FMT ".vtu", app_ctx->output_dir, increment));
124ccaff030SJeremy L Thompson 
125050e48ebSJeremy L Thompson   // Increment sequence
126*2b730f8bSJeremy L Thompson   PetscCall(VecGetDM(U, &dm));
127*2b730f8bSJeremy L Thompson   PetscCall(DMSetOutputSequenceNumber(dm, increment, load_increment));
128ccaff030SJeremy L Thompson 
129ccaff030SJeremy L Thompson   // Output solution vector
130*2b730f8bSJeremy L Thompson   PetscCall(PetscViewerVTKOpen(comm, output_filename, FILE_MODE_WRITE, &viewer));
131*2b730f8bSJeremy L Thompson   PetscCall(VecView(U, viewer));
132*2b730f8bSJeremy L Thompson   PetscCall(PetscViewerDestroy(&viewer));
133ccaff030SJeremy L Thompson 
134ccaff030SJeremy L Thompson   PetscFunctionReturn(0);
135ccaff030SJeremy L Thompson };
1365c25879aSJeremy L Thompson 
1375c25879aSJeremy L Thompson // -----------------------------------------------------------------------------
1385c25879aSJeremy L Thompson // Output diagnostic quantities for visualization
1395c25879aSJeremy L Thompson // -----------------------------------------------------------------------------
140*2b730f8bSJeremy L Thompson PetscErrorCode ViewDiagnosticQuantities(MPI_Comm comm, DM dmU, UserMult user, AppCtx app_ctx, Vec U, CeedElemRestriction elem_restr_diagnostic) {
141d1d35e2fSjeremylt   Vec          Diagnostic, Y_loc, mult_vec;
142d1d35e2fSjeremylt   CeedVector   y_ceed;
1435c25879aSJeremy L Thompson   CeedScalar  *x, *y;
144d1d35e2fSjeremylt   PetscMemType x_mem_type, y_mem_type;
145d1d35e2fSjeremylt   PetscInt     loc_size;
1465c25879aSJeremy L Thompson   PetscViewer  viewer;
147d1d35e2fSjeremylt   char         output_filename[PETSC_MAX_PATH_LEN];
1485c25879aSJeremy L Thompson 
1495c25879aSJeremy L Thompson   PetscFunctionBeginUser;
1505c25879aSJeremy L Thompson 
1515c25879aSJeremy L Thompson   // ---------------------------------------------------------------------------
1525c25879aSJeremy L Thompson   // PETSc and libCEED vectors
1535c25879aSJeremy L Thompson   // ---------------------------------------------------------------------------
154*2b730f8bSJeremy L Thompson   PetscCall(DMCreateGlobalVector(user->dm, &Diagnostic));
155*2b730f8bSJeremy L Thompson   PetscCall(PetscObjectSetName((PetscObject)Diagnostic, ""));
156*2b730f8bSJeremy L Thompson   PetscCall(DMCreateLocalVector(user->dm, &Y_loc));
157*2b730f8bSJeremy L Thompson   PetscCall(VecGetSize(Y_loc, &loc_size));
158d1d35e2fSjeremylt   CeedVectorCreate(user->ceed, loc_size, &y_ceed);
1595c25879aSJeremy L Thompson 
1605c25879aSJeremy L Thompson   // ---------------------------------------------------------------------------
1615c25879aSJeremy L Thompson   // Compute quantities
1625c25879aSJeremy L Thompson   // ---------------------------------------------------------------------------
1635c25879aSJeremy L Thompson   // -- Global-to-local
164*2b730f8bSJeremy L Thompson   PetscCall(VecZeroEntries(user->X_loc));
165*2b730f8bSJeremy L Thompson   PetscCall(DMPlexInsertBoundaryValues(dmU, PETSC_TRUE, user->X_loc, user->load_increment, NULL, NULL, NULL));
166*2b730f8bSJeremy L Thompson   PetscCall(DMGlobalToLocal(dmU, U, INSERT_VALUES, user->X_loc));
167*2b730f8bSJeremy L Thompson   PetscCall(VecZeroEntries(Y_loc));
1685c25879aSJeremy L Thompson 
1695c25879aSJeremy L Thompson   // -- Setup CEED vectors
170*2b730f8bSJeremy L Thompson   PetscCall(VecGetArrayReadAndMemType(user->X_loc, (const PetscScalar **)&x, &x_mem_type));
171*2b730f8bSJeremy L Thompson   PetscCall(VecGetArrayAndMemType(Y_loc, &y, &y_mem_type));
172d1d35e2fSjeremylt   CeedVectorSetArray(user->x_ceed, MemTypeP2C(x_mem_type), CEED_USE_POINTER, x);
173d1d35e2fSjeremylt   CeedVectorSetArray(y_ceed, MemTypeP2C(y_mem_type), CEED_USE_POINTER, y);
1745c25879aSJeremy L Thompson 
1755c25879aSJeremy L Thompson   // -- Apply CEED operator
176d1d35e2fSjeremylt   CeedOperatorApply(user->op, user->x_ceed, y_ceed, CEED_REQUEST_IMMEDIATE);
1775c25879aSJeremy L Thompson 
178d1d35e2fSjeremylt   // -- Restore PETSc vector; keep y_ceed viewing memory of Y_loc for use below
179d1d35e2fSjeremylt   CeedVectorTakeArray(user->x_ceed, MemTypeP2C(x_mem_type), NULL);
180*2b730f8bSJeremy L Thompson   PetscCall(VecRestoreArrayReadAndMemType(user->X_loc, (const PetscScalar **)&x));
1815c25879aSJeremy L Thompson 
1825c25879aSJeremy L Thompson   // -- Local-to-global
183*2b730f8bSJeremy L Thompson   PetscCall(VecZeroEntries(Diagnostic));
184*2b730f8bSJeremy L Thompson   PetscCall(DMLocalToGlobal(user->dm, Y_loc, ADD_VALUES, Diagnostic));
1855c25879aSJeremy L Thompson 
1865c25879aSJeremy L Thompson   // ---------------------------------------------------------------------------
1875c25879aSJeremy L Thompson   // Scale for multiplicity
1885c25879aSJeremy L Thompson   // ---------------------------------------------------------------------------
1895c25879aSJeremy L Thompson   // -- Setup vectors
190*2b730f8bSJeremy L Thompson   PetscCall(VecDuplicate(Diagnostic, &mult_vec));
191*2b730f8bSJeremy L Thompson   PetscCall(VecZeroEntries(Y_loc));
1925c25879aSJeremy L Thompson 
1935c25879aSJeremy L Thompson   // -- Compute multiplicity
194d1d35e2fSjeremylt   CeedElemRestrictionGetMultiplicity(elem_restr_diagnostic, y_ceed);
1955c25879aSJeremy L Thompson 
1965c25879aSJeremy L Thompson   // -- Restore vectors
197d1d35e2fSjeremylt   CeedVectorTakeArray(y_ceed, MemTypeP2C(y_mem_type), NULL);
198*2b730f8bSJeremy L Thompson   PetscCall(VecRestoreArrayAndMemType(Y_loc, &y));
1995c25879aSJeremy L Thompson 
2005c25879aSJeremy L Thompson   // -- Local-to-global
201*2b730f8bSJeremy L Thompson   PetscCall(VecZeroEntries(mult_vec));
202*2b730f8bSJeremy L Thompson   PetscCall(DMLocalToGlobal(user->dm, Y_loc, ADD_VALUES, mult_vec));
2035c25879aSJeremy L Thompson 
2045c25879aSJeremy L Thompson   // -- Scale
205*2b730f8bSJeremy L Thompson   PetscCall(VecReciprocal(mult_vec));
206*2b730f8bSJeremy L Thompson   PetscCall(VecPointwiseMult(Diagnostic, Diagnostic, mult_vec));
2075c25879aSJeremy L Thompson 
2085c25879aSJeremy L Thompson   // ---------------------------------------------------------------------------
2095c25879aSJeremy L Thompson   // Output solution vector
2105c25879aSJeremy L Thompson   // ---------------------------------------------------------------------------
211*2b730f8bSJeremy L Thompson   PetscCall(PetscSNPrintf(output_filename, sizeof output_filename, "%s/diagnostic_quantities.vtu", app_ctx->output_dir));
212*2b730f8bSJeremy L Thompson   PetscCall(PetscViewerVTKOpen(comm, output_filename, FILE_MODE_WRITE, &viewer));
213*2b730f8bSJeremy L Thompson   PetscCall(VecView(Diagnostic, viewer));
214*2b730f8bSJeremy L Thompson   PetscCall(PetscViewerDestroy(&viewer));
2155c25879aSJeremy L Thompson 
2165c25879aSJeremy L Thompson   // ---------------------------------------------------------------------------
2175c25879aSJeremy L Thompson   // Cleanup
2185c25879aSJeremy L Thompson   // ---------------------------------------------------------------------------
219*2b730f8bSJeremy L Thompson   PetscCall(VecDestroy(&Diagnostic));
220*2b730f8bSJeremy L Thompson   PetscCall(VecDestroy(&mult_vec));
221*2b730f8bSJeremy L Thompson   PetscCall(VecDestroy(&Y_loc));
222d1d35e2fSjeremylt   CeedVectorDestroy(&y_ceed);
2235c25879aSJeremy L Thompson 
2245c25879aSJeremy L Thompson   PetscFunctionReturn(0);
2255c25879aSJeremy L Thompson };
2265754ecacSJeremy L Thompson 
2275754ecacSJeremy L Thompson // -----------------------------------------------------------------------------
2285754ecacSJeremy L Thompson // Regression testing
2295754ecacSJeremy L Thompson // -----------------------------------------------------------------------------
2305754ecacSJeremy L Thompson // test option change. could remove the loading step. Run only with one loading step and compare relatively to ref file
231*2b730f8bSJeremy L Thompson // option: expect_final_strain_energy and check against the relative error to ref is within tolerance (10^-5) I.e. one Newton solve then check final
232*2b730f8bSJeremy L Thompson // energy
2335754ecacSJeremy L Thompson PetscErrorCode RegressionTests_solids(AppCtx app_ctx, PetscReal energy) {
2345754ecacSJeremy L Thompson   PetscFunctionBegin;
2355754ecacSJeremy L Thompson 
2365754ecacSJeremy L Thompson   if (app_ctx->expect_final_strain >= 0.) {
2375754ecacSJeremy L Thompson     PetscReal energy_ref = app_ctx->expect_final_strain;
2385754ecacSJeremy L Thompson     PetscReal error      = PetscAbsReal(energy - energy_ref) / energy_ref;
2395754ecacSJeremy L Thompson 
2405754ecacSJeremy L Thompson     if (error > app_ctx->test_tol) {
241*2b730f8bSJeremy L Thompson       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Energy %e does not match expected energy %e: relative tolerance %e > %e\n", (double)energy,
242*2b730f8bSJeremy L Thompson                             (double)energy_ref, (double)error, app_ctx->test_tol));
2435754ecacSJeremy L Thompson     }
2445754ecacSJeremy L Thompson   }
2455754ecacSJeremy L Thompson   PetscFunctionReturn(0);
2465754ecacSJeremy L Thompson };
247