1*9ba83ac0SJeremy L Thompson // Copyright (c) 2017-2026, 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"
122b730f8bSJeremy L Thompson
1349aac155SJeremy L Thompson #include <ceed.h>
1449aac155SJeremy L Thompson #include <petscdmplex.h>
1549aac155SJeremy L Thompson #include <petscmat.h>
1649aac155SJeremy L Thompson
175754ecacSJeremy L Thompson #include "../include/utils.h"
18ccaff030SJeremy L Thompson
19ccaff030SJeremy L Thompson // -----------------------------------------------------------------------------
20ccaff030SJeremy L Thompson // Create libCEED operator context
21ccaff030SJeremy L Thompson // -----------------------------------------------------------------------------
22ccaff030SJeremy L Thompson // Setup context data for Jacobian evaluation
SetupJacobianCtx(MPI_Comm comm,AppCtx app_ctx,DM dm,Vec V,Vec V_loc,CeedData ceed_data,Ceed ceed,CeedQFunctionContext ctx_phys,CeedQFunctionContext ctx_phys_smoother,UserMult jacobian_ctx)232b730f8bSJeremy 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,
242b730f8bSJeremy L Thompson CeedQFunctionContext ctx_phys_smoother, UserMult jacobian_ctx) {
25ccaff030SJeremy L Thompson PetscFunctionBeginUser;
26ccaff030SJeremy L Thompson
27ccaff030SJeremy L Thompson // PETSc objects
28d1d35e2fSjeremylt jacobian_ctx->comm = comm;
29d1d35e2fSjeremylt jacobian_ctx->dm = dm;
30ccaff030SJeremy L Thompson
31ccaff030SJeremy L Thompson // Work vectors
32d1d35e2fSjeremylt jacobian_ctx->X_loc = V_loc;
332b730f8bSJeremy L Thompson PetscCall(VecDuplicate(V_loc, &jacobian_ctx->Y_loc));
34d1d35e2fSjeremylt jacobian_ctx->x_ceed = ceed_data->x_ceed;
35d1d35e2fSjeremylt jacobian_ctx->y_ceed = ceed_data->y_ceed;
36ccaff030SJeremy L Thompson
37ccaff030SJeremy L Thompson // libCEED operator
385754ecacSJeremy L Thompson jacobian_ctx->op = ceed_data->op_jacobian;
395754ecacSJeremy L Thompson jacobian_ctx->qf = ceed_data->qf_jacobian;
40ccaff030SJeremy L Thompson
41ccaff030SJeremy L Thompson // Ceed
42d1d35e2fSjeremylt jacobian_ctx->ceed = ceed;
43ccaff030SJeremy L Thompson
44f7b4142eSJeremy L Thompson // Physics
45d1d35e2fSjeremylt jacobian_ctx->ctx_phys = ctx_phys;
46d1d35e2fSjeremylt jacobian_ctx->ctx_phys_smoother = ctx_phys_smoother;
47ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS);
48ccaff030SJeremy L Thompson };
49ccaff030SJeremy L Thompson
50ccaff030SJeremy L Thompson // Setup context data for prolongation and restriction operators
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,CeedData ceed_data_f,Ceed ceed,UserMultProlongRestr prolong_restr_ctx)512b730f8bSJeremy 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,
522b730f8bSJeremy L Thompson CeedData ceed_data_f, Ceed ceed, UserMultProlongRestr prolong_restr_ctx) {
53ccaff030SJeremy L Thompson PetscFunctionBeginUser;
54ccaff030SJeremy L Thompson
55ccaff030SJeremy L Thompson // PETSc objects
56d1d35e2fSjeremylt prolong_restr_ctx->comm = comm;
57d1d35e2fSjeremylt prolong_restr_ctx->dm_c = dm_c;
58d1d35e2fSjeremylt prolong_restr_ctx->dm_f = dm_f;
59ccaff030SJeremy L Thompson
60ccaff030SJeremy L Thompson // Work vectors
61d1d35e2fSjeremylt prolong_restr_ctx->loc_vec_c = V_loc_c;
62d1d35e2fSjeremylt prolong_restr_ctx->loc_vec_f = V_loc_f;
63d1d35e2fSjeremylt prolong_restr_ctx->ceed_vec_c = ceed_data_c->x_ceed;
64d1d35e2fSjeremylt prolong_restr_ctx->ceed_vec_f = ceed_data_f->x_ceed;
65ccaff030SJeremy L Thompson
66ccaff030SJeremy L Thompson // libCEED operators
67d1d35e2fSjeremylt prolong_restr_ctx->op_prolong = ceed_data_f->op_prolong;
68d1d35e2fSjeremylt prolong_restr_ctx->op_restrict = ceed_data_f->op_restrict;
69ccaff030SJeremy L Thompson
70ccaff030SJeremy L Thompson // Ceed
71d1d35e2fSjeremylt prolong_restr_ctx->ceed = ceed;
72ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS);
73ccaff030SJeremy L Thompson };
74ccaff030SJeremy L Thompson
75ccaff030SJeremy L Thompson // -----------------------------------------------------------------------------
76ccaff030SJeremy L Thompson // Jacobian setup
77ccaff030SJeremy L Thompson // -----------------------------------------------------------------------------
FormJacobian(SNES snes,Vec U,Mat J,Mat J_pre,void * ctx)78d1d35e2fSjeremylt PetscErrorCode FormJacobian(SNES snes, Vec U, Mat J, Mat J_pre, void *ctx) {
79ccaff030SJeremy L Thompson PetscFunctionBeginUser;
80ccaff030SJeremy L Thompson
81ccaff030SJeremy L Thompson // Context data
82d1d35e2fSjeremylt FormJacobCtx form_jacob_ctx = (FormJacobCtx)ctx;
83d1d35e2fSjeremylt PetscInt num_levels = form_jacob_ctx->num_levels;
84d1d35e2fSjeremylt Mat *jacob_mat = form_jacob_ctx->jacob_mat;
85ccaff030SJeremy L Thompson
86e3e3df41Sjeremylt // Update Jacobian on each level
87d1d35e2fSjeremylt for (PetscInt level = 0; level < num_levels; level++) {
882b730f8bSJeremy L Thompson PetscCall(MatAssemblyBegin(jacob_mat[level], MAT_FINAL_ASSEMBLY));
892b730f8bSJeremy L Thompson PetscCall(MatAssemblyEnd(jacob_mat[level], MAT_FINAL_ASSEMBLY));
90ccaff030SJeremy L Thompson }
91ccaff030SJeremy L Thompson
92ccaff030SJeremy L Thompson // Form coarse assembled matrix
932b730f8bSJeremy L Thompson CeedOperatorLinearAssemble(form_jacob_ctx->op_coarse, form_jacob_ctx->coo_values);
9417f0843fSJeremy L Thompson const CeedScalar *values;
9517f0843fSJeremy L Thompson CeedVectorGetArrayRead(form_jacob_ctx->coo_values, CEED_MEM_HOST, &values);
962b730f8bSJeremy L Thompson PetscCall(MatSetValuesCOO(form_jacob_ctx->jacob_mat_coarse, values, ADD_VALUES));
9717f0843fSJeremy L Thompson CeedVectorRestoreArrayRead(form_jacob_ctx->coo_values, &values);
98ccaff030SJeremy L Thompson
99d1d35e2fSjeremylt // J_pre might be AIJ (e.g., when using coloring), so we need to assemble it
1002b730f8bSJeremy L Thompson PetscCall(MatAssemblyBegin(J_pre, MAT_FINAL_ASSEMBLY));
1012b730f8bSJeremy L Thompson PetscCall(MatAssemblyEnd(J_pre, MAT_FINAL_ASSEMBLY));
102d1d35e2fSjeremylt if (J != J_pre) {
1032b730f8bSJeremy L Thompson PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
1042b730f8bSJeremy L Thompson PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
1050e0d204cSJed Brown }
106ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS);
107ccaff030SJeremy L Thompson };
108ccaff030SJeremy L Thompson
109ccaff030SJeremy L Thompson // -----------------------------------------------------------------------------
110ccaff030SJeremy L Thompson // Output solution for visualization
111ccaff030SJeremy L Thompson // -----------------------------------------------------------------------------
ViewSolution(MPI_Comm comm,AppCtx app_ctx,Vec U,PetscInt increment,PetscScalar load_increment)1122b730f8bSJeremy L Thompson PetscErrorCode ViewSolution(MPI_Comm comm, AppCtx app_ctx, Vec U, PetscInt increment, PetscScalar load_increment) {
113ccaff030SJeremy L Thompson DM dm;
114ccaff030SJeremy L Thompson PetscViewer viewer;
115d1d35e2fSjeremylt char output_filename[PETSC_MAX_PATH_LEN];
116d99129b9SLeila Ghaffari PetscMPIInt rank;
117ccaff030SJeremy L Thompson
118ccaff030SJeremy L Thompson PetscFunctionBeginUser;
119ccaff030SJeremy L Thompson
120d99129b9SLeila Ghaffari // Create output directory
121d99129b9SLeila Ghaffari MPI_Comm_rank(comm, &rank);
1222b730f8bSJeremy L Thompson if (!rank) {
1232b730f8bSJeremy L Thompson PetscCall(PetscMkdir(app_ctx->output_dir));
1242b730f8bSJeremy L Thompson }
125d99129b9SLeila Ghaffari
126ccaff030SJeremy L Thompson // Build file name
1272b730f8bSJeremy L Thompson PetscCall(PetscSNPrintf(output_filename, sizeof output_filename, "%s/solution-%03" PetscInt_FMT ".vtu", app_ctx->output_dir, increment));
128ccaff030SJeremy L Thompson
129050e48ebSJeremy L Thompson // Increment sequence
1302b730f8bSJeremy L Thompson PetscCall(VecGetDM(U, &dm));
1312b730f8bSJeremy L Thompson PetscCall(DMSetOutputSequenceNumber(dm, increment, load_increment));
132ccaff030SJeremy L Thompson
133ccaff030SJeremy L Thompson // Output solution vector
1342b730f8bSJeremy L Thompson PetscCall(PetscViewerVTKOpen(comm, output_filename, FILE_MODE_WRITE, &viewer));
1352b730f8bSJeremy L Thompson PetscCall(VecView(U, viewer));
1362b730f8bSJeremy L Thompson PetscCall(PetscViewerDestroy(&viewer));
137ccaff030SJeremy L Thompson
138ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS);
139ccaff030SJeremy L Thompson };
1405c25879aSJeremy L Thompson
1415c25879aSJeremy L Thompson // -----------------------------------------------------------------------------
1425c25879aSJeremy L Thompson // Output diagnostic quantities for visualization
1435c25879aSJeremy L Thompson // -----------------------------------------------------------------------------
ViewDiagnosticQuantities(MPI_Comm comm,DM dmU,UserMult user,AppCtx app_ctx,Vec U,CeedElemRestriction elem_restr_diagnostic)1442b730f8bSJeremy L Thompson PetscErrorCode ViewDiagnosticQuantities(MPI_Comm comm, DM dmU, UserMult user, AppCtx app_ctx, Vec U, CeedElemRestriction elem_restr_diagnostic) {
145d1d35e2fSjeremylt Vec Diagnostic, Y_loc, mult_vec;
146d1d35e2fSjeremylt CeedVector y_ceed;
1475c25879aSJeremy L Thompson CeedScalar *x, *y;
148d1d35e2fSjeremylt PetscMemType x_mem_type, y_mem_type;
149d1d35e2fSjeremylt PetscInt loc_size;
1505c25879aSJeremy L Thompson PetscViewer viewer;
151d1d35e2fSjeremylt char output_filename[PETSC_MAX_PATH_LEN];
1525c25879aSJeremy L Thompson
1535c25879aSJeremy L Thompson PetscFunctionBeginUser;
1545c25879aSJeremy L Thompson
1555c25879aSJeremy L Thompson // ---------------------------------------------------------------------------
1565c25879aSJeremy L Thompson // PETSc and libCEED vectors
1575c25879aSJeremy L Thompson // ---------------------------------------------------------------------------
1582b730f8bSJeremy L Thompson PetscCall(DMCreateGlobalVector(user->dm, &Diagnostic));
1592b730f8bSJeremy L Thompson PetscCall(PetscObjectSetName((PetscObject)Diagnostic, ""));
1602b730f8bSJeremy L Thompson PetscCall(DMCreateLocalVector(user->dm, &Y_loc));
1612b730f8bSJeremy L Thompson PetscCall(VecGetSize(Y_loc, &loc_size));
162d1d35e2fSjeremylt CeedVectorCreate(user->ceed, loc_size, &y_ceed);
1635c25879aSJeremy L Thompson
1645c25879aSJeremy L Thompson // ---------------------------------------------------------------------------
1655c25879aSJeremy L Thompson // Compute quantities
1665c25879aSJeremy L Thompson // ---------------------------------------------------------------------------
1675c25879aSJeremy L Thompson // -- Global-to-local
1682b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(user->X_loc));
1692b730f8bSJeremy L Thompson PetscCall(DMPlexInsertBoundaryValues(dmU, PETSC_TRUE, user->X_loc, user->load_increment, NULL, NULL, NULL));
1702b730f8bSJeremy L Thompson PetscCall(DMGlobalToLocal(dmU, U, INSERT_VALUES, user->X_loc));
1712b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(Y_loc));
1725c25879aSJeremy L Thompson
1735c25879aSJeremy L Thompson // -- Setup CEED vectors
1742b730f8bSJeremy L Thompson PetscCall(VecGetArrayReadAndMemType(user->X_loc, (const PetscScalar **)&x, &x_mem_type));
1752b730f8bSJeremy L Thompson PetscCall(VecGetArrayAndMemType(Y_loc, &y, &y_mem_type));
176d1d35e2fSjeremylt CeedVectorSetArray(user->x_ceed, MemTypeP2C(x_mem_type), CEED_USE_POINTER, x);
177d1d35e2fSjeremylt CeedVectorSetArray(y_ceed, MemTypeP2C(y_mem_type), CEED_USE_POINTER, y);
1785c25879aSJeremy L Thompson
1795c25879aSJeremy L Thompson // -- Apply CEED operator
180d1d35e2fSjeremylt CeedOperatorApply(user->op, user->x_ceed, y_ceed, CEED_REQUEST_IMMEDIATE);
1815c25879aSJeremy L Thompson
182d1d35e2fSjeremylt // -- Restore PETSc vector; keep y_ceed viewing memory of Y_loc for use below
183d1d35e2fSjeremylt CeedVectorTakeArray(user->x_ceed, MemTypeP2C(x_mem_type), NULL);
1842b730f8bSJeremy L Thompson PetscCall(VecRestoreArrayReadAndMemType(user->X_loc, (const PetscScalar **)&x));
1855c25879aSJeremy L Thompson
1865c25879aSJeremy L Thompson // -- Local-to-global
1872b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(Diagnostic));
1882b730f8bSJeremy L Thompson PetscCall(DMLocalToGlobal(user->dm, Y_loc, ADD_VALUES, Diagnostic));
1895c25879aSJeremy L Thompson
1905c25879aSJeremy L Thompson // ---------------------------------------------------------------------------
1915c25879aSJeremy L Thompson // Scale for multiplicity
1925c25879aSJeremy L Thompson // ---------------------------------------------------------------------------
1935c25879aSJeremy L Thompson // -- Setup vectors
1942b730f8bSJeremy L Thompson PetscCall(VecDuplicate(Diagnostic, &mult_vec));
1952b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(Y_loc));
1965c25879aSJeremy L Thompson
1975c25879aSJeremy L Thompson // -- Compute multiplicity
198d1d35e2fSjeremylt CeedElemRestrictionGetMultiplicity(elem_restr_diagnostic, y_ceed);
1995c25879aSJeremy L Thompson
2005c25879aSJeremy L Thompson // -- Restore vectors
201d1d35e2fSjeremylt CeedVectorTakeArray(y_ceed, MemTypeP2C(y_mem_type), NULL);
2022b730f8bSJeremy L Thompson PetscCall(VecRestoreArrayAndMemType(Y_loc, &y));
2035c25879aSJeremy L Thompson
2045c25879aSJeremy L Thompson // -- Local-to-global
2052b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(mult_vec));
2062b730f8bSJeremy L Thompson PetscCall(DMLocalToGlobal(user->dm, Y_loc, ADD_VALUES, mult_vec));
2075c25879aSJeremy L Thompson
2085c25879aSJeremy L Thompson // -- Scale
2092b730f8bSJeremy L Thompson PetscCall(VecReciprocal(mult_vec));
2102b730f8bSJeremy L Thompson PetscCall(VecPointwiseMult(Diagnostic, Diagnostic, mult_vec));
2115c25879aSJeremy L Thompson
2125c25879aSJeremy L Thompson // ---------------------------------------------------------------------------
2135c25879aSJeremy L Thompson // Output solution vector
2145c25879aSJeremy L Thompson // ---------------------------------------------------------------------------
2152b730f8bSJeremy L Thompson PetscCall(PetscSNPrintf(output_filename, sizeof output_filename, "%s/diagnostic_quantities.vtu", app_ctx->output_dir));
2162b730f8bSJeremy L Thompson PetscCall(PetscViewerVTKOpen(comm, output_filename, FILE_MODE_WRITE, &viewer));
2172b730f8bSJeremy L Thompson PetscCall(VecView(Diagnostic, viewer));
2182b730f8bSJeremy L Thompson PetscCall(PetscViewerDestroy(&viewer));
2195c25879aSJeremy L Thompson
2205c25879aSJeremy L Thompson // ---------------------------------------------------------------------------
2215c25879aSJeremy L Thompson // Cleanup
2225c25879aSJeremy L Thompson // ---------------------------------------------------------------------------
2232b730f8bSJeremy L Thompson PetscCall(VecDestroy(&Diagnostic));
2242b730f8bSJeremy L Thompson PetscCall(VecDestroy(&mult_vec));
2252b730f8bSJeremy L Thompson PetscCall(VecDestroy(&Y_loc));
226d1d35e2fSjeremylt CeedVectorDestroy(&y_ceed);
2275c25879aSJeremy L Thompson
228ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS);
2295c25879aSJeremy L Thompson };
2305754ecacSJeremy L Thompson
2315754ecacSJeremy L Thompson // -----------------------------------------------------------------------------
2325754ecacSJeremy L Thompson // Regression testing
2335754ecacSJeremy L Thompson // -----------------------------------------------------------------------------
2345754ecacSJeremy L Thompson // test option change. could remove the loading step. Run only with one loading step and compare relatively to ref file
2352b730f8bSJeremy 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
2362b730f8bSJeremy L Thompson // energy
RegressionTests_solids(AppCtx app_ctx,PetscReal energy)2375754ecacSJeremy L Thompson PetscErrorCode RegressionTests_solids(AppCtx app_ctx, PetscReal energy) {
2385754ecacSJeremy L Thompson PetscFunctionBegin;
2395754ecacSJeremy L Thompson
2405754ecacSJeremy L Thompson if (app_ctx->expect_final_strain >= 0.) {
2415754ecacSJeremy L Thompson PetscReal energy_ref = app_ctx->expect_final_strain;
2425754ecacSJeremy L Thompson PetscReal error = PetscAbsReal(energy - energy_ref) / energy_ref;
2435754ecacSJeremy L Thompson
2445754ecacSJeremy L Thompson if (error > app_ctx->test_tol) {
2452b730f8bSJeremy L Thompson PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Energy %e does not match expected energy %e: relative tolerance %e > %e\n", (double)energy,
2462b730f8bSJeremy L Thompson (double)energy_ref, (double)error, app_ctx->test_tol));
2475754ecacSJeremy L Thompson }
2485754ecacSJeremy L Thompson }
249ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS);
2505754ecacSJeremy L Thompson };
251