1 // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2 // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3 // reserved. See files LICENSE and NOTICE for details. 4 // 5 // This file is part of CEED, a collection of benchmarks, miniapps, software 6 // libraries and APIs for efficient high-order finite element and spectral 7 // element discretizations for exascale applications. For more information and 8 // source code availability see http://github.com/ceed. 9 // 10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11 // a collaborative effort of two U.S. Department of Energy organizations (Office 12 // of Science and the National Nuclear Security Administration) responsible for 13 // the planning and preparation of a capable exascale ecosystem, including 14 // software, applications, hardware, advanced system engineering and early 15 // testbed platforms, in support of the nation's exascale computing imperative. 16 17 // libCEED + PETSc Example: Navier-Stokes 18 // 19 // This example demonstrates a simple usage of libCEED with PETSc to solve a 20 // Navier-Stokes problem. 21 // 22 // The code is intentionally "raw", using only low-level communication 23 // primitives. 24 // 25 // Build with: 26 // 27 // make [PETSC_DIR=</path/to/petsc>] [CEED_DIR=</path/to/libceed>] navierstokes 28 // 29 // Sample runs: 30 // 31 // ./navierstokes -ceed /cpu/self -problem density_current -degree 1 32 // ./navierstokes -ceed /gpu/occa -problem advection -degree 1 33 // 34 //TESTARGS -ceed {ceed_resource} -test explicit -degree 3 -dm_plex_box_faces 1,1,2 -units_kilogram 1e-9 -lx 125 -ly 125 -lz 250 -center 62.5,62.5,187.5 -rc 100. -thetaC -35. -ksp_atol 1e-4 -ksp_rtol 1e-3 -ksp_type bcgs -snes_atol 1e-3 -snes_lag_jacobian 100 -snes_lag_jacobian_persists -snes_mf_operator -ts_dt 1e-3 35 //TESTARGS -ceed {ceed_resource} -test implicit_stab_none -degree 3 -dm_plex_box_faces 1,1,2 -units_kilogram 1e-9 -lx 125 -ly 125 -lz 250 -center 62.5,62.5,187.5 -rc 100. -thetaC -35. -ksp_atol 1e-4 -ksp_rtol 1e-3 -ksp_type bcgs -snes_atol 1e-3 -snes_lag_jacobian 100 -snes_lag_jacobian_persists -snes_mf_operator -ts_dt 1e-3 -implicit -ts_type alpha 36 //TESTARGS -ceed {ceed_resource} -test implicit_stab_supg -degree 3 -dm_plex_box_faces 1,1,2 -units_kilogram 1e-9 -lx 125 -ly 125 -lz 250 -center 62.5,62.5,187.5 -rc 100. -thetaC -35. -ksp_atol 1e-4 -ksp_rtol 1e-3 -ksp_type bcgs -snes_atol 1e-3 -snes_lag_jacobian 100 -snes_lag_jacobian_persists -snes_mf_operator -ts_dt 1e-3 -implicit -ts_type alpha -stab supg 37 38 /// @file 39 /// Navier-Stokes example using PETSc 40 41 const char help[] = "Solve Navier-Stokes using PETSc and libCEED\n"; 42 43 #include <petscts.h> 44 #include <petscdmplex.h> 45 #include <ceed.h> 46 #include <stdbool.h> 47 #include <petscsys.h> 48 #include "common.h" 49 #include "advection.h" 50 #include "advection2d.h" 51 #include "densitycurrent.h" 52 53 // MemType Options 54 static const char *const memTypes[] = { 55 "host", 56 "device", 57 "memType", "CEED_MEM_", NULL 58 }; 59 60 // Problem Options 61 typedef enum { 62 NS_DENSITY_CURRENT = 0, 63 NS_ADVECTION = 1, 64 NS_ADVECTION2D = 2, 65 } problemType; 66 static const char *const problemTypes[] = { 67 "density_current", 68 "advection", 69 "advection2d", 70 "problemType", "NS_", NULL 71 }; 72 73 typedef enum { 74 STAB_NONE = 0, 75 STAB_SU = 1, // Streamline Upwind 76 STAB_SUPG = 2, // Streamline Upwind Petrov-Galerkin 77 } StabilizationType; 78 static const char *const StabilizationTypes[] = { 79 "NONE", 80 "SU", 81 "SUPG", 82 "StabilizationType", "STAB_", NULL 83 }; 84 85 // Test Options 86 typedef enum { 87 TEST_NONE = 0, // Non test mode 88 TEST_EXPLICIT = 1, // Explicit test 89 TEST_IMPLICIT_STAB_NONE = 2, // Implicit test no stab 90 TEST_IMPLICIT_STAB_SUPG = 3, // Implicit test supg stab 91 } testType; 92 static const char *const testTypes[] = { 93 "none", 94 "explicit", 95 "implicit_stab_none", 96 "implicit_stab_supg", 97 "testType", "TEST_", NULL 98 }; 99 100 // Tests specific data 101 typedef struct { 102 PetscScalar testtol; 103 const char *filepath; 104 } testData; 105 106 testData testOptions[] = { 107 [TEST_NONE] = { 108 .testtol = 0., 109 .filepath = NULL 110 }, 111 [TEST_EXPLICIT] = { 112 .testtol = 1E-5, 113 .filepath = "examples/fluids/tests-output/fluids-navierstokes-explicit.bin" 114 }, 115 [TEST_IMPLICIT_STAB_NONE] = { 116 .testtol = 5E-4, 117 .filepath = "examples/fluids/tests-output/fluids-navierstokes-implicit-stab-none.bin" 118 }, 119 [TEST_IMPLICIT_STAB_SUPG] = { 120 .testtol = 5E-4, 121 .filepath = "examples/fluids/tests-output/fluids-navierstokes-implicit-stab-supg.bin" 122 } 123 }; 124 125 // Problem specific data 126 typedef struct { 127 CeedInt dim, qdatasize; 128 CeedQFunctionUser setup, ics, apply_rhs, apply_ifunction; 129 PetscErrorCode (*bc)(PetscInt, PetscReal, const PetscReal[], PetscInt, 130 PetscScalar[], void *); 131 const char *setup_loc, *ics_loc, *apply_rhs_loc, *apply_ifunction_loc; 132 const bool non_zero_time; 133 } problemData; 134 135 problemData problemOptions[] = { 136 [NS_DENSITY_CURRENT] = { 137 .dim = 3, 138 .qdatasize = 10, 139 .setup = Setup, 140 .setup_loc = Setup_loc, 141 .ics = ICsDC, 142 .ics_loc = ICsDC_loc, 143 .apply_rhs = DC, 144 .apply_rhs_loc = DC_loc, 145 .apply_ifunction = IFunction_DC, 146 .apply_ifunction_loc = IFunction_DC_loc, 147 .bc = Exact_DC, 148 .non_zero_time = PETSC_FALSE, 149 }, 150 [NS_ADVECTION] = { 151 .dim = 3, 152 .qdatasize = 10, 153 .setup = Setup, 154 .setup_loc = Setup_loc, 155 .ics = ICsAdvection, 156 .ics_loc = ICsAdvection_loc, 157 .apply_rhs = Advection, 158 .apply_rhs_loc = Advection_loc, 159 .apply_ifunction = IFunction_Advection, 160 .apply_ifunction_loc = IFunction_Advection_loc, 161 .bc = Exact_Advection, 162 .non_zero_time = PETSC_FALSE, 163 }, 164 [NS_ADVECTION2D] = { 165 .dim = 2, 166 .qdatasize = 5, 167 .setup = Setup2d, 168 .setup_loc = Setup2d_loc, 169 .ics = ICsAdvection2d, 170 .ics_loc = ICsAdvection2d_loc, 171 .apply_rhs = Advection2d, 172 .apply_rhs_loc = Advection2d_loc, 173 .apply_ifunction = IFunction_Advection2d, 174 .apply_ifunction_loc = IFunction_Advection2d_loc, 175 .bc = Exact_Advection2d, 176 .non_zero_time = PETSC_TRUE, 177 }, 178 }; 179 180 // PETSc user data 181 typedef struct User_ *User; 182 typedef struct Units_ *Units; 183 184 struct User_ { 185 MPI_Comm comm; 186 PetscInt outputfreq; 187 DM dm; 188 DM dmviz; 189 Mat interpviz; 190 Ceed ceed; 191 Units units; 192 CeedVector qceed, qdotceed, gceed; 193 CeedOperator op_rhs, op_ifunction; 194 Vec M; 195 char outputfolder[PETSC_MAX_PATH_LEN]; 196 PetscInt contsteps; 197 }; 198 199 struct Units_ { 200 // fundamental units 201 PetscScalar meter; 202 PetscScalar kilogram; 203 PetscScalar second; 204 PetscScalar Kelvin; 205 // derived units 206 PetscScalar Pascal; 207 PetscScalar JperkgK; 208 PetscScalar mpersquareds; 209 PetscScalar WpermK; 210 PetscScalar kgpercubicm; 211 PetscScalar kgpersquaredms; 212 PetscScalar Joulepercubicm; 213 }; 214 215 typedef struct SimpleBC_ *SimpleBC; 216 struct SimpleBC_ { 217 PetscInt nwall, nslip[3]; 218 PetscInt walls[6], slips[3][6]; 219 PetscBool userbc; 220 }; 221 222 // Essential BC dofs are encoded in closure indices as -(i+1). 223 static PetscInt Involute(PetscInt i) { 224 return i >= 0 ? i : -(i+1); 225 } 226 227 // Utility function to create local CEED restriction 228 static PetscErrorCode CreateRestrictionFromPlex(Ceed ceed, DM dm, CeedInt P, 229 CeedElemRestriction *Erestrict) { 230 231 PetscSection section; 232 PetscInt c, cStart, cEnd, Nelem, Ndof, *erestrict, eoffset, nfields, dim; 233 PetscErrorCode ierr; 234 Vec Uloc; 235 236 PetscFunctionBeginUser; 237 ierr = DMGetDimension(dm, &dim); CHKERRQ(ierr); 238 ierr = DMGetLocalSection(dm,§ion); CHKERRQ(ierr); 239 ierr = PetscSectionGetNumFields(section, &nfields); CHKERRQ(ierr); 240 PetscInt ncomp[nfields], fieldoff[nfields+1]; 241 fieldoff[0] = 0; 242 for (PetscInt f=0; f<nfields; f++) { 243 ierr = PetscSectionGetFieldComponents(section, f, &ncomp[f]); CHKERRQ(ierr); 244 fieldoff[f+1] = fieldoff[f] + ncomp[f]; 245 } 246 247 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd); CHKERRQ(ierr); 248 Nelem = cEnd - cStart; 249 ierr = PetscMalloc1(Nelem*PetscPowInt(P, dim), &erestrict); CHKERRQ(ierr); 250 for (c=cStart,eoffset=0; c<cEnd; c++) { 251 PetscInt numindices, *indices, nnodes; 252 ierr = DMPlexGetClosureIndices(dm, section, section, c, &numindices, 253 &indices, NULL); CHKERRQ(ierr); 254 if (numindices % fieldoff[nfields]) SETERRQ1(PETSC_COMM_SELF, 255 PETSC_ERR_ARG_INCOMP, "Number of closure indices not compatible with Cell %D", 256 c); 257 nnodes = numindices / fieldoff[nfields]; 258 for (PetscInt i=0; i<nnodes; i++) { 259 // Check that indices are blocked by node and thus can be coalesced as a single field with 260 // fieldoff[nfields] = sum(ncomp) components. 261 for (PetscInt f=0; f<nfields; f++) { 262 for (PetscInt j=0; j<ncomp[f]; j++) { 263 if (Involute(indices[fieldoff[f]*nnodes + i*ncomp[f] + j]) 264 != Involute(indices[i*ncomp[0]]) + fieldoff[f] + j) 265 SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP, 266 "Cell %D closure indices not interlaced for node %D field %D component %D", 267 c, i, f, j); 268 } 269 } 270 // Essential boundary conditions are encoded as -(loc+1), but we don't care so we decode. 271 PetscInt loc = Involute(indices[i*ncomp[0]]); 272 erestrict[eoffset++] = loc / fieldoff[nfields]; 273 } 274 ierr = DMPlexRestoreClosureIndices(dm, section, section, c, &numindices, 275 &indices, NULL); CHKERRQ(ierr); 276 } 277 if (eoffset != Nelem*PetscPowInt(P, dim)) SETERRQ3(PETSC_COMM_SELF, 278 PETSC_ERR_LIB, "ElemRestriction of size (%D,%D) initialized %D nodes", Nelem, 279 PetscPowInt(P, dim),eoffset); 280 ierr = DMGetLocalVector(dm, &Uloc); CHKERRQ(ierr); 281 ierr = VecGetLocalSize(Uloc, &Ndof); CHKERRQ(ierr); 282 ierr = DMRestoreLocalVector(dm, &Uloc); CHKERRQ(ierr); 283 CeedElemRestrictionCreate(ceed, CEED_INTERLACED, Nelem, PetscPowInt(P, dim), 284 Ndof/fieldoff[nfields], fieldoff[nfields], 285 CEED_MEM_HOST, CEED_COPY_VALUES, erestrict, Erestrict); 286 ierr = PetscFree(erestrict); CHKERRQ(ierr); 287 PetscFunctionReturn(0); 288 } 289 290 static int CreateVectorFromPetscVec(Ceed ceed, Vec p, CeedVector *v) { 291 PetscErrorCode ierr; 292 PetscInt m; 293 294 PetscFunctionBeginUser; 295 ierr = VecGetLocalSize(p, &m); CHKERRQ(ierr); 296 ierr = CeedVectorCreate(ceed, m, v); CHKERRQ(ierr); 297 PetscFunctionReturn(0); 298 } 299 300 static int VectorPlacePetscVec(CeedVector c, Vec p) { 301 PetscErrorCode ierr; 302 PetscInt mceed,mpetsc; 303 PetscScalar *a; 304 305 PetscFunctionBeginUser; 306 ierr = CeedVectorGetLength(c, &mceed); CHKERRQ(ierr); 307 ierr = VecGetLocalSize(p, &mpetsc); CHKERRQ(ierr); 308 if (mceed != mpetsc) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP, 309 "Cannot place PETSc Vec of length %D in CeedVector of length %D", 310 mpetsc, mceed); 311 ierr = VecGetArray(p, &a); CHKERRQ(ierr); 312 CeedVectorSetArray(c, CEED_MEM_HOST, CEED_USE_POINTER, a); 313 PetscFunctionReturn(0); 314 } 315 316 static PetscErrorCode DMPlexInsertBoundaryValues_NS(DM dm, 317 PetscBool insertEssential, Vec Qloc, PetscReal time, Vec faceGeomFVM, 318 Vec cellGeomFVM, Vec gradFVM) { 319 PetscErrorCode ierr; 320 Vec Qbc; 321 322 PetscFunctionBegin; 323 ierr = DMGetNamedLocalVector(dm, "Qbc", &Qbc); CHKERRQ(ierr); 324 ierr = VecAXPY(Qloc, 1., Qbc); CHKERRQ(ierr); 325 ierr = DMRestoreNamedLocalVector(dm, "Qbc", &Qbc); CHKERRQ(ierr); 326 PetscFunctionReturn(0); 327 } 328 329 // This is the RHS of the ODE, given as u_t = G(t,u) 330 // This function takes in a state vector Q and writes into G 331 static PetscErrorCode RHS_NS(TS ts, PetscReal t, Vec Q, Vec G, void *userData) { 332 PetscErrorCode ierr; 333 User user = *(User *)userData; 334 PetscScalar *q, *g; 335 Vec Qloc, Gloc; 336 337 // Global-to-local 338 PetscFunctionBeginUser; 339 ierr = DMGetLocalVector(user->dm, &Qloc); CHKERRQ(ierr); 340 ierr = DMGetLocalVector(user->dm, &Gloc); CHKERRQ(ierr); 341 ierr = VecZeroEntries(Qloc); CHKERRQ(ierr); 342 ierr = DMGlobalToLocal(user->dm, Q, INSERT_VALUES, Qloc); CHKERRQ(ierr); 343 ierr = DMPlexInsertBoundaryValues(user->dm, PETSC_TRUE, Qloc, 0.0, 344 NULL, NULL, NULL); CHKERRQ(ierr); 345 ierr = VecZeroEntries(Gloc); CHKERRQ(ierr); 346 347 // Ceed Vectors 348 ierr = VecGetArrayRead(Qloc, (const PetscScalar **)&q); CHKERRQ(ierr); 349 ierr = VecGetArray(Gloc, &g); CHKERRQ(ierr); 350 CeedVectorSetArray(user->qceed, CEED_MEM_HOST, CEED_USE_POINTER, q); 351 CeedVectorSetArray(user->gceed, CEED_MEM_HOST, CEED_USE_POINTER, g); 352 353 // Apply CEED operator 354 CeedOperatorApply(user->op_rhs, user->qceed, user->gceed, 355 CEED_REQUEST_IMMEDIATE); 356 357 // Restore vectors 358 ierr = VecRestoreArrayRead(Qloc, (const PetscScalar **)&q); CHKERRQ(ierr); 359 ierr = VecRestoreArray(Gloc, &g); CHKERRQ(ierr); 360 361 ierr = VecZeroEntries(G); CHKERRQ(ierr); 362 ierr = DMLocalToGlobal(user->dm, Gloc, ADD_VALUES, G); CHKERRQ(ierr); 363 364 // Inverse of the lumped mass matrix 365 ierr = VecPointwiseMult(G, G, user->M); // M is Minv 366 CHKERRQ(ierr); 367 368 ierr = DMRestoreLocalVector(user->dm, &Qloc); CHKERRQ(ierr); 369 ierr = DMRestoreLocalVector(user->dm, &Gloc); CHKERRQ(ierr); 370 PetscFunctionReturn(0); 371 } 372 373 static PetscErrorCode IFunction_NS(TS ts, PetscReal t, Vec Q, Vec Qdot, Vec G, 374 void *userData) { 375 PetscErrorCode ierr; 376 User user = *(User *)userData; 377 const PetscScalar *q, *qdot; 378 PetscScalar *g; 379 Vec Qloc, Qdotloc, Gloc; 380 381 // Global-to-local 382 PetscFunctionBeginUser; 383 ierr = DMGetLocalVector(user->dm, &Qloc); CHKERRQ(ierr); 384 ierr = DMGetLocalVector(user->dm, &Qdotloc); CHKERRQ(ierr); 385 ierr = DMGetLocalVector(user->dm, &Gloc); CHKERRQ(ierr); 386 ierr = VecZeroEntries(Qloc); CHKERRQ(ierr); 387 ierr = DMGlobalToLocal(user->dm, Q, INSERT_VALUES, Qloc); CHKERRQ(ierr); 388 ierr = DMPlexInsertBoundaryValues(user->dm, PETSC_TRUE, Qloc, 0.0, 389 NULL, NULL, NULL); CHKERRQ(ierr); 390 ierr = VecZeroEntries(Qdotloc); CHKERRQ(ierr); 391 ierr = DMGlobalToLocal(user->dm, Qdot, INSERT_VALUES, Qdotloc); CHKERRQ(ierr); 392 ierr = VecZeroEntries(Gloc); CHKERRQ(ierr); 393 394 // Ceed Vectors 395 ierr = VecGetArrayRead(Qloc, &q); CHKERRQ(ierr); 396 ierr = VecGetArrayRead(Qdotloc, &qdot); CHKERRQ(ierr); 397 ierr = VecGetArray(Gloc, &g); CHKERRQ(ierr); 398 CeedVectorSetArray(user->qceed, CEED_MEM_HOST, CEED_USE_POINTER, 399 (PetscScalar *)q); 400 CeedVectorSetArray(user->qdotceed, CEED_MEM_HOST, CEED_USE_POINTER, 401 (PetscScalar *)qdot); 402 CeedVectorSetArray(user->gceed, CEED_MEM_HOST, CEED_USE_POINTER, g); 403 404 // Apply CEED operator 405 CeedOperatorApply(user->op_ifunction, user->qceed, user->gceed, 406 CEED_REQUEST_IMMEDIATE); 407 408 // Restore vectors 409 ierr = VecRestoreArrayRead(Qloc, &q); CHKERRQ(ierr); 410 ierr = VecRestoreArrayRead(Qdotloc, &qdot); CHKERRQ(ierr); 411 ierr = VecRestoreArray(Gloc, &g); CHKERRQ(ierr); 412 413 ierr = VecZeroEntries(G); CHKERRQ(ierr); 414 ierr = DMLocalToGlobal(user->dm, Gloc, ADD_VALUES, G); CHKERRQ(ierr); 415 416 ierr = DMRestoreLocalVector(user->dm, &Qloc); CHKERRQ(ierr); 417 ierr = DMRestoreLocalVector(user->dm, &Qdotloc); CHKERRQ(ierr); 418 ierr = DMRestoreLocalVector(user->dm, &Gloc); CHKERRQ(ierr); 419 PetscFunctionReturn(0); 420 } 421 422 // User provided TS Monitor 423 static PetscErrorCode TSMonitor_NS(TS ts, PetscInt stepno, PetscReal time, 424 Vec Q, void *ctx) { 425 User user = ctx; 426 Vec Qloc; 427 char filepath[PETSC_MAX_PATH_LEN]; 428 PetscViewer viewer; 429 PetscErrorCode ierr; 430 431 // Set up output 432 PetscFunctionBeginUser; 433 // Print every 'outputfreq' steps 434 if (stepno % user->outputfreq != 0) 435 PetscFunctionReturn(0); 436 ierr = DMGetLocalVector(user->dm, &Qloc); CHKERRQ(ierr); 437 ierr = PetscObjectSetName((PetscObject)Qloc, "StateVec"); CHKERRQ(ierr); 438 ierr = VecZeroEntries(Qloc); CHKERRQ(ierr); 439 ierr = DMGlobalToLocal(user->dm, Q, INSERT_VALUES, Qloc); CHKERRQ(ierr); 440 441 // Output 442 ierr = PetscSNPrintf(filepath, sizeof filepath, "%s/ns-%03D.vtu", 443 user->outputfolder, stepno + user->contsteps); 444 CHKERRQ(ierr); 445 ierr = PetscViewerVTKOpen(PetscObjectComm((PetscObject)Q), filepath, 446 FILE_MODE_WRITE, &viewer); CHKERRQ(ierr); 447 ierr = VecView(Qloc, viewer); CHKERRQ(ierr); 448 if (user->dmviz) { 449 Vec Qrefined, Qrefined_loc; 450 char filepath_refined[PETSC_MAX_PATH_LEN]; 451 PetscViewer viewer_refined; 452 453 ierr = DMGetGlobalVector(user->dmviz, &Qrefined); CHKERRQ(ierr); 454 ierr = DMGetLocalVector(user->dmviz, &Qrefined_loc); CHKERRQ(ierr); 455 ierr = PetscObjectSetName((PetscObject)Qrefined_loc, "Refined"); 456 CHKERRQ(ierr); 457 ierr = MatInterpolate(user->interpviz, Q, Qrefined); CHKERRQ(ierr); 458 ierr = VecZeroEntries(Qrefined_loc); CHKERRQ(ierr); 459 ierr = DMGlobalToLocal(user->dmviz, Qrefined, INSERT_VALUES, Qrefined_loc); 460 CHKERRQ(ierr); 461 ierr = PetscSNPrintf(filepath_refined, sizeof filepath_refined, 462 "%s/nsrefined-%03D.vtu", 463 user->outputfolder, stepno + user->contsteps); 464 CHKERRQ(ierr); 465 ierr = PetscViewerVTKOpen(PetscObjectComm((PetscObject)Qrefined), 466 filepath_refined, 467 FILE_MODE_WRITE, &viewer_refined); CHKERRQ(ierr); 468 ierr = VecView(Qrefined_loc, viewer_refined); CHKERRQ(ierr); 469 ierr = DMRestoreLocalVector(user->dmviz, &Qrefined_loc); CHKERRQ(ierr); 470 ierr = DMRestoreGlobalVector(user->dmviz, &Qrefined); CHKERRQ(ierr); 471 ierr = PetscViewerDestroy(&viewer_refined); CHKERRQ(ierr); 472 } 473 ierr = DMRestoreLocalVector(user->dm, &Qloc); CHKERRQ(ierr); 474 475 // Save data in a binary file for continuation of simulations 476 ierr = PetscSNPrintf(filepath, sizeof filepath, "%s/ns-solution.bin", 477 user->outputfolder); CHKERRQ(ierr); 478 ierr = PetscViewerBinaryOpen(user->comm, filepath, FILE_MODE_WRITE, &viewer); 479 CHKERRQ(ierr); 480 ierr = VecView(Q, viewer); CHKERRQ(ierr); 481 ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr); 482 483 // Save time stamp 484 // Dimensionalize time back 485 time /= user->units->second; 486 ierr = PetscSNPrintf(filepath, sizeof filepath, "%s/ns-time.bin", 487 user->outputfolder); CHKERRQ(ierr); 488 ierr = PetscViewerBinaryOpen(user->comm, filepath, FILE_MODE_WRITE, &viewer); 489 CHKERRQ(ierr); 490 #if PETSC_VERSION_GE(3,13,0) 491 ierr = PetscViewerBinaryWrite(viewer, &time, 1, PETSC_REAL); 492 #else 493 ierr = PetscViewerBinaryWrite(viewer, &time, 1, PETSC_REAL, true); 494 #endif 495 CHKERRQ(ierr); 496 ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr); 497 498 PetscFunctionReturn(0); 499 } 500 501 static PetscErrorCode ICs_FixMultiplicity(CeedOperator op_ics, 502 CeedVector xcorners, CeedVector q0ceed, DM dm, Vec Qloc, Vec Q, 503 CeedElemRestriction restrictq, SetupContext ctxSetup, CeedScalar time) { 504 PetscErrorCode ierr; 505 CeedVector multlvec; 506 Vec Multiplicity, MultiplicityLoc; 507 508 ctxSetup->time = time; 509 ierr = VecZeroEntries(Qloc); CHKERRQ(ierr); 510 ierr = VectorPlacePetscVec(q0ceed, Qloc); CHKERRQ(ierr); 511 CeedOperatorApply(op_ics, xcorners, q0ceed, CEED_REQUEST_IMMEDIATE); 512 ierr = VecZeroEntries(Q); CHKERRQ(ierr); 513 ierr = DMLocalToGlobal(dm, Qloc, ADD_VALUES, Q); CHKERRQ(ierr); 514 515 // Fix multiplicity for output of ICs 516 ierr = DMGetLocalVector(dm, &MultiplicityLoc); CHKERRQ(ierr); 517 CeedElemRestrictionCreateVector(restrictq, &multlvec, NULL); 518 ierr = VectorPlacePetscVec(multlvec, MultiplicityLoc); CHKERRQ(ierr); 519 CeedElemRestrictionGetMultiplicity(restrictq, multlvec); 520 CeedVectorDestroy(&multlvec); 521 ierr = DMGetGlobalVector(dm, &Multiplicity); CHKERRQ(ierr); 522 ierr = VecZeroEntries(Multiplicity); CHKERRQ(ierr); 523 ierr = DMLocalToGlobal(dm, MultiplicityLoc, ADD_VALUES, Multiplicity); 524 CHKERRQ(ierr); 525 ierr = VecPointwiseDivide(Q, Q, Multiplicity); CHKERRQ(ierr); 526 ierr = VecPointwiseDivide(Qloc, Qloc, MultiplicityLoc); CHKERRQ(ierr); 527 ierr = DMRestoreLocalVector(dm, &MultiplicityLoc); CHKERRQ(ierr); 528 ierr = DMRestoreGlobalVector(dm, &Multiplicity); CHKERRQ(ierr); 529 530 PetscFunctionReturn(0); 531 } 532 533 static PetscErrorCode ComputeLumpedMassMatrix(Ceed ceed, DM dm, 534 CeedElemRestriction restrictq, CeedBasis basisq, 535 CeedElemRestriction restrictqdi, CeedVector qdata, Vec M) { 536 PetscErrorCode ierr; 537 CeedQFunction qf_mass; 538 CeedOperator op_mass; 539 CeedVector mceed; 540 Vec Mloc; 541 CeedInt ncompq, qdatasize; 542 543 PetscFunctionBeginUser; 544 CeedElemRestrictionGetNumComponents(restrictq, &ncompq); 545 CeedElemRestrictionGetNumComponents(restrictqdi, &qdatasize); 546 // Create the Q-function that defines the action of the mass operator 547 CeedQFunctionCreateInterior(ceed, 1, Mass, Mass_loc, &qf_mass); 548 CeedQFunctionAddInput(qf_mass, "q", ncompq, CEED_EVAL_INTERP); 549 CeedQFunctionAddInput(qf_mass, "qdata", qdatasize, CEED_EVAL_NONE); 550 CeedQFunctionAddOutput(qf_mass, "v", ncompq, CEED_EVAL_INTERP); 551 552 // Create the mass operator 553 CeedOperatorCreate(ceed, qf_mass, NULL, NULL, &op_mass); 554 CeedOperatorSetField(op_mass, "q", restrictq, basisq, CEED_VECTOR_ACTIVE); 555 CeedOperatorSetField(op_mass, "qdata", restrictqdi, 556 CEED_BASIS_COLLOCATED, qdata); 557 CeedOperatorSetField(op_mass, "v", restrictq, basisq, CEED_VECTOR_ACTIVE); 558 559 ierr = DMGetLocalVector(dm, &Mloc); CHKERRQ(ierr); 560 ierr = VecZeroEntries(Mloc); CHKERRQ(ierr); 561 CeedElemRestrictionCreateVector(restrictq, &mceed, NULL); 562 ierr = VectorPlacePetscVec(mceed, Mloc); CHKERRQ(ierr); 563 564 { 565 // Compute a lumped mass matrix 566 CeedVector onesvec; 567 CeedElemRestrictionCreateVector(restrictq, &onesvec, NULL); 568 CeedVectorSetValue(onesvec, 1.0); 569 CeedOperatorApply(op_mass, onesvec, mceed, CEED_REQUEST_IMMEDIATE); 570 CeedVectorDestroy(&onesvec); 571 CeedOperatorDestroy(&op_mass); 572 CeedVectorDestroy(&mceed); 573 } 574 CeedQFunctionDestroy(&qf_mass); 575 576 ierr = VecZeroEntries(M); CHKERRQ(ierr); 577 ierr = DMLocalToGlobal(dm, Mloc, ADD_VALUES, M); CHKERRQ(ierr); 578 ierr = DMRestoreLocalVector(dm, &Mloc); CHKERRQ(ierr); 579 580 // Invert diagonally lumped mass vector for RHS function 581 ierr = VecReciprocal(M); CHKERRQ(ierr); 582 PetscFunctionReturn(0); 583 } 584 585 static PetscErrorCode SetUpDM(DM dm, problemData *problem, PetscInt degree, 586 SimpleBC bc, void *ctxSetup) { 587 PetscErrorCode ierr; 588 589 PetscFunctionBeginUser; 590 { 591 // Configure the finite element space and boundary conditions 592 PetscFE fe; 593 PetscInt ncompq = 5; 594 ierr = PetscFECreateLagrange(PETSC_COMM_SELF, problem->dim, ncompq, 595 PETSC_FALSE, degree, PETSC_DECIDE, 596 &fe); 597 ierr = PetscObjectSetName((PetscObject)fe, "Q"); CHKERRQ(ierr); 598 ierr = DMAddField(dm,NULL,(PetscObject)fe); CHKERRQ(ierr); 599 ierr = DMCreateDS(dm); CHKERRQ(ierr); 600 { 601 PetscInt comps[1] = {1}; 602 ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "slipx", "Face Sets", 0, 603 1, comps, (void(*)(void))NULL, bc->nslip[0], 604 bc->slips[0], ctxSetup); CHKERRQ(ierr); 605 comps[0] = 2; 606 ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "slipy", "Face Sets", 0, 607 1, comps, (void(*)(void))NULL, bc->nslip[1], 608 bc->slips[1], ctxSetup); CHKERRQ(ierr); 609 comps[0] = 3; 610 ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "slipz", "Face Sets", 0, 611 1, comps, (void(*)(void))NULL, bc->nslip[2], 612 bc->slips[2], ctxSetup); CHKERRQ(ierr); 613 } 614 if (bc->userbc == PETSC_TRUE) { 615 for (PetscInt c = 0; c < 3; c++) { 616 for (PetscInt s = 0; s < bc->nslip[c]; s++) { 617 for (PetscInt w = 0; w < bc->nwall; w++) { 618 if (bc->slips[c][s] == bc->walls[w]) 619 SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, 620 "Boundary condition already set on face %D!\n", bc->walls[w]); 621 622 } 623 } 624 } 625 } 626 // Wall boundary conditions are zero energy density and zero flux for 627 // velocity in advection/advection2d, and zero velocity and zero flux 628 // for mass density and energy density in density_current 629 { 630 if (problem->bc == Exact_Advection || problem->bc == Exact_Advection2d) { 631 PetscInt comps[1] = {4}; 632 ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", "Face Sets", 0, 633 1, comps, (void(*)(void))problem->bc, 634 bc->nwall, bc->walls, ctxSetup); CHKERRQ(ierr); 635 } else if (problem->bc == Exact_DC) { 636 PetscInt comps[3] = {1, 2, 3}; 637 ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", "Face Sets", 0, 638 3, comps, (void(*)(void))problem->bc, 639 bc->nwall, bc->walls, ctxSetup); CHKERRQ(ierr); 640 } else 641 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, 642 "Undefined boundary conditions for this problem"); 643 } 644 ierr = DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL); 645 CHKERRQ(ierr); 646 ierr = PetscFEDestroy(&fe); CHKERRQ(ierr); 647 } 648 { 649 // Empty name for conserved field (because there is only one field) 650 PetscSection section; 651 ierr = DMGetLocalSection(dm, §ion); CHKERRQ(ierr); 652 ierr = PetscSectionSetFieldName(section, 0, ""); CHKERRQ(ierr); 653 ierr = PetscSectionSetComponentName(section, 0, 0, "Density"); 654 CHKERRQ(ierr); 655 ierr = PetscSectionSetComponentName(section, 0, 1, "MomentumX"); 656 CHKERRQ(ierr); 657 ierr = PetscSectionSetComponentName(section, 0, 2, "MomentumY"); 658 CHKERRQ(ierr); 659 ierr = PetscSectionSetComponentName(section, 0, 3, "MomentumZ"); 660 CHKERRQ(ierr); 661 ierr = PetscSectionSetComponentName(section, 0, 4, "EnergyDensity"); 662 CHKERRQ(ierr); 663 } 664 PetscFunctionReturn(0); 665 } 666 667 int main(int argc, char **argv) { 668 PetscInt ierr; 669 MPI_Comm comm; 670 DM dm, dmcoord, dmviz; 671 Mat interpviz; 672 TS ts; 673 TSAdapt adapt; 674 User user; 675 Units units; 676 char ceedresource[4096] = "/cpu/self"; 677 PetscInt cStart, cEnd, localNelem, lnodes, gnodes, steps; 678 const PetscInt ncompq = 5; 679 PetscMPIInt rank; 680 PetscScalar ftime; 681 Vec Q, Qloc, Xloc; 682 Ceed ceed; 683 CeedInt numP, numQ; 684 CeedVector xcorners, qdata, q0ceed; 685 CeedBasis basisx, basisxc, basisq; 686 CeedElemRestriction restrictx, restrictxcoord, restrictq, restrictqdi; 687 CeedQFunction qf_setup, qf_ics, qf_rhs, qf_ifunction; 688 CeedOperator op_setup, op_ics; 689 CeedScalar Rd; 690 CeedMemType memtyperequested; 691 PetscScalar WpermK, Pascal, JperkgK, mpersquareds, kgpercubicm, 692 kgpersquaredms, Joulepercubicm; 693 problemType problemChoice; 694 problemData *problem = NULL; 695 StabilizationType stab; 696 testType testChoice; 697 testData *test = NULL; 698 PetscBool implicit; 699 PetscInt viz_refine = 0; 700 struct SimpleBC_ bc = { 701 .nslip = {2, 2, 2}, 702 .slips = {{5, 6}, {3, 4}, {1, 2}} 703 }; 704 double start, cpu_time_used; 705 // Check PETSc CUDA support 706 PetscBool petschavecuda, setmemtyperequest = PETSC_FALSE; 707 // *INDENT-OFF* 708 #ifdef PETSC_HAVE_CUDA 709 petschavecuda = PETSC_TRUE; 710 #else 711 petschavecuda = PETSC_FALSE; 712 #endif 713 // *INDENT-ON* 714 715 // Create the libCEED contexts 716 PetscScalar meter = 1e-2; // 1 meter in scaled length units 717 PetscScalar second = 1e-2; // 1 second in scaled time units 718 PetscScalar kilogram = 1e-6; // 1 kilogram in scaled mass units 719 PetscScalar Kelvin = 1; // 1 Kelvin in scaled temperature units 720 CeedScalar theta0 = 300.; // K 721 CeedScalar thetaC = -15.; // K 722 CeedScalar P0 = 1.e5; // Pa 723 CeedScalar N = 0.01; // 1/s 724 CeedScalar cv = 717.; // J/(kg K) 725 CeedScalar cp = 1004.; // J/(kg K) 726 CeedScalar g = 9.81; // m/s^2 727 CeedScalar lambda = -2./3.; // - 728 CeedScalar mu = 75.; // Pa s, dynamic viscosity 729 // mu = 75 is not physical for air, but is good for numerical stability 730 CeedScalar k = 0.02638; // W/(m K) 731 CeedScalar CtauS = 0.; // dimensionless 732 CeedScalar strong_form = 0.; // [0,1] 733 PetscScalar lx = 8000.; // m 734 PetscScalar ly = 8000.; // m 735 PetscScalar lz = 4000.; // m 736 CeedScalar rc = 1000.; // m (Radius of bubble) 737 PetscScalar resx = 1000.; // m (resolution in x) 738 PetscScalar resy = 1000.; // m (resolution in y) 739 PetscScalar resz = 1000.; // m (resolution in z) 740 PetscInt outputfreq = 10; // - 741 PetscInt contsteps = 0; // - 742 PetscInt degree = 1; // - 743 PetscInt qextra = 2; // - 744 PetscReal center[3], dc_axis[3] = {0, 0, 0}; 745 746 ierr = PetscInitialize(&argc, &argv, NULL, help); 747 if (ierr) return ierr; 748 749 // Allocate PETSc context 750 ierr = PetscCalloc1(1, &user); CHKERRQ(ierr); 751 ierr = PetscMalloc1(1, &units); CHKERRQ(ierr); 752 753 // Parse command line options 754 comm = PETSC_COMM_WORLD; 755 ierr = PetscOptionsBegin(comm, NULL, "Navier-Stokes in PETSc with libCEED", 756 NULL); CHKERRQ(ierr); 757 ierr = PetscOptionsString("-ceed", "CEED resource specifier", 758 NULL, ceedresource, ceedresource, 759 sizeof(ceedresource), NULL); CHKERRQ(ierr); 760 testChoice = TEST_NONE; 761 ierr = PetscOptionsEnum("-test", "Run tests", NULL, 762 testTypes, (PetscEnum)testChoice, 763 (PetscEnum *)&testChoice, 764 NULL); CHKERRQ(ierr); 765 test = &testOptions[testChoice]; 766 problemChoice = NS_DENSITY_CURRENT; 767 ierr = PetscOptionsEnum("-problem", "Problem to solve", NULL, 768 problemTypes, (PetscEnum)problemChoice, 769 (PetscEnum *)&problemChoice, NULL); CHKERRQ(ierr); 770 problem = &problemOptions[problemChoice]; 771 ierr = PetscOptionsEnum("-stab", "Stabilization method", NULL, 772 StabilizationTypes, (PetscEnum)(stab = STAB_NONE), 773 (PetscEnum *)&stab, NULL); CHKERRQ(ierr); 774 ierr = PetscOptionsBool("-implicit", "Use implicit (IFunction) formulation", 775 NULL, implicit=PETSC_FALSE, &implicit, NULL); 776 CHKERRQ(ierr); 777 if (!implicit && stab != STAB_NONE) { 778 ierr = PetscPrintf(comm, "Warning! Use -stab only with -implicit\n"); 779 CHKERRQ(ierr); 780 } 781 { 782 PetscInt len; 783 PetscBool flg; 784 ierr = PetscOptionsIntArray("-bc_wall", 785 "Use wall boundary conditions on this list of faces", 786 NULL, bc.walls, 787 (len = sizeof(bc.walls) / sizeof(bc.walls[0]), 788 &len), &flg); CHKERRQ(ierr); 789 if (flg) bc.nwall = len; 790 for (PetscInt j=0; j<3; j++) { 791 const char *flags[3] = {"-bc_slip_x", "-bc_slip_y", "-bc_slip_z"}; 792 ierr = PetscOptionsIntArray(flags[j], 793 "Use slip boundary conditions on this list of faces", 794 NULL, bc.slips[j], 795 (len = sizeof(bc.slips[j]) / sizeof(bc.slips[j][0]), 796 &len), &flg); 797 CHKERRQ(ierr); 798 if (flg) { 799 bc.nslip[j] = len; 800 bc.userbc = PETSC_TRUE; 801 } 802 } 803 } 804 ierr = PetscOptionsInt("-viz_refine", 805 "Regular refinement levels for visualization", 806 NULL, viz_refine, &viz_refine, NULL); 807 CHKERRQ(ierr); 808 ierr = PetscOptionsScalar("-units_meter", "1 meter in scaled length units", 809 NULL, meter, &meter, NULL); CHKERRQ(ierr); 810 meter = fabs(meter); 811 ierr = PetscOptionsScalar("-units_second","1 second in scaled time units", 812 NULL, second, &second, NULL); CHKERRQ(ierr); 813 second = fabs(second); 814 ierr = PetscOptionsScalar("-units_kilogram","1 kilogram in scaled mass units", 815 NULL, kilogram, &kilogram, NULL); CHKERRQ(ierr); 816 kilogram = fabs(kilogram); 817 ierr = PetscOptionsScalar("-units_Kelvin", 818 "1 Kelvin in scaled temperature units", 819 NULL, Kelvin, &Kelvin, NULL); CHKERRQ(ierr); 820 Kelvin = fabs(Kelvin); 821 ierr = PetscOptionsScalar("-theta0", "Reference potential temperature", 822 NULL, theta0, &theta0, NULL); CHKERRQ(ierr); 823 ierr = PetscOptionsScalar("-thetaC", "Perturbation of potential temperature", 824 NULL, thetaC, &thetaC, NULL); CHKERRQ(ierr); 825 ierr = PetscOptionsScalar("-P0", "Atmospheric pressure", 826 NULL, P0, &P0, NULL); CHKERRQ(ierr); 827 ierr = PetscOptionsScalar("-N", "Brunt-Vaisala frequency", 828 NULL, N, &N, NULL); CHKERRQ(ierr); 829 ierr = PetscOptionsScalar("-cv", "Heat capacity at constant volume", 830 NULL, cv, &cv, NULL); CHKERRQ(ierr); 831 ierr = PetscOptionsScalar("-cp", "Heat capacity at constant pressure", 832 NULL, cp, &cp, NULL); CHKERRQ(ierr); 833 ierr = PetscOptionsScalar("-g", "Gravitational acceleration", 834 NULL, g, &g, NULL); CHKERRQ(ierr); 835 ierr = PetscOptionsScalar("-lambda", 836 "Stokes hypothesis second viscosity coefficient", 837 NULL, lambda, &lambda, NULL); CHKERRQ(ierr); 838 ierr = PetscOptionsScalar("-mu", "Shear dynamic viscosity coefficient", 839 NULL, mu, &mu, NULL); CHKERRQ(ierr); 840 ierr = PetscOptionsScalar("-k", "Thermal conductivity", 841 NULL, k, &k, NULL); CHKERRQ(ierr); 842 ierr = PetscOptionsScalar("-CtauS", 843 "Scale coefficient for tau (nondimensional)", 844 NULL, CtauS, &CtauS, NULL); CHKERRQ(ierr); 845 if (stab == STAB_NONE && CtauS != 0) { 846 ierr = PetscPrintf(comm, 847 "Warning! Use -CtauS only with -stab su or -stab supg\n"); 848 CHKERRQ(ierr); 849 } 850 ierr = PetscOptionsScalar("-strong_form", 851 "Strong (1) or weak/integrated by parts (0) advection residual", 852 NULL, strong_form, &strong_form, NULL); 853 CHKERRQ(ierr); 854 if (problemChoice == NS_DENSITY_CURRENT && (CtauS != 0 || strong_form != 0)) { 855 ierr = PetscPrintf(comm, 856 "Warning! Problem density_current does not support -CtauS or -strong_form\n"); 857 CHKERRQ(ierr); 858 } 859 ierr = PetscOptionsScalar("-lx", "Length scale in x direction", 860 NULL, lx, &lx, NULL); CHKERRQ(ierr); 861 ierr = PetscOptionsScalar("-ly", "Length scale in y direction", 862 NULL, ly, &ly, NULL); CHKERRQ(ierr); 863 ierr = PetscOptionsScalar("-lz", "Length scale in z direction", 864 NULL, lz, &lz, NULL); CHKERRQ(ierr); 865 ierr = PetscOptionsScalar("-rc", "Characteristic radius of thermal bubble", 866 NULL, rc, &rc, NULL); CHKERRQ(ierr); 867 ierr = PetscOptionsScalar("-resx","Target resolution in x", 868 NULL, resx, &resx, NULL); CHKERRQ(ierr); 869 ierr = PetscOptionsScalar("-resy","Target resolution in y", 870 NULL, resy, &resy, NULL); CHKERRQ(ierr); 871 ierr = PetscOptionsScalar("-resz","Target resolution in z", 872 NULL, resz, &resz, NULL); CHKERRQ(ierr); 873 PetscInt n = problem->dim; 874 center[0] = 0.5 * lx; 875 center[1] = 0.5 * ly; 876 center[2] = 0.5 * lz; 877 ierr = PetscOptionsRealArray("-center", "Location of bubble center", 878 NULL, center, &n, NULL); CHKERRQ(ierr); 879 n = problem->dim; 880 ierr = PetscOptionsRealArray("-dc_axis", 881 "Axis of density current cylindrical anomaly, or {0,0,0} for spherically symmetric", 882 NULL, dc_axis, &n, NULL); CHKERRQ(ierr); 883 { 884 PetscReal norm = PetscSqrtReal(PetscSqr(dc_axis[0]) + 885 PetscSqr(dc_axis[1]) + PetscSqr(dc_axis[2])); 886 if (norm > 0) { 887 for (int i=0; i<3; i++) dc_axis[i] /= norm; 888 } 889 } 890 ierr = PetscOptionsInt("-output_freq", 891 "Frequency of output, in number of steps", 892 NULL, outputfreq, &outputfreq, NULL); CHKERRQ(ierr); 893 ierr = PetscOptionsInt("-continue", "Continue from previous solution", 894 NULL, contsteps, &contsteps, NULL); CHKERRQ(ierr); 895 ierr = PetscOptionsInt("-degree", "Polynomial degree of finite elements", 896 NULL, degree, °ree, NULL); CHKERRQ(ierr); 897 ierr = PetscOptionsInt("-qextra", "Number of extra quadrature points", 898 NULL, qextra, &qextra, NULL); CHKERRQ(ierr); 899 ierr = PetscStrncpy(user->outputfolder, ".", 2); CHKERRQ(ierr); 900 ierr = PetscOptionsString("-of", "Output folder", 901 NULL, user->outputfolder, user->outputfolder, 902 sizeof(user->outputfolder), NULL); CHKERRQ(ierr); 903 memtyperequested = petschavecuda ? CEED_MEM_DEVICE : CEED_MEM_HOST; 904 ierr = PetscOptionsEnum("-memtype", 905 "CEED MemType requested", NULL, 906 memTypes, (PetscEnum)memtyperequested, 907 (PetscEnum *)&memtyperequested, &setmemtyperequest); 908 CHKERRQ(ierr); 909 ierr = PetscOptionsEnd(); CHKERRQ(ierr); 910 911 // Define derived units 912 Pascal = kilogram / (meter * PetscSqr(second)); 913 JperkgK = PetscSqr(meter) / (PetscSqr(second) * Kelvin); 914 mpersquareds = meter / PetscSqr(second); 915 WpermK = kilogram * meter / (pow(second,3) * Kelvin); 916 kgpercubicm = kilogram / pow(meter,3); 917 kgpersquaredms = kilogram / (PetscSqr(meter) * second); 918 Joulepercubicm = kilogram / (meter * PetscSqr(second)); 919 920 // Scale variables to desired units 921 theta0 *= Kelvin; 922 thetaC *= Kelvin; 923 P0 *= Pascal; 924 N *= (1./second); 925 cv *= JperkgK; 926 cp *= JperkgK; 927 Rd = cp - cv; 928 g *= mpersquareds; 929 mu *= Pascal * second; 930 k *= WpermK; 931 lx = fabs(lx) * meter; 932 ly = fabs(ly) * meter; 933 lz = fabs(lz) * meter; 934 rc = fabs(rc) * meter; 935 resx = fabs(resx) * meter; 936 resy = fabs(resy) * meter; 937 resz = fabs(resz) * meter; 938 for (int i=0; i<3; i++) center[i] *= meter; 939 940 const CeedInt dim = problem->dim, ncompx = problem->dim, 941 qdatasize = problem->qdatasize; 942 // Set up the libCEED context 943 struct SetupContext_ ctxSetup = { 944 .theta0 = theta0, 945 .thetaC = thetaC, 946 .P0 = P0, 947 .N = N, 948 .cv = cv, 949 .cp = cp, 950 .Rd = Rd, 951 .g = g, 952 .rc = rc, 953 .lx = lx, 954 .ly = ly, 955 .lz = lz, 956 .center[0] = center[0], 957 .center[1] = center[1], 958 .center[2] = center[2], 959 .dc_axis[0] = dc_axis[0], 960 .dc_axis[1] = dc_axis[1], 961 .dc_axis[2] = dc_axis[2], 962 .time = 0, 963 }; 964 965 // Create the mesh 966 { 967 const PetscReal scale[3] = {lx, ly, lz}; 968 ierr = DMPlexCreateBoxMesh(comm, dim, PETSC_FALSE, NULL, NULL, scale, 969 NULL, PETSC_TRUE, &dm); 970 CHKERRQ(ierr); 971 } 972 973 // Distribute the mesh over processes 974 { 975 DM dmDist = NULL; 976 PetscPartitioner part; 977 978 ierr = DMPlexGetPartitioner(dm, &part); CHKERRQ(ierr); 979 ierr = PetscPartitionerSetFromOptions(part); CHKERRQ(ierr); 980 ierr = DMPlexDistribute(dm, 0, NULL, &dmDist); CHKERRQ(ierr); 981 if (dmDist) { 982 ierr = DMDestroy(&dm); CHKERRQ(ierr); 983 dm = dmDist; 984 } 985 } 986 ierr = DMViewFromOptions(dm, NULL, "-dm_view"); CHKERRQ(ierr); 987 988 // Setup DM 989 ierr = DMLocalizeCoordinates(dm); CHKERRQ(ierr); 990 ierr = DMSetFromOptions(dm); CHKERRQ(ierr); 991 ierr = SetUpDM(dm, problem, degree, &bc, &ctxSetup); CHKERRQ(ierr); 992 993 // Refine DM for high-order viz 994 dmviz = NULL; 995 interpviz = NULL; 996 if (viz_refine) { 997 DM dmhierarchy[viz_refine+1]; 998 999 ierr = DMPlexSetRefinementUniform(dm, PETSC_TRUE); CHKERRQ(ierr); 1000 dmhierarchy[0] = dm; 1001 for (PetscInt i = 0, d = degree; i < viz_refine; i++) { 1002 Mat interp_next; 1003 1004 ierr = DMRefine(dmhierarchy[i], MPI_COMM_NULL, &dmhierarchy[i+1]); 1005 CHKERRQ(ierr); 1006 ierr = DMSetCoarseDM(dmhierarchy[i+1], dmhierarchy[i]); CHKERRQ(ierr); 1007 d = (d + 1) / 2; 1008 if (i + 1 == viz_refine) d = 1; 1009 ierr = SetUpDM(dmhierarchy[i+1], problem, d, &bc, &ctxSetup); CHKERRQ(ierr); 1010 ierr = DMCreateInterpolation(dmhierarchy[i], dmhierarchy[i+1], 1011 &interp_next, NULL); CHKERRQ(ierr); 1012 if (!i) interpviz = interp_next; 1013 else { 1014 Mat C; 1015 ierr = MatMatMult(interp_next, interpviz, MAT_INITIAL_MATRIX, 1016 PETSC_DECIDE, &C); CHKERRQ(ierr); 1017 ierr = MatDestroy(&interp_next); CHKERRQ(ierr); 1018 ierr = MatDestroy(&interpviz); CHKERRQ(ierr); 1019 interpviz = C; 1020 } 1021 } 1022 for (PetscInt i=1; i<viz_refine; i++) { 1023 ierr = DMDestroy(&dmhierarchy[i]); CHKERRQ(ierr); 1024 } 1025 dmviz = dmhierarchy[viz_refine]; 1026 } 1027 ierr = DMCreateGlobalVector(dm, &Q); CHKERRQ(ierr); 1028 ierr = DMGetLocalVector(dm, &Qloc); CHKERRQ(ierr); 1029 ierr = VecGetSize(Qloc, &lnodes); CHKERRQ(ierr); 1030 lnodes /= ncompq; 1031 1032 // Initialize CEED 1033 CeedInit(ceedresource, &ceed); 1034 // Set memtype 1035 CeedMemType memtypebackend; 1036 CeedGetPreferredMemType(ceed, &memtypebackend); 1037 // Check memtype compatibility 1038 if (!setmemtyperequest) 1039 memtyperequested = memtypebackend; 1040 else if (!petschavecuda && memtyperequested == CEED_MEM_DEVICE) 1041 SETERRQ1(PETSC_COMM_WORLD, PETSC_ERR_SUP_SYS, 1042 "PETSc was not built with CUDA. " 1043 "Requested MemType CEED_MEM_DEVICE is not supported.", NULL); 1044 1045 // Set number of 1D nodes and quadrature points 1046 numP = degree + 1; 1047 numQ = numP + qextra; 1048 1049 // Print summary 1050 if (testChoice == TEST_NONE) { 1051 CeedInt gdofs, odofs; 1052 int comm_size; 1053 char box_faces_str[PETSC_MAX_PATH_LEN] = "NONE"; 1054 ierr = VecGetSize(Q, &gdofs); CHKERRQ(ierr); 1055 ierr = VecGetLocalSize(Q, &odofs); CHKERRQ(ierr); 1056 gnodes = gdofs/ncompq; 1057 ierr = MPI_Comm_size(comm, &comm_size); CHKERRQ(ierr); 1058 ierr = PetscOptionsGetString(NULL, NULL, "-dm_plex_box_faces", box_faces_str, 1059 sizeof(box_faces_str), NULL); CHKERRQ(ierr); 1060 const char *usedresource; 1061 CeedGetResource(ceed, &usedresource); 1062 1063 ierr = PetscPrintf(comm, 1064 "\n-- libCEED Navier-Stokes solver + PETSc --\n" 1065 " rank(s): : %d\n" 1066 " PETSc:\n" 1067 " dm_plex_box_faces: : %s\n" 1068 " libCEED:\n" 1069 " libCEED Backend : %s\n" 1070 " libCEED Backend MemType : %s\n" 1071 " libCEED User Requested MemType : %s\n" 1072 " Mesh:\n" 1073 " Number of 1D Basis Nodes (P) : %d\n" 1074 " Number of 1D Quadrature Points (Q) : %d\n" 1075 " Global DoFs : %D\n" 1076 " Owned DoFs : %D\n" 1077 " DoFs per node : %D\n" 1078 " Global nodes : %D\n" 1079 " Owned nodes : %D\n", 1080 comm_size, box_faces_str, usedresource, 1081 CeedMemTypes[memtypebackend], 1082 (setmemtyperequest) ? 1083 CeedMemTypes[memtyperequested] : "none", 1084 numP, numQ, gdofs, odofs, ncompq, gnodes, lnodes); 1085 CHKERRQ(ierr); 1086 } 1087 1088 // Set up global mass vector 1089 ierr = VecDuplicate(Q, &user->M); CHKERRQ(ierr); 1090 1091 // Set up libCEED 1092 // CEED Bases 1093 CeedInit(ceedresource, &ceed); 1094 CeedBasisCreateTensorH1Lagrange(ceed, dim, ncompq, numP, numQ, CEED_GAUSS, 1095 &basisq); 1096 CeedBasisCreateTensorH1Lagrange(ceed, dim, ncompx, 2, numQ, CEED_GAUSS, 1097 &basisx); 1098 CeedBasisCreateTensorH1Lagrange(ceed, dim, ncompx, 2, numP, 1099 CEED_GAUSS_LOBATTO, &basisxc); 1100 1101 ierr = DMGetCoordinateDM(dm, &dmcoord); CHKERRQ(ierr); 1102 ierr = DMPlexSetClosurePermutationTensor(dmcoord, PETSC_DETERMINE, NULL); 1103 CHKERRQ(ierr); 1104 1105 // CEED Restrictions 1106 ierr = CreateRestrictionFromPlex(ceed, dm, degree+1, &restrictq); 1107 CHKERRQ(ierr); 1108 ierr = CreateRestrictionFromPlex(ceed, dmcoord, 2, &restrictx); CHKERRQ(ierr); 1109 DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd); CHKERRQ(ierr); 1110 localNelem = cEnd - cStart; 1111 CeedInt numQdim = CeedIntPow(numQ, dim); 1112 CeedElemRestrictionCreateStrided(ceed, localNelem, numQdim, 1113 localNelem*numQdim, qdatasize, 1114 CEED_STRIDES_BACKEND, &restrictqdi); 1115 CeedElemRestrictionCreateStrided(ceed, localNelem, PetscPowInt(numP, dim), 1116 localNelem*PetscPowInt(numP, dim), ncompx, 1117 CEED_STRIDES_BACKEND, &restrictxcoord); 1118 1119 ierr = DMGetCoordinatesLocal(dm, &Xloc); CHKERRQ(ierr); 1120 ierr = CreateVectorFromPetscVec(ceed, Xloc, &xcorners); CHKERRQ(ierr); 1121 1122 // Create the CEED vectors that will be needed in setup 1123 CeedInt Nqpts; 1124 CeedBasisGetNumQuadraturePoints(basisq, &Nqpts); 1125 CeedVectorCreate(ceed, qdatasize*localNelem*Nqpts, &qdata); 1126 CeedElemRestrictionCreateVector(restrictq, &q0ceed, NULL); 1127 1128 // Create the Q-function that builds the quadrature data for the NS operator 1129 CeedQFunctionCreateInterior(ceed, 1, problem->setup, problem->setup_loc, 1130 &qf_setup); 1131 CeedQFunctionAddInput(qf_setup, "dx", ncompx*dim, CEED_EVAL_GRAD); 1132 CeedQFunctionAddInput(qf_setup, "weight", 1, CEED_EVAL_WEIGHT); 1133 CeedQFunctionAddOutput(qf_setup, "qdata", qdatasize, CEED_EVAL_NONE); 1134 1135 // Create the Q-function that sets the ICs of the operator 1136 CeedQFunctionCreateInterior(ceed, 1, problem->ics, problem->ics_loc, &qf_ics); 1137 CeedQFunctionAddInput(qf_ics, "x", ncompx, CEED_EVAL_INTERP); 1138 CeedQFunctionAddOutput(qf_ics, "q0", ncompq, CEED_EVAL_NONE); 1139 1140 qf_rhs = NULL; 1141 if (problem->apply_rhs) { // Create the Q-function that defines the action of the RHS operator 1142 CeedQFunctionCreateInterior(ceed, 1, problem->apply_rhs, 1143 problem->apply_rhs_loc, &qf_rhs); 1144 CeedQFunctionAddInput(qf_rhs, "q", ncompq, CEED_EVAL_INTERP); 1145 CeedQFunctionAddInput(qf_rhs, "dq", ncompq*dim, CEED_EVAL_GRAD); 1146 CeedQFunctionAddInput(qf_rhs, "qdata", qdatasize, CEED_EVAL_NONE); 1147 CeedQFunctionAddInput(qf_rhs, "x", ncompx, CEED_EVAL_INTERP); 1148 CeedQFunctionAddOutput(qf_rhs, "v", ncompq, CEED_EVAL_INTERP); 1149 CeedQFunctionAddOutput(qf_rhs, "dv", ncompq*dim, CEED_EVAL_GRAD); 1150 } 1151 1152 qf_ifunction = NULL; 1153 if (problem->apply_ifunction) { // Create the Q-function that defines the action of the IFunction 1154 CeedQFunctionCreateInterior(ceed, 1, problem->apply_ifunction, 1155 problem->apply_ifunction_loc, &qf_ifunction); 1156 CeedQFunctionAddInput(qf_ifunction, "q", ncompq, CEED_EVAL_INTERP); 1157 CeedQFunctionAddInput(qf_ifunction, "dq", ncompq*dim, CEED_EVAL_GRAD); 1158 CeedQFunctionAddInput(qf_ifunction, "qdot", ncompq, CEED_EVAL_INTERP); 1159 CeedQFunctionAddInput(qf_ifunction, "qdata", qdatasize, CEED_EVAL_NONE); 1160 CeedQFunctionAddInput(qf_ifunction, "x", ncompx, CEED_EVAL_INTERP); 1161 CeedQFunctionAddOutput(qf_ifunction, "v", ncompq, CEED_EVAL_INTERP); 1162 CeedQFunctionAddOutput(qf_ifunction, "dv", ncompq*dim, CEED_EVAL_GRAD); 1163 } 1164 1165 // Create the operator that builds the quadrature data for the NS operator 1166 CeedOperatorCreate(ceed, qf_setup, NULL, NULL, &op_setup); 1167 CeedOperatorSetField(op_setup, "dx", restrictx, basisx, CEED_VECTOR_ACTIVE); 1168 CeedOperatorSetField(op_setup, "weight", CEED_ELEMRESTRICTION_NONE, 1169 basisx, CEED_VECTOR_NONE); 1170 CeedOperatorSetField(op_setup, "qdata", restrictqdi, 1171 CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE); 1172 1173 // Create the operator that sets the ICs 1174 CeedOperatorCreate(ceed, qf_ics, NULL, NULL, &op_ics); 1175 CeedOperatorSetField(op_ics, "x", restrictx, basisxc, CEED_VECTOR_ACTIVE); 1176 CeedOperatorSetField(op_ics, "q0", restrictq, 1177 CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE); 1178 1179 CeedElemRestrictionCreateVector(restrictq, &user->qceed, NULL); 1180 CeedElemRestrictionCreateVector(restrictq, &user->qdotceed, NULL); 1181 CeedElemRestrictionCreateVector(restrictq, &user->gceed, NULL); 1182 1183 if (qf_rhs) { // Create the RHS physics operator 1184 CeedOperator op; 1185 CeedOperatorCreate(ceed, qf_rhs, NULL, NULL, &op); 1186 CeedOperatorSetField(op, "q", restrictq, basisq, CEED_VECTOR_ACTIVE); 1187 CeedOperatorSetField(op, "dq", restrictq, basisq, CEED_VECTOR_ACTIVE); 1188 CeedOperatorSetField(op, "qdata", restrictqdi, 1189 CEED_BASIS_COLLOCATED, qdata); 1190 CeedOperatorSetField(op, "x", restrictx, basisx, xcorners); 1191 CeedOperatorSetField(op, "v", restrictq, basisq, CEED_VECTOR_ACTIVE); 1192 CeedOperatorSetField(op, "dv", restrictq, basisq, CEED_VECTOR_ACTIVE); 1193 user->op_rhs = op; 1194 } 1195 1196 if (qf_ifunction) { // Create the IFunction operator 1197 CeedOperator op; 1198 CeedOperatorCreate(ceed, qf_ifunction, NULL, NULL, &op); 1199 CeedOperatorSetField(op, "q", restrictq, basisq, CEED_VECTOR_ACTIVE); 1200 CeedOperatorSetField(op, "dq", restrictq, basisq, CEED_VECTOR_ACTIVE); 1201 CeedOperatorSetField(op, "qdot", restrictq, basisq, user->qdotceed); 1202 CeedOperatorSetField(op, "qdata", restrictqdi, 1203 CEED_BASIS_COLLOCATED, qdata); 1204 CeedOperatorSetField(op, "x", restrictx, basisx, xcorners); 1205 CeedOperatorSetField(op, "v", restrictq, basisq, CEED_VECTOR_ACTIVE); 1206 CeedOperatorSetField(op, "dv", restrictq, basisq, CEED_VECTOR_ACTIVE); 1207 user->op_ifunction = op; 1208 } 1209 1210 CeedQFunctionSetContext(qf_ics, &ctxSetup, sizeof ctxSetup); 1211 CeedScalar ctxNS[8] = {lambda, mu, k, cv, cp, g, Rd}; 1212 struct Advection2dContext_ ctxAdvection2d = { 1213 .CtauS = CtauS, 1214 .strong_form = strong_form, 1215 .stabilization = stab, 1216 }; 1217 switch (problemChoice) { 1218 case NS_DENSITY_CURRENT: 1219 if (qf_rhs) CeedQFunctionSetContext(qf_rhs, &ctxNS, sizeof ctxNS); 1220 if (qf_ifunction) CeedQFunctionSetContext(qf_ifunction, &ctxNS, 1221 sizeof ctxNS); 1222 break; 1223 case NS_ADVECTION: 1224 case NS_ADVECTION2D: 1225 if (qf_rhs) CeedQFunctionSetContext(qf_rhs, &ctxAdvection2d, 1226 sizeof ctxAdvection2d); 1227 if (qf_ifunction) CeedQFunctionSetContext(qf_ifunction, &ctxAdvection2d, 1228 sizeof ctxAdvection2d); 1229 } 1230 1231 // Set up PETSc context 1232 // Set up units structure 1233 units->meter = meter; 1234 units->kilogram = kilogram; 1235 units->second = second; 1236 units->Kelvin = Kelvin; 1237 units->Pascal = Pascal; 1238 units->JperkgK = JperkgK; 1239 units->mpersquareds = mpersquareds; 1240 units->WpermK = WpermK; 1241 units->kgpercubicm = kgpercubicm; 1242 units->kgpersquaredms = kgpersquaredms; 1243 units->Joulepercubicm = Joulepercubicm; 1244 1245 // Set up user structure 1246 user->comm = comm; 1247 user->outputfreq = outputfreq; 1248 user->contsteps = contsteps; 1249 user->units = units; 1250 user->dm = dm; 1251 user->dmviz = dmviz; 1252 user->interpviz = interpviz; 1253 user->ceed = ceed; 1254 1255 // Calculate qdata and ICs 1256 // Set up state global and local vectors 1257 ierr = VecZeroEntries(Q); CHKERRQ(ierr); 1258 1259 ierr = VectorPlacePetscVec(q0ceed, Qloc); CHKERRQ(ierr); 1260 1261 // Apply Setup Ceed Operators 1262 ierr = VectorPlacePetscVec(xcorners, Xloc); CHKERRQ(ierr); 1263 CeedOperatorApply(op_setup, xcorners, qdata, CEED_REQUEST_IMMEDIATE); 1264 ierr = ComputeLumpedMassMatrix(ceed, dm, restrictq, basisq, restrictqdi, qdata, 1265 user->M); CHKERRQ(ierr); 1266 1267 ierr = ICs_FixMultiplicity(op_ics, xcorners, q0ceed, dm, Qloc, Q, restrictq, 1268 &ctxSetup, 0.0); CHKERRQ(ierr); 1269 if (1) { // Record boundary values from initial condition and override DMPlexInsertBoundaryValues() 1270 // We use this for the main simulation DM because the reference DMPlexInsertBoundaryValues() is very slow. If we 1271 // disable this, we should still get the same results due to the problem->bc function, but with potentially much 1272 // slower execution. 1273 Vec Qbc; 1274 ierr = DMGetNamedLocalVector(dm, "Qbc", &Qbc); CHKERRQ(ierr); 1275 ierr = VecCopy(Qloc, Qbc); CHKERRQ(ierr); 1276 ierr = VecZeroEntries(Qloc); CHKERRQ(ierr); 1277 ierr = DMGlobalToLocal(dm, Q, INSERT_VALUES, Qloc); CHKERRQ(ierr); 1278 ierr = VecAXPY(Qbc, -1., Qloc); CHKERRQ(ierr); 1279 ierr = DMRestoreNamedLocalVector(dm, "Qbc", &Qbc); CHKERRQ(ierr); 1280 ierr = PetscObjectComposeFunction((PetscObject)dm, 1281 "DMPlexInsertBoundaryValues_C", DMPlexInsertBoundaryValues_NS); 1282 CHKERRQ(ierr); 1283 } 1284 1285 MPI_Comm_rank(comm, &rank); 1286 if (!rank) {ierr = PetscMkdir(user->outputfolder); CHKERRQ(ierr);} 1287 // Gather initial Q values 1288 // In case of continuation of simulation, set up initial values from binary file 1289 if (contsteps) { // continue from existent solution 1290 PetscViewer viewer; 1291 char filepath[PETSC_MAX_PATH_LEN]; 1292 // Read input 1293 ierr = PetscSNPrintf(filepath, sizeof filepath, "%s/ns-solution.bin", 1294 user->outputfolder); 1295 CHKERRQ(ierr); 1296 ierr = PetscViewerBinaryOpen(comm, filepath, FILE_MODE_READ, &viewer); 1297 CHKERRQ(ierr); 1298 ierr = VecLoad(Q, viewer); CHKERRQ(ierr); 1299 ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr); 1300 } 1301 ierr = DMRestoreLocalVector(dm, &Qloc); CHKERRQ(ierr); 1302 1303 // Create and setup TS 1304 ierr = TSCreate(comm, &ts); CHKERRQ(ierr); 1305 ierr = TSSetDM(ts, dm); CHKERRQ(ierr); 1306 if (implicit) { 1307 ierr = TSSetType(ts, TSBDF); CHKERRQ(ierr); 1308 if (user->op_ifunction) { 1309 ierr = TSSetIFunction(ts, NULL, IFunction_NS, &user); CHKERRQ(ierr); 1310 } else { // Implicit integrators can fall back to using an RHSFunction 1311 ierr = TSSetRHSFunction(ts, NULL, RHS_NS, &user); CHKERRQ(ierr); 1312 } 1313 } else { 1314 if (!user->op_rhs) SETERRQ(comm,PETSC_ERR_ARG_NULL, 1315 "Problem does not provide RHSFunction"); 1316 ierr = TSSetType(ts, TSRK); CHKERRQ(ierr); 1317 ierr = TSRKSetType(ts, TSRK5F); CHKERRQ(ierr); 1318 ierr = TSSetRHSFunction(ts, NULL, RHS_NS, &user); CHKERRQ(ierr); 1319 } 1320 ierr = TSSetMaxTime(ts, 500. * units->second); CHKERRQ(ierr); 1321 ierr = TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER); CHKERRQ(ierr); 1322 ierr = TSSetTimeStep(ts, 1.e-2 * units->second); CHKERRQ(ierr); 1323 if (testChoice != TEST_NONE) {ierr = TSSetMaxSteps(ts, 10); CHKERRQ(ierr);} 1324 ierr = TSGetAdapt(ts, &adapt); CHKERRQ(ierr); 1325 ierr = TSAdaptSetStepLimits(adapt, 1326 1.e-12 * units->second, 1327 1.e2 * units->second); CHKERRQ(ierr); 1328 ierr = TSSetFromOptions(ts); CHKERRQ(ierr); 1329 if (!contsteps) { // print initial condition 1330 if (testChoice == TEST_NONE) { 1331 ierr = TSMonitor_NS(ts, 0, 0., Q, user); CHKERRQ(ierr); 1332 } 1333 } else { // continue from time of last output 1334 PetscReal time; 1335 PetscInt count; 1336 PetscViewer viewer; 1337 char filepath[PETSC_MAX_PATH_LEN]; 1338 ierr = PetscSNPrintf(filepath, sizeof filepath, "%s/ns-time.bin", 1339 user->outputfolder); CHKERRQ(ierr); 1340 ierr = PetscViewerBinaryOpen(comm, filepath, FILE_MODE_READ, &viewer); 1341 CHKERRQ(ierr); 1342 ierr = PetscViewerBinaryRead(viewer, &time, 1, &count, PETSC_REAL); 1343 CHKERRQ(ierr); 1344 ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr); 1345 ierr = TSSetTime(ts, time * user->units->second); CHKERRQ(ierr); 1346 } 1347 if (testChoice == TEST_NONE) { 1348 ierr = TSMonitorSet(ts, TSMonitor_NS, user, NULL); CHKERRQ(ierr); 1349 } 1350 1351 // Solve 1352 start = MPI_Wtime(); 1353 ierr = PetscBarrier((PetscObject)ts); CHKERRQ(ierr); 1354 ierr = TSSolve(ts, Q); CHKERRQ(ierr); 1355 cpu_time_used = MPI_Wtime() - start; 1356 ierr = TSGetSolveTime(ts, &ftime); CHKERRQ(ierr); 1357 ierr = MPI_Allreduce(MPI_IN_PLACE, &cpu_time_used, 1, MPI_DOUBLE, MPI_MIN, 1358 comm); CHKERRQ(ierr); 1359 if (testChoice == TEST_NONE) { 1360 ierr = PetscPrintf(PETSC_COMM_WORLD, 1361 "Time taken for solution (sec): %g\n", 1362 (double)cpu_time_used); CHKERRQ(ierr); 1363 } 1364 1365 // Get error 1366 if (problem->non_zero_time && testChoice == TEST_NONE) { 1367 Vec Qexact, Qexactloc; 1368 PetscReal norm; 1369 ierr = DMCreateGlobalVector(dm, &Qexact); CHKERRQ(ierr); 1370 ierr = DMGetLocalVector(dm, &Qexactloc); CHKERRQ(ierr); 1371 ierr = VecGetSize(Qexactloc, &lnodes); CHKERRQ(ierr); 1372 1373 ierr = ICs_FixMultiplicity(op_ics, xcorners, q0ceed, dm, Qexactloc, Qexact, 1374 restrictq, &ctxSetup, ftime); CHKERRQ(ierr); 1375 1376 ierr = VecAXPY(Q, -1.0, Qexact); CHKERRQ(ierr); 1377 ierr = VecNorm(Q, NORM_MAX, &norm); CHKERRQ(ierr); 1378 CeedVectorDestroy(&q0ceed); 1379 ierr = PetscPrintf(PETSC_COMM_WORLD, 1380 "Max Error: %g\n", 1381 (double)norm); CHKERRQ(ierr); 1382 // Clean up vectors 1383 ierr = DMRestoreLocalVector(dm, &Qexactloc); CHKERRQ(ierr); 1384 ierr = VecDestroy(&Qexact); CHKERRQ(ierr); 1385 } 1386 1387 // Output Statistics 1388 ierr = TSGetStepNumber(ts,&steps); CHKERRQ(ierr); 1389 if (testChoice == TEST_NONE) { 1390 ierr = PetscPrintf(PETSC_COMM_WORLD, 1391 "Time integrator took %D time steps to reach final time %g\n", 1392 steps, (double)ftime); CHKERRQ(ierr); 1393 } 1394 // Output numerical values from command line 1395 ierr = VecViewFromOptions(Q, NULL, "-vec_view"); CHKERRQ(ierr); 1396 1397 // compare reference solution values with current run 1398 if (testChoice != TEST_NONE) { 1399 PetscViewer viewer; 1400 // Read reference file 1401 Vec Qref; 1402 PetscReal error, Qrefnorm; 1403 ierr = VecDuplicate(Q, &Qref); CHKERRQ(ierr); 1404 ierr = PetscViewerBinaryOpen(comm, test->filepath, FILE_MODE_READ, &viewer); 1405 CHKERRQ(ierr); 1406 ierr = VecLoad(Qref, viewer); CHKERRQ(ierr); 1407 ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr); 1408 1409 // Compute error with respect to reference solution 1410 ierr = VecAXPY(Q, -1.0, Qref); CHKERRQ(ierr); 1411 ierr = VecNorm(Qref, NORM_MAX, &Qrefnorm); CHKERRQ(ierr); 1412 ierr = VecScale(Q, 1./Qrefnorm); CHKERRQ(ierr); 1413 ierr = VecNorm(Q, NORM_MAX, &error); CHKERRQ(ierr); 1414 ierr = VecDestroy(&Qref); CHKERRQ(ierr); 1415 // Check error 1416 if (error > test->testtol) { 1417 ierr = PetscPrintf(PETSC_COMM_WORLD, 1418 "Test failed with error norm %g\n", 1419 (double)error); CHKERRQ(ierr); 1420 } 1421 ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr); 1422 } 1423 1424 // Clean up libCEED 1425 CeedVectorDestroy(&qdata); 1426 CeedVectorDestroy(&user->qceed); 1427 CeedVectorDestroy(&user->qdotceed); 1428 CeedVectorDestroy(&user->gceed); 1429 CeedVectorDestroy(&xcorners); 1430 CeedBasisDestroy(&basisq); 1431 CeedBasisDestroy(&basisx); 1432 CeedBasisDestroy(&basisxc); 1433 CeedElemRestrictionDestroy(&restrictq); 1434 CeedElemRestrictionDestroy(&restrictx); 1435 CeedElemRestrictionDestroy(&restrictqdi); 1436 CeedElemRestrictionDestroy(&restrictxcoord); 1437 CeedQFunctionDestroy(&qf_setup); 1438 CeedQFunctionDestroy(&qf_ics); 1439 CeedQFunctionDestroy(&qf_rhs); 1440 CeedQFunctionDestroy(&qf_ifunction); 1441 CeedOperatorDestroy(&op_setup); 1442 CeedOperatorDestroy(&op_ics); 1443 CeedOperatorDestroy(&user->op_rhs); 1444 CeedOperatorDestroy(&user->op_ifunction); 1445 CeedDestroy(&ceed); 1446 1447 // Clean up PETSc 1448 ierr = VecDestroy(&Q); CHKERRQ(ierr); 1449 ierr = VecDestroy(&user->M); CHKERRQ(ierr); 1450 ierr = MatDestroy(&interpviz); CHKERRQ(ierr); 1451 ierr = DMDestroy(&dmviz); CHKERRQ(ierr); 1452 ierr = TSDestroy(&ts); CHKERRQ(ierr); 1453 ierr = DMDestroy(&dm); CHKERRQ(ierr); 1454 ierr = PetscFree(units); CHKERRQ(ierr); 1455 ierr = PetscFree(user); CHKERRQ(ierr); 1456 return PetscFinalize(); 1457 } 1458 1459