xref: /libCEED/examples/fluids/src/setupts.c (revision e6225c4737d2b5358b9c1c5b7c13d86915d842f6)
177841947SLeila Ghaffari // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
277841947SLeila Ghaffari // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
377841947SLeila Ghaffari // reserved. See files LICENSE and NOTICE for details.
477841947SLeila Ghaffari //
577841947SLeila Ghaffari // This file is part of CEED, a collection of benchmarks, miniapps, software
677841947SLeila Ghaffari // libraries and APIs for efficient high-order finite element and spectral
777841947SLeila Ghaffari // element discretizations for exascale applications. For more information and
877841947SLeila Ghaffari // source code availability see http://github.com/ceed.
977841947SLeila Ghaffari //
1077841947SLeila Ghaffari // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
1177841947SLeila Ghaffari // a collaborative effort of two U.S. Department of Energy organizations (Office
1277841947SLeila Ghaffari // of Science and the National Nuclear Security Administration) responsible for
1377841947SLeila Ghaffari // the planning and preparation of a capable exascale ecosystem, including
1477841947SLeila Ghaffari // software, applications, hardware, advanced system engineering and early
1577841947SLeila Ghaffari // testbed platforms, in support of the nation's exascale computing imperative.
1677841947SLeila Ghaffari 
1777841947SLeila Ghaffari /// @file
1877841947SLeila Ghaffari /// Time-stepping functions for Navier-Stokes example using PETSc
1977841947SLeila Ghaffari 
2077841947SLeila Ghaffari #include "../navierstokes.h"
2177841947SLeila Ghaffari #include "../qfunctions/mass.h"
2277841947SLeila Ghaffari 
2377841947SLeila Ghaffari // Compute mass matrix for explicit scheme
2477841947SLeila Ghaffari PetscErrorCode ComputeLumpedMassMatrix(Ceed ceed, DM dm, CeedData ceed_data,
2577841947SLeila Ghaffari                                        Vec M) {
2677841947SLeila Ghaffari   Vec            M_loc;
2777841947SLeila Ghaffari   CeedQFunction  qf_mass;
2877841947SLeila Ghaffari   CeedOperator   op_mass;
2977841947SLeila Ghaffari   CeedVector     m_ceed, ones_vec;
3077841947SLeila Ghaffari   CeedInt        num_comp_q, q_data_size;
3177841947SLeila Ghaffari   PetscErrorCode ierr;
3277841947SLeila Ghaffari   PetscFunctionBeginUser;
3377841947SLeila Ghaffari 
3477841947SLeila Ghaffari   // CEED Restriction
3577841947SLeila Ghaffari   CeedElemRestrictionGetNumComponents(ceed_data->elem_restr_q, &num_comp_q);
3677841947SLeila Ghaffari   CeedElemRestrictionGetNumComponents(ceed_data->elem_restr_qd_i, &q_data_size);
3777841947SLeila Ghaffari   CeedElemRestrictionCreateVector(ceed_data->elem_restr_q, &m_ceed, NULL);
3877841947SLeila Ghaffari   CeedElemRestrictionCreateVector(ceed_data->elem_restr_q, &ones_vec, NULL);
3977841947SLeila Ghaffari   CeedVectorSetValue(ones_vec, 1.0);
4077841947SLeila Ghaffari 
4177841947SLeila Ghaffari   // CEED QFunction
4277841947SLeila Ghaffari   CeedQFunctionCreateInterior(ceed, 1, Mass, Mass_loc, &qf_mass);
4377841947SLeila Ghaffari   CeedQFunctionAddInput(qf_mass, "q", num_comp_q, CEED_EVAL_INTERP);
4477841947SLeila Ghaffari   CeedQFunctionAddInput(qf_mass, "q_data", q_data_size, CEED_EVAL_NONE);
4577841947SLeila Ghaffari   CeedQFunctionAddOutput(qf_mass, "v", num_comp_q, CEED_EVAL_INTERP);
4677841947SLeila Ghaffari 
4777841947SLeila Ghaffari   // CEED Operator
4877841947SLeila Ghaffari   CeedOperatorCreate(ceed, qf_mass, NULL, NULL, &op_mass);
4977841947SLeila Ghaffari   CeedOperatorSetField(op_mass, "q", ceed_data->elem_restr_q, ceed_data->basis_q,
5077841947SLeila Ghaffari                        CEED_VECTOR_ACTIVE);
5177841947SLeila Ghaffari   CeedOperatorSetField(op_mass, "q_data", ceed_data->elem_restr_qd_i,
5277841947SLeila Ghaffari                        CEED_BASIS_COLLOCATED, ceed_data->q_data);
5377841947SLeila Ghaffari   CeedOperatorSetField(op_mass, "v", ceed_data->elem_restr_q, ceed_data->basis_q,
5477841947SLeila Ghaffari                        CEED_VECTOR_ACTIVE);
5577841947SLeila Ghaffari 
5677841947SLeila Ghaffari   // Place PETSc vector in CEED vector
5777841947SLeila Ghaffari   CeedScalar *m;
5877841947SLeila Ghaffari   PetscMemType m_mem_type;
5977841947SLeila Ghaffari   ierr = DMGetLocalVector(dm, &M_loc); CHKERRQ(ierr);
6077841947SLeila Ghaffari   ierr = VecGetArrayAndMemType(M_loc, (PetscScalar **)&m, &m_mem_type);
6177841947SLeila Ghaffari   CHKERRQ(ierr);
6277841947SLeila Ghaffari   CeedVectorSetArray(m_ceed, MemTypeP2C(m_mem_type), CEED_USE_POINTER, m);
6377841947SLeila Ghaffari 
6477841947SLeila Ghaffari   // Apply CEED Operator
6577841947SLeila Ghaffari   CeedOperatorApply(op_mass, ones_vec, m_ceed, CEED_REQUEST_IMMEDIATE);
6677841947SLeila Ghaffari 
6777841947SLeila Ghaffari   // Restore vectors
6877841947SLeila Ghaffari   CeedVectorTakeArray(m_ceed, MemTypeP2C(m_mem_type), NULL);
6977841947SLeila Ghaffari   ierr = VecRestoreArrayReadAndMemType(M_loc, (const PetscScalar **)&m);
7077841947SLeila Ghaffari   CHKERRQ(ierr);
7177841947SLeila Ghaffari 
7277841947SLeila Ghaffari   // Local-to-Global
7377841947SLeila Ghaffari   ierr = VecZeroEntries(M); CHKERRQ(ierr);
7477841947SLeila Ghaffari   ierr = DMLocalToGlobal(dm, M_loc, ADD_VALUES, M); CHKERRQ(ierr);
7577841947SLeila Ghaffari   ierr = DMRestoreLocalVector(dm, &M_loc); CHKERRQ(ierr);
7677841947SLeila Ghaffari 
7777841947SLeila Ghaffari   // Invert diagonally lumped mass vector for RHS function
7877841947SLeila Ghaffari   ierr = VecReciprocal(M); CHKERRQ(ierr);
7977841947SLeila Ghaffari 
8077841947SLeila Ghaffari   // Cleanup
8177841947SLeila Ghaffari   CeedVectorDestroy(&ones_vec);
8277841947SLeila Ghaffari   CeedVectorDestroy(&m_ceed);
8377841947SLeila Ghaffari   CeedQFunctionDestroy(&qf_mass);
8477841947SLeila Ghaffari   CeedOperatorDestroy(&op_mass);
8577841947SLeila Ghaffari 
8677841947SLeila Ghaffari   PetscFunctionReturn(0);
8777841947SLeila Ghaffari }
8877841947SLeila Ghaffari 
8977841947SLeila Ghaffari // RHS (Explicit time-stepper) function setup
9077841947SLeila Ghaffari //   This is the RHS of the ODE, given as u_t = G(t,u)
9177841947SLeila Ghaffari //   This function takes in a state vector Q and writes into G
9277841947SLeila Ghaffari PetscErrorCode RHS_NS(TS ts, PetscReal t, Vec Q, Vec G, void *user_data) {
9377841947SLeila Ghaffari 
9477841947SLeila Ghaffari   User           user = *(User *)user_data;
9577841947SLeila Ghaffari   PetscScalar    *q, *g;
9677841947SLeila Ghaffari   Vec            Q_loc, G_loc;
9777841947SLeila Ghaffari   PetscMemType   q_mem_type, g_mem_type;
9877841947SLeila Ghaffari   PetscErrorCode ierr;
9977841947SLeila Ghaffari   PetscFunctionBeginUser;
10077841947SLeila Ghaffari 
10177841947SLeila Ghaffari   // Update EulerContext
10277841947SLeila Ghaffari   if (user->phys->has_curr_time) user->phys->euler_ctx->curr_time = t;
10377841947SLeila Ghaffari 
10477841947SLeila Ghaffari   // Get local vectors
10577841947SLeila Ghaffari   ierr = DMGetLocalVector(user->dm, &Q_loc); CHKERRQ(ierr);
10677841947SLeila Ghaffari   ierr = DMGetLocalVector(user->dm, &G_loc); CHKERRQ(ierr);
10777841947SLeila Ghaffari 
10877841947SLeila Ghaffari   // Global-to-local
10977841947SLeila Ghaffari   ierr = VecZeroEntries(Q_loc); CHKERRQ(ierr);
11077841947SLeila Ghaffari   ierr = DMGlobalToLocal(user->dm, Q, INSERT_VALUES, Q_loc); CHKERRQ(ierr);
11177841947SLeila Ghaffari   ierr = DMPlexInsertBoundaryValues(user->dm, PETSC_TRUE, Q_loc, 0.0,
11277841947SLeila Ghaffari                                     NULL, NULL, NULL); CHKERRQ(ierr);
11377841947SLeila Ghaffari   ierr = VecZeroEntries(G_loc); CHKERRQ(ierr);
11477841947SLeila Ghaffari 
11577841947SLeila Ghaffari   // Place PETSc vectors in CEED vectors
11677841947SLeila Ghaffari   ierr = VecGetArrayReadAndMemType(Q_loc, (const PetscScalar **)&q, &q_mem_type);
11777841947SLeila Ghaffari   CHKERRQ(ierr);
11877841947SLeila Ghaffari   ierr = VecGetArrayAndMemType(G_loc, &g, &g_mem_type); CHKERRQ(ierr);
11977841947SLeila Ghaffari   CeedVectorSetArray(user->q_ceed, MemTypeP2C(q_mem_type), CEED_USE_POINTER, q);
12077841947SLeila Ghaffari   CeedVectorSetArray(user->g_ceed, MemTypeP2C(g_mem_type), CEED_USE_POINTER, g);
12177841947SLeila Ghaffari 
12277841947SLeila Ghaffari   // Apply CEED operator
12377841947SLeila Ghaffari   CeedOperatorApply(user->op_rhs, user->q_ceed, user->g_ceed,
12477841947SLeila Ghaffari                     CEED_REQUEST_IMMEDIATE);
12577841947SLeila Ghaffari 
12677841947SLeila Ghaffari   // Restore vectors
12777841947SLeila Ghaffari   CeedVectorTakeArray(user->q_ceed, MemTypeP2C(q_mem_type), NULL);
12877841947SLeila Ghaffari   CeedVectorTakeArray(user->g_ceed, MemTypeP2C(g_mem_type), NULL);
12977841947SLeila Ghaffari   ierr = VecRestoreArrayReadAndMemType(Q_loc, (const PetscScalar **)&q);
13077841947SLeila Ghaffari   CHKERRQ(ierr);
13177841947SLeila Ghaffari   ierr = VecRestoreArrayAndMemType(G_loc, &g); CHKERRQ(ierr);
13277841947SLeila Ghaffari 
13377841947SLeila Ghaffari   // Local-to-Global
13477841947SLeila Ghaffari   ierr = VecZeroEntries(G); CHKERRQ(ierr);
13577841947SLeila Ghaffari   ierr = DMLocalToGlobal(user->dm, G_loc, ADD_VALUES, G); CHKERRQ(ierr);
13677841947SLeila Ghaffari 
13777841947SLeila Ghaffari   // Inverse of the lumped mass matrix (M is Minv)
13877841947SLeila Ghaffari   ierr = VecPointwiseMult(G, G, user->M); CHKERRQ(ierr);
13977841947SLeila Ghaffari 
14077841947SLeila Ghaffari   // Restore vectors
14177841947SLeila Ghaffari   ierr = DMRestoreLocalVector(user->dm, &Q_loc); CHKERRQ(ierr);
14277841947SLeila Ghaffari   ierr = DMRestoreLocalVector(user->dm, &G_loc); CHKERRQ(ierr);
14377841947SLeila Ghaffari 
14477841947SLeila Ghaffari   PetscFunctionReturn(0);
14577841947SLeila Ghaffari }
14677841947SLeila Ghaffari 
14777841947SLeila Ghaffari // Implicit time-stepper function setup
14877841947SLeila Ghaffari PetscErrorCode IFunction_NS(TS ts, PetscReal t, Vec Q, Vec Q_dot, Vec G,
14977841947SLeila Ghaffari                             void *user_data) {
15077841947SLeila Ghaffari   User              user = *(User *)user_data;
15177841947SLeila Ghaffari   const PetscScalar *q, *q_dot;
15277841947SLeila Ghaffari   PetscScalar       *g;
15377841947SLeila Ghaffari   Vec               Q_loc, Q_dot_loc, G_loc;
15477841947SLeila Ghaffari   PetscMemType      q_mem_type, q_dot_mem_type, g_mem_type;
15577841947SLeila Ghaffari   PetscErrorCode    ierr;
15677841947SLeila Ghaffari   PetscFunctionBeginUser;
15777841947SLeila Ghaffari 
15877841947SLeila Ghaffari   // Update EulerContext
15977841947SLeila Ghaffari   if (user->phys->has_curr_time) user->phys->euler_ctx->curr_time = t;
16077841947SLeila Ghaffari 
16177841947SLeila Ghaffari   // Get local vectors
16277841947SLeila Ghaffari   ierr = DMGetLocalVector(user->dm, &Q_loc); CHKERRQ(ierr);
16377841947SLeila Ghaffari   ierr = DMGetLocalVector(user->dm, &Q_dot_loc); CHKERRQ(ierr);
16477841947SLeila Ghaffari   ierr = DMGetLocalVector(user->dm, &G_loc); CHKERRQ(ierr);
16577841947SLeila Ghaffari 
16677841947SLeila Ghaffari   // Global-to-local
16777841947SLeila Ghaffari   ierr = VecZeroEntries(Q_loc); CHKERRQ(ierr);
16877841947SLeila Ghaffari   ierr = DMGlobalToLocal(user->dm, Q, INSERT_VALUES, Q_loc); CHKERRQ(ierr);
16977841947SLeila Ghaffari   ierr = DMPlexInsertBoundaryValues(user->dm, PETSC_TRUE, Q_loc, 0.0,
17077841947SLeila Ghaffari                                     NULL, NULL, NULL); CHKERRQ(ierr);
17177841947SLeila Ghaffari   ierr = VecZeroEntries(Q_dot_loc); CHKERRQ(ierr);
17277841947SLeila Ghaffari   ierr = DMGlobalToLocal(user->dm, Q_dot, INSERT_VALUES, Q_dot_loc);
17377841947SLeila Ghaffari   CHKERRQ(ierr);
17477841947SLeila Ghaffari   ierr = VecZeroEntries(G_loc); CHKERRQ(ierr);
17577841947SLeila Ghaffari 
17677841947SLeila Ghaffari   // Place PETSc vectors in CEED vectors
17777841947SLeila Ghaffari   ierr = VecGetArrayReadAndMemType(Q_loc, &q, &q_mem_type); CHKERRQ(ierr);
17877841947SLeila Ghaffari   ierr = VecGetArrayReadAndMemType(Q_dot_loc, &q_dot, &q_dot_mem_type);
17977841947SLeila Ghaffari   CHKERRQ(ierr);
18077841947SLeila Ghaffari   ierr = VecGetArrayAndMemType(G_loc, &g, &g_mem_type); CHKERRQ(ierr);
18177841947SLeila Ghaffari   CeedVectorSetArray(user->q_ceed, MemTypeP2C(q_mem_type), CEED_USE_POINTER,
18277841947SLeila Ghaffari                      (PetscScalar *)q);
18377841947SLeila Ghaffari   CeedVectorSetArray(user->q_dot_ceed, MemTypeP2C(q_dot_mem_type),
184*e6225c47SLeila Ghaffari                      CEED_USE_POINTER, (PetscScalar *)q_dot);
18577841947SLeila Ghaffari   CeedVectorSetArray(user->g_ceed, MemTypeP2C(g_mem_type), CEED_USE_POINTER, g);
18677841947SLeila Ghaffari 
18777841947SLeila Ghaffari   // Apply CEED operator
18877841947SLeila Ghaffari   CeedOperatorApply(user->op_ifunction, user->q_ceed, user->g_ceed,
18977841947SLeila Ghaffari                     CEED_REQUEST_IMMEDIATE);
19077841947SLeila Ghaffari 
19177841947SLeila Ghaffari   // Restore vectors
19277841947SLeila Ghaffari   CeedVectorTakeArray(user->q_ceed, MemTypeP2C(q_mem_type), NULL);
19377841947SLeila Ghaffari   CeedVectorTakeArray(user->q_dot_ceed, MemTypeP2C(q_dot_mem_type), NULL);
19477841947SLeila Ghaffari   CeedVectorTakeArray(user->g_ceed, MemTypeP2C(g_mem_type), NULL);
19577841947SLeila Ghaffari   ierr = VecRestoreArrayReadAndMemType(Q_loc, &q); CHKERRQ(ierr);
19677841947SLeila Ghaffari   ierr = VecRestoreArrayReadAndMemType(Q_dot_loc, &q_dot); CHKERRQ(ierr);
19777841947SLeila Ghaffari   ierr = VecRestoreArrayAndMemType(G_loc, &g); CHKERRQ(ierr);
19877841947SLeila Ghaffari 
19977841947SLeila Ghaffari   // Local-to-Global
20077841947SLeila Ghaffari   ierr = VecZeroEntries(G); CHKERRQ(ierr);
20177841947SLeila Ghaffari   ierr = DMLocalToGlobal(user->dm, G_loc, ADD_VALUES, G); CHKERRQ(ierr);
20277841947SLeila Ghaffari 
20377841947SLeila Ghaffari   // Restore vectors
20477841947SLeila Ghaffari   ierr = DMRestoreLocalVector(user->dm, &Q_loc); CHKERRQ(ierr);
20577841947SLeila Ghaffari   ierr = DMRestoreLocalVector(user->dm, &Q_dot_loc); CHKERRQ(ierr);
20677841947SLeila Ghaffari   ierr = DMRestoreLocalVector(user->dm, &G_loc); CHKERRQ(ierr);
20777841947SLeila Ghaffari 
20877841947SLeila Ghaffari   PetscFunctionReturn(0);
20977841947SLeila Ghaffari }
21077841947SLeila Ghaffari 
21177841947SLeila Ghaffari // User provided TS Monitor
21277841947SLeila Ghaffari PetscErrorCode TSMonitor_NS(TS ts, PetscInt step_no, PetscReal time,
21377841947SLeila Ghaffari                             Vec Q, void *ctx) {
21477841947SLeila Ghaffari   User           user = ctx;
21577841947SLeila Ghaffari   Vec            Q_loc;
21677841947SLeila Ghaffari   char           file_path[PETSC_MAX_PATH_LEN];
21777841947SLeila Ghaffari   PetscViewer    viewer;
21877841947SLeila Ghaffari   PetscErrorCode ierr;
21977841947SLeila Ghaffari   PetscFunctionBeginUser;
22077841947SLeila Ghaffari 
22177841947SLeila Ghaffari   // Print every 'output_freq' steps
22277841947SLeila Ghaffari   if (step_no % user->app_ctx->output_freq != 0)
22377841947SLeila Ghaffari     PetscFunctionReturn(0);
22477841947SLeila Ghaffari 
22577841947SLeila Ghaffari   // Set up output
22677841947SLeila Ghaffari   ierr = DMGetLocalVector(user->dm, &Q_loc); CHKERRQ(ierr);
22777841947SLeila Ghaffari   ierr = PetscObjectSetName((PetscObject)Q_loc, "StateVec"); CHKERRQ(ierr);
22877841947SLeila Ghaffari   ierr = VecZeroEntries(Q_loc); CHKERRQ(ierr);
22977841947SLeila Ghaffari   ierr = DMGlobalToLocal(user->dm, Q, INSERT_VALUES, Q_loc); CHKERRQ(ierr);
23077841947SLeila Ghaffari 
23177841947SLeila Ghaffari   // Output
23277841947SLeila Ghaffari   ierr = PetscSNPrintf(file_path, sizeof file_path, "%s/ns-%03D.vtu",
23377841947SLeila Ghaffari                        user->app_ctx->output_dir, step_no + user->app_ctx->cont_steps);
23477841947SLeila Ghaffari   CHKERRQ(ierr);
23577841947SLeila Ghaffari   ierr = PetscViewerVTKOpen(PetscObjectComm((PetscObject)Q), file_path,
23677841947SLeila Ghaffari                             FILE_MODE_WRITE, &viewer); CHKERRQ(ierr);
23777841947SLeila Ghaffari   ierr = VecView(Q_loc, viewer); CHKERRQ(ierr);
23877841947SLeila Ghaffari   ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr);
23977841947SLeila Ghaffari   if (user->dm_viz) {
24077841947SLeila Ghaffari     Vec         Q_refined, Q_refined_loc;
24177841947SLeila Ghaffari     char        file_path_refined[PETSC_MAX_PATH_LEN];
24277841947SLeila Ghaffari     PetscViewer viewer_refined;
24377841947SLeila Ghaffari 
24477841947SLeila Ghaffari     ierr = DMGetGlobalVector(user->dm_viz, &Q_refined); CHKERRQ(ierr);
24577841947SLeila Ghaffari     ierr = DMGetLocalVector(user->dm_viz, &Q_refined_loc); CHKERRQ(ierr);
24677841947SLeila Ghaffari     ierr = PetscObjectSetName((PetscObject)Q_refined_loc, "Refined");
24777841947SLeila Ghaffari     CHKERRQ(ierr);
24877841947SLeila Ghaffari     ierr = MatInterpolate(user->interp_viz, Q, Q_refined); CHKERRQ(ierr);
24977841947SLeila Ghaffari     ierr = VecZeroEntries(Q_refined_loc); CHKERRQ(ierr);
25077841947SLeila Ghaffari     ierr = DMGlobalToLocal(user->dm_viz, Q_refined, INSERT_VALUES, Q_refined_loc);
25177841947SLeila Ghaffari     CHKERRQ(ierr);
25277841947SLeila Ghaffari     ierr = PetscSNPrintf(file_path_refined, sizeof file_path_refined,
253*e6225c47SLeila Ghaffari                          "%s/nsrefined-%03D.vtu", user->app_ctx->output_dir,
254*e6225c47SLeila Ghaffari                          step_no + user->app_ctx->cont_steps);
25577841947SLeila Ghaffari     CHKERRQ(ierr);
25677841947SLeila Ghaffari     ierr = PetscViewerVTKOpen(PetscObjectComm((PetscObject)Q_refined),
257*e6225c47SLeila Ghaffari                               file_path_refined, FILE_MODE_WRITE, &viewer_refined); CHKERRQ(ierr);
25877841947SLeila Ghaffari     ierr = VecView(Q_refined_loc, viewer_refined); CHKERRQ(ierr);
25977841947SLeila Ghaffari     ierr = DMRestoreLocalVector(user->dm_viz, &Q_refined_loc); CHKERRQ(ierr);
26077841947SLeila Ghaffari     ierr = DMRestoreGlobalVector(user->dm_viz, &Q_refined); CHKERRQ(ierr);
26177841947SLeila Ghaffari     ierr = PetscViewerDestroy(&viewer_refined); CHKERRQ(ierr);
26277841947SLeila Ghaffari   }
26377841947SLeila Ghaffari   ierr = DMRestoreLocalVector(user->dm, &Q_loc); CHKERRQ(ierr);
26477841947SLeila Ghaffari 
26577841947SLeila Ghaffari   // Save data in a binary file for continuation of simulations
26677841947SLeila Ghaffari   ierr = PetscSNPrintf(file_path, sizeof file_path, "%s/ns-solution.bin",
26777841947SLeila Ghaffari                        user->app_ctx->output_dir); CHKERRQ(ierr);
26877841947SLeila Ghaffari   ierr = PetscViewerBinaryOpen(user->comm, file_path, FILE_MODE_WRITE, &viewer);
26977841947SLeila Ghaffari   CHKERRQ(ierr);
27077841947SLeila Ghaffari   ierr = VecView(Q, viewer); CHKERRQ(ierr);
27177841947SLeila Ghaffari   ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr);
27277841947SLeila Ghaffari 
27377841947SLeila Ghaffari   // Save time stamp
27477841947SLeila Ghaffari   // Dimensionalize time back
27577841947SLeila Ghaffari   time /= user->units->second;
27677841947SLeila Ghaffari   ierr = PetscSNPrintf(file_path, sizeof file_path, "%s/ns-time.bin",
27777841947SLeila Ghaffari                        user->app_ctx->output_dir); CHKERRQ(ierr);
27877841947SLeila Ghaffari   ierr = PetscViewerBinaryOpen(user->comm, file_path, FILE_MODE_WRITE, &viewer);
27977841947SLeila Ghaffari   CHKERRQ(ierr);
28077841947SLeila Ghaffari   #if PETSC_VERSION_GE(3,13,0)
28177841947SLeila Ghaffari   ierr = PetscViewerBinaryWrite(viewer, &time, 1, PETSC_REAL);
28277841947SLeila Ghaffari   #else
28377841947SLeila Ghaffari   ierr = PetscViewerBinaryWrite(viewer, &time, 1, PETSC_REAL, true);
28477841947SLeila Ghaffari   #endif
28577841947SLeila Ghaffari   CHKERRQ(ierr);
28677841947SLeila Ghaffari   ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr);
28777841947SLeila Ghaffari 
28877841947SLeila Ghaffari   PetscFunctionReturn(0);
28977841947SLeila Ghaffari }
29077841947SLeila Ghaffari 
29177841947SLeila Ghaffari // TS: Create, setup, and solve
29277841947SLeila Ghaffari PetscErrorCode TSSolve_NS(DM dm, User user, AppCtx app_ctx, Physics phys,
29377841947SLeila Ghaffari                           Vec *Q, PetscScalar *f_time, TS *ts) {
29477841947SLeila Ghaffari   MPI_Comm       comm = user->comm;
29577841947SLeila Ghaffari   TSAdapt        adapt;
29677841947SLeila Ghaffari   PetscScalar    final_time;
29777841947SLeila Ghaffari   PetscErrorCode ierr;
29877841947SLeila Ghaffari   PetscFunctionBeginUser;
29977841947SLeila Ghaffari 
30077841947SLeila Ghaffari   ierr = TSCreate(comm, ts); CHKERRQ(ierr);
30177841947SLeila Ghaffari   ierr = TSSetDM(*ts, dm); CHKERRQ(ierr);
30277841947SLeila Ghaffari   if (phys->implicit) {
30377841947SLeila Ghaffari     ierr = TSSetType(*ts, TSBDF); CHKERRQ(ierr);
30477841947SLeila Ghaffari     if (user->op_ifunction) {
30577841947SLeila Ghaffari       ierr = TSSetIFunction(*ts, NULL, IFunction_NS, &user); CHKERRQ(ierr);
30677841947SLeila Ghaffari     } else { // Implicit integrators can fall back to using an RHSFunction
30777841947SLeila Ghaffari       ierr = TSSetRHSFunction(*ts, NULL, RHS_NS, &user); CHKERRQ(ierr);
30877841947SLeila Ghaffari     }
30977841947SLeila Ghaffari   } else {
31077841947SLeila Ghaffari     if (!user->op_rhs) SETERRQ(comm, PETSC_ERR_ARG_NULL,
31177841947SLeila Ghaffari                                  "Problem does not provide RHSFunction");
31277841947SLeila Ghaffari     ierr = TSSetType(*ts, TSRK); CHKERRQ(ierr);
31377841947SLeila Ghaffari     ierr = TSRKSetType(*ts, TSRK5F); CHKERRQ(ierr);
31477841947SLeila Ghaffari     ierr = TSSetRHSFunction(*ts, NULL, RHS_NS, &user); CHKERRQ(ierr);
31577841947SLeila Ghaffari   }
31677841947SLeila Ghaffari   ierr = TSSetMaxTime(*ts, 500. * user->units->second); CHKERRQ(ierr);
31777841947SLeila Ghaffari   ierr = TSSetExactFinalTime(*ts, TS_EXACTFINALTIME_STEPOVER); CHKERRQ(ierr);
31877841947SLeila Ghaffari   ierr = TSSetTimeStep(*ts, 1.e-2 * user->units->second); CHKERRQ(ierr);
31977841947SLeila Ghaffari   if (app_ctx->test_mode) {ierr = TSSetMaxSteps(*ts, 10); CHKERRQ(ierr);}
32077841947SLeila Ghaffari   ierr = TSGetAdapt(*ts, &adapt); CHKERRQ(ierr);
32177841947SLeila Ghaffari   ierr = TSAdaptSetStepLimits(adapt,
32277841947SLeila Ghaffari                               1.e-12 * user->units->second,
32377841947SLeila Ghaffari                               1.e2 * user->units->second); CHKERRQ(ierr);
32477841947SLeila Ghaffari   ierr = TSSetFromOptions(*ts); CHKERRQ(ierr);
32577841947SLeila Ghaffari   if (!app_ctx->cont_steps) { // print initial condition
32677841947SLeila Ghaffari     if (!app_ctx->test_mode) {
32777841947SLeila Ghaffari       ierr = TSMonitor_NS(*ts, 0, 0., *Q, user); CHKERRQ(ierr);
32877841947SLeila Ghaffari     }
32977841947SLeila Ghaffari   } else { // continue from time of last output
33077841947SLeila Ghaffari     PetscReal   time;
33177841947SLeila Ghaffari     PetscInt    count;
33277841947SLeila Ghaffari     PetscViewer viewer;
33377841947SLeila Ghaffari     char        file_path[PETSC_MAX_PATH_LEN];
33477841947SLeila Ghaffari     ierr = PetscSNPrintf(file_path, sizeof file_path, "%s/ns-time.bin",
33577841947SLeila Ghaffari                          app_ctx->output_dir); CHKERRQ(ierr);
33677841947SLeila Ghaffari     ierr = PetscViewerBinaryOpen(comm, file_path, FILE_MODE_READ, &viewer);
33777841947SLeila Ghaffari     CHKERRQ(ierr);
33877841947SLeila Ghaffari     ierr = PetscViewerBinaryRead(viewer, &time, 1, &count, PETSC_REAL);
33977841947SLeila Ghaffari     CHKERRQ(ierr);
34077841947SLeila Ghaffari     ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr);
34177841947SLeila Ghaffari     ierr = TSSetTime(*ts, time * user->units->second); CHKERRQ(ierr);
34277841947SLeila Ghaffari   }
34377841947SLeila Ghaffari   if (!app_ctx->test_mode) {
34477841947SLeila Ghaffari     ierr = TSMonitorSet(*ts, TSMonitor_NS, user, NULL); CHKERRQ(ierr);
34577841947SLeila Ghaffari   }
34677841947SLeila Ghaffari 
34777841947SLeila Ghaffari   // Solve
34877841947SLeila Ghaffari   double start, cpu_time_used;
34977841947SLeila Ghaffari   start = MPI_Wtime();
35077841947SLeila Ghaffari   ierr = PetscBarrier((PetscObject) *ts); CHKERRQ(ierr);
35177841947SLeila Ghaffari   ierr = TSSolve(*ts, *Q); CHKERRQ(ierr);
35277841947SLeila Ghaffari   cpu_time_used = MPI_Wtime() - start;
35377841947SLeila Ghaffari   ierr = TSGetSolveTime(*ts, &final_time); CHKERRQ(ierr);
35477841947SLeila Ghaffari   *f_time = final_time;
35577841947SLeila Ghaffari   ierr = MPI_Allreduce(MPI_IN_PLACE, &cpu_time_used, 1, MPI_DOUBLE, MPI_MIN,
35677841947SLeila Ghaffari                        comm); CHKERRQ(ierr);
35777841947SLeila Ghaffari   if (!app_ctx->test_mode) {
35877841947SLeila Ghaffari     ierr = PetscPrintf(PETSC_COMM_WORLD,
35977841947SLeila Ghaffari                        "Time taken for solution (sec): %g\n",
36077841947SLeila Ghaffari                        (double)cpu_time_used); CHKERRQ(ierr);
36177841947SLeila Ghaffari   }
36277841947SLeila Ghaffari   PetscFunctionReturn(0);
36377841947SLeila Ghaffari }
364