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