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/cuda -problem advection -degree 1 33 // 34 //TESTARGS(name="dc_explicit") -ceed {ceed_resource} -test -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. -ts_dt 1e-3 -compare_final_state_atol 1E-11 -compare_final_state_filename examples/fluids/tests-output/fluids-navierstokes-dc-explicit.bin 35 //TESTARGS(name="dc_implicit_stab_none") -ceed {ceed_resource} -test -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 -compare_final_state_atol 5E-4 -compare_final_state_filename examples/fluids/tests-output/fluids-navierstokes-dc-implicit-stab-none.bin 36 //TESTARGS(name="adv_rotation_explicit_strong") -ceed {ceed_resource} -test -problem advection -strong_form 1 -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. -ts_dt 1e-3 -compare_final_state_atol 1E-11 -compare_final_state_filename examples/fluids/tests-output/fluids-navierstokes-adv-rotation-explicit-strong.bin 37 //TESTARGS(name="adv_rotation_implicit_stab_supg") -ceed {ceed_resource} -test -problem advection -CtauS .3 -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. -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 -compare_final_state_atol 5E-4 -compare_final_state_filename examples/fluids/tests-output/fluids-navierstokes-adv-rotation-implicit-stab-supg.bin 38 //TESTARGS(name="adv_translation_implicit_stab_su") -ceed {ceed_resource} -test -problem advection -CtauS .3 -stab su -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. -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 -problem_advection_wind translation -problem_advection_wind_translation .53,-1.33,-2.65 -compare_final_state_atol 5E-4 -compare_final_state_filename examples/fluids/tests-output/fluids-navierstokes-adv-translation-implicit-stab-su.bin 39 //TESTARGS(name="adv2d_rotation_explicit_strong") -ceed {ceed_resource} -test -problem advection2d -strong_form 1 -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. -ts_dt 1e-3 -compare_final_state_atol 1E-11 -compare_final_state_filename examples/fluids/tests-output/fluids-navierstokes-adv2d-rotation-explicit-strong.bin 40 //TESTARGS(name="adv2d_rotation_implicit_stab_supg") -ceed {ceed_resource} -test -problem advection2d -CtauS .3 -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. -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 -compare_final_state_atol 5E-4 -compare_final_state_filename examples/fluids/tests-output/fluids-navierstokes-adv2d-rotation-implicit-stab-supg.bin 41 //TESTARGS(name="adv2d_translation_implicit_stab_su") -ceed {ceed_resource} -test -problem advection2d -CtauS .3 -stab su -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. -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 -problem_advection_wind translation -problem_advection_wind_translation .53,-1.33,0 -compare_final_state_atol 5E-4 -compare_final_state_filename examples/fluids/tests-output/fluids-navierstokes-adv2d-translation-implicit-stab-su.bin 42 43 /// @file 44 /// Navier-Stokes example using PETSc 45 46 const char help[] = "Solve Navier-Stokes using PETSc and libCEED\n"; 47 48 #include <ceed.h> 49 #include <petscdmplex.h> 50 #include <petscsys.h> 51 #include <petscts.h> 52 #include <stdbool.h> 53 #include "advection.h" 54 #include "advection2d.h" 55 #include "common.h" 56 #include "euler-vortex.h" 57 #include "densitycurrent.h" 58 #include "setup-boundary.h" 59 60 #if PETSC_VERSION_LT(3,14,0) 61 # define DMPlexGetClosureIndices(a,b,c,d,e,f,g,h,i) DMPlexGetClosureIndices(a,b,c,d,f,g,i) 62 # define DMPlexRestoreClosureIndices(a,b,c,d,e,f,g,h,i) DMPlexRestoreClosureIndices(a,b,c,d,f,g,i) 63 #endif 64 65 #if PETSC_VERSION_LT(3,14,0) 66 # define DMAddBoundary(a,b,c,d,e,f,g,h,i,j,k,l) DMAddBoundary(a,b,c,d,e,f,g,h,j,k,l) 67 #endif 68 69 // MemType Options 70 static const char *const memTypes[] = { 71 "host", 72 "device", 73 "memType", "CEED_MEM_", NULL 74 }; 75 76 // Problem Options 77 typedef enum { 78 NS_DENSITY_CURRENT = 0, 79 NS_ADVECTION = 1, 80 NS_ADVECTION2D = 2, 81 NS_EULER_VORTEX = 3, 82 } problemType; 83 static const char *const problemTypes[] = { 84 "density_current", 85 "advection", 86 "advection2d", 87 "euler_vortex", 88 "problemType", "NS_", NULL 89 }; 90 91 // Wind Options for Advection 92 typedef enum { 93 ADVECTION_WIND_ROTATION = 0, 94 ADVECTION_WIND_TRANSLATION = 1, 95 } WindType; 96 static const char *const WindTypes[] = { 97 "rotation", 98 "translation", 99 "WindType", "ADVECTION_WIND_", NULL 100 }; 101 102 typedef enum { 103 STAB_NONE = 0, 104 STAB_SU = 1, // Streamline Upwind 105 STAB_SUPG = 2, // Streamline Upwind Petrov-Galerkin 106 } StabilizationType; 107 static const char *const StabilizationTypes[] = { 108 "none", 109 "SU", 110 "SUPG", 111 "StabilizationType", "STAB_", NULL 112 }; 113 114 typedef enum { 115 EULER_TEST_NONE = 0, 116 EULER_TEST_1 = 1, 117 EULER_TEST_2 = 2, 118 EULER_TEST_3 = 3, 119 EULER_TEST_4 = 4, 120 } EulerTestType; 121 static const char *const EulerTestTypes[] = { 122 "none", 123 "t1", 124 "t2", 125 "t3", 126 "t4", 127 "EulerTestType", "EULER_TEST_", NULL 128 }; 129 130 // Problem specific data 131 typedef struct { 132 CeedInt dim, qdatasizeVol, qdatasizeSur; 133 CeedQFunctionUser setupVol, setupSur, ics, applyVol_rhs, applyVol_ifunction, 134 applySur; 135 PetscErrorCode (*bc)(PetscInt, PetscReal, const PetscReal[], PetscInt, 136 PetscScalar[], void *); 137 const char *setupVol_loc, *setupSur_loc, *ics_loc, *applyVol_rhs_loc, 138 *applyVol_ifunction_loc, *applySur_loc; 139 const bool non_zero_time; 140 } problemData; 141 142 problemData problemOptions[] = { 143 [NS_DENSITY_CURRENT] = { 144 .dim = 3, 145 .qdatasizeVol = 10, 146 .qdatasizeSur = 4, 147 .setupVol = Setup, 148 .setupVol_loc = Setup_loc, 149 .setupSur = SetupBoundary, 150 .setupSur_loc = SetupBoundary_loc, 151 .ics = ICsDC, 152 .ics_loc = ICsDC_loc, 153 .applyVol_rhs = DC, 154 .applyVol_rhs_loc = DC_loc, 155 .applyVol_ifunction = IFunction_DC, 156 .applyVol_ifunction_loc = IFunction_DC_loc, 157 .bc = Exact_DC, 158 .non_zero_time = PETSC_FALSE, 159 }, 160 [NS_ADVECTION] = { 161 .dim = 3, 162 .qdatasizeVol = 10, 163 .qdatasizeSur = 4, 164 .setupVol = Setup, 165 .setupVol_loc = Setup_loc, 166 .setupSur = SetupBoundary, 167 .setupSur_loc = SetupBoundary_loc, 168 .ics = ICsAdvection, 169 .ics_loc = ICsAdvection_loc, 170 .applyVol_rhs = Advection, 171 .applyVol_rhs_loc = Advection_loc, 172 .applyVol_ifunction = IFunction_Advection, 173 .applyVol_ifunction_loc = IFunction_Advection_loc, 174 .applySur = Advection_Sur, 175 .applySur_loc = Advection_Sur_loc, 176 .bc = Exact_Advection, 177 .non_zero_time = PETSC_FALSE, 178 }, 179 [NS_ADVECTION2D] = { 180 .dim = 2, 181 .qdatasizeVol = 5, 182 .qdatasizeSur = 3, 183 .setupVol = Setup2d, 184 .setupVol_loc = Setup2d_loc, 185 .setupSur = SetupBoundary2d, 186 .setupSur_loc = SetupBoundary2d_loc, 187 .ics = ICsAdvection2d, 188 .ics_loc = ICsAdvection2d_loc, 189 .applyVol_rhs = Advection2d, 190 .applyVol_rhs_loc = Advection2d_loc, 191 .applyVol_ifunction = IFunction_Advection2d, 192 .applyVol_ifunction_loc = IFunction_Advection2d_loc, 193 .applySur = Advection2d_Sur, 194 .applySur_loc = Advection2d_Sur_loc, 195 .bc = Exact_Advection2d, 196 .non_zero_time = PETSC_TRUE, 197 }, 198 [NS_EULER_VORTEX] = { 199 .dim = 3, 200 .qdatasizeVol = 10, 201 .qdatasizeSur = 4, 202 .setupVol = Setup, 203 .setupVol_loc = Setup_loc, 204 .setupSur = SetupBoundary, 205 .setupSur_loc = SetupBoundary_loc, 206 .ics = ICsEuler, 207 .ics_loc = ICsEuler_loc, 208 .applyVol_rhs = Euler, 209 .applyVol_rhs_loc = Euler_loc, 210 .applySur = Euler_Sur, 211 .applySur_loc = Euler_Sur_loc, 212 .bc = Exact_Euler, 213 .non_zero_time = PETSC_TRUE, 214 }, 215 }; 216 217 // PETSc user data 218 typedef struct User_ *User; 219 typedef struct Units_ *Units; 220 221 struct User_ { 222 MPI_Comm comm; 223 PetscInt outputfreq; 224 DM dm; 225 DM dmviz; 226 Mat interpviz; 227 Ceed ceed; 228 Units units; 229 CeedVector qceed, qdotceed, gceed; 230 CeedOperator op_rhs_vol, op_rhs, op_ifunction_vol, op_ifunction; 231 Vec M; 232 char outputdir[PETSC_MAX_PATH_LEN]; 233 PetscInt contsteps; 234 EulerContext ctxEulerData; 235 }; 236 237 struct Units_ { 238 // fundamental units 239 PetscScalar meter; 240 PetscScalar kilogram; 241 PetscScalar second; 242 PetscScalar Kelvin; 243 // derived units 244 PetscScalar Pascal; 245 PetscScalar JperkgK; 246 PetscScalar mpersquareds; 247 PetscScalar WpermK; 248 PetscScalar kgpercubicm; 249 PetscScalar kgpersquaredms; 250 PetscScalar Joulepercubicm; 251 PetscScalar Joule; 252 }; 253 254 typedef struct SimpleBC_ *SimpleBC; 255 struct SimpleBC_ { 256 PetscInt nwall, nslip[3]; 257 PetscInt walls[6], slips[3][6]; 258 PetscBool userbc; 259 }; 260 261 // Essential BC dofs are encoded in closure indices as -(i+1). 262 static PetscInt Involute(PetscInt i) { 263 return i >= 0 ? i : -(i+1); 264 } 265 266 // Utility function to create local CEED restriction 267 static PetscErrorCode CreateRestrictionFromPlex(Ceed ceed, DM dm, CeedInt P, 268 CeedInt height, DMLabel domainLabel, CeedInt value, 269 CeedElemRestriction *Erestrict) { 270 271 PetscSection section; 272 PetscInt p, Nelem, Ndof, *erestrict, eoffset, nfields, dim, depth; 273 DMLabel depthLabel; 274 IS depthIS, iterIS; 275 Vec Uloc; 276 const PetscInt *iterIndices; 277 PetscErrorCode ierr; 278 279 PetscFunctionBeginUser; 280 ierr = DMGetDimension(dm, &dim); CHKERRQ(ierr); 281 dim -= height; 282 ierr = DMGetLocalSection(dm, §ion); CHKERRQ(ierr); 283 ierr = PetscSectionGetNumFields(section, &nfields); CHKERRQ(ierr); 284 PetscInt ncomp[nfields], fieldoff[nfields+1]; 285 fieldoff[0] = 0; 286 for (PetscInt f=0; f<nfields; f++) { 287 ierr = PetscSectionGetFieldComponents(section, f, &ncomp[f]); CHKERRQ(ierr); 288 fieldoff[f+1] = fieldoff[f] + ncomp[f]; 289 } 290 291 ierr = DMPlexGetDepth(dm, &depth); CHKERRQ(ierr); 292 ierr = DMPlexGetDepthLabel(dm, &depthLabel); CHKERRQ(ierr); 293 ierr = DMLabelGetStratumIS(depthLabel, depth - height, &depthIS); CHKERRQ(ierr); 294 if (domainLabel) { 295 IS domainIS; 296 ierr = DMLabelGetStratumIS(domainLabel, value, &domainIS); CHKERRQ(ierr); 297 if (domainIS) { // domainIS is non-empty 298 ierr = ISIntersect(depthIS, domainIS, &iterIS); CHKERRQ(ierr); 299 ierr = ISDestroy(&domainIS); CHKERRQ(ierr); 300 } else { // domainIS is NULL (empty) 301 iterIS = NULL; 302 } 303 ierr = ISDestroy(&depthIS); CHKERRQ(ierr); 304 } else { 305 iterIS = depthIS; 306 } 307 if (iterIS) { 308 ierr = ISGetLocalSize(iterIS, &Nelem); CHKERRQ(ierr); 309 ierr = ISGetIndices(iterIS, &iterIndices); CHKERRQ(ierr); 310 } else { 311 Nelem = 0; 312 iterIndices = NULL; 313 } 314 ierr = PetscMalloc1(Nelem*PetscPowInt(P, dim), &erestrict); CHKERRQ(ierr); 315 for (p=0,eoffset=0; p<Nelem; p++) { 316 PetscInt c = iterIndices[p]; 317 PetscInt numindices, *indices, nnodes; 318 ierr = DMPlexGetClosureIndices(dm, section, section, c, PETSC_TRUE, 319 &numindices, &indices, NULL, NULL); 320 CHKERRQ(ierr); 321 bool flip = false; 322 if (height > 0) { 323 PetscInt numCells, numFaces, start = -1; 324 const PetscInt *orients, *faces, *cells; 325 ierr = DMPlexGetSupport(dm, c, &cells); CHKERRQ(ierr); 326 ierr = DMPlexGetSupportSize(dm, c, &numCells); CHKERRQ(ierr); 327 if (numCells != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, 328 "Expected one cell in support of exterior face, but got %D cells", 329 numCells); 330 ierr = DMPlexGetCone(dm, cells[0], &faces); CHKERRQ(ierr); 331 ierr = DMPlexGetConeSize(dm, cells[0], &numFaces); CHKERRQ(ierr); 332 for (PetscInt i=0; i<numFaces; i++) {if (faces[i] == c) start = i;} 333 if (start < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, 334 "Could not find face %D in cone of its support", 335 c); 336 ierr = DMPlexGetConeOrientation(dm, cells[0], &orients); CHKERRQ(ierr); 337 if (orients[start] < 0) flip = true; 338 } 339 if (numindices % fieldoff[nfields]) SETERRQ1(PETSC_COMM_SELF, 340 PETSC_ERR_ARG_INCOMP, "Number of closure indices not compatible with Cell %D", 341 c); 342 nnodes = numindices / fieldoff[nfields]; 343 for (PetscInt i=0; i<nnodes; i++) { 344 PetscInt ii = i; 345 if (flip) { 346 if (P == nnodes) ii = nnodes - 1 - i; 347 else if (P*P == nnodes) { 348 PetscInt row = i / P, col = i % P; 349 ii = row + col * P; 350 } else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, 351 "No support for flipping point with %D nodes != P (%D) or P^2", 352 nnodes, P); 353 } 354 // Check that indices are blocked by node and thus can be coalesced as a single field with 355 // fieldoff[nfields] = sum(ncomp) components. 356 for (PetscInt f=0; f<nfields; f++) { 357 for (PetscInt j=0; j<ncomp[f]; j++) { 358 if (Involute(indices[fieldoff[f]*nnodes + ii*ncomp[f] + j]) 359 != Involute(indices[ii*ncomp[0]]) + fieldoff[f] + j) 360 SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, 361 "Cell %D closure indices not interlaced for node %D field %D component %D", 362 c, ii, f, j); 363 } 364 } 365 // Essential boundary conditions are encoded as -(loc+1), but we don't care so we decode. 366 PetscInt loc = Involute(indices[ii*ncomp[0]]); 367 erestrict[eoffset++] = loc; 368 } 369 ierr = DMPlexRestoreClosureIndices(dm, section, section, c, PETSC_TRUE, 370 &numindices, &indices, NULL, NULL); 371 CHKERRQ(ierr); 372 } 373 if (eoffset != Nelem*PetscPowInt(P, dim)) 374 SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, 375 "ElemRestriction of size (%D,%D) initialized %D nodes", Nelem, 376 PetscPowInt(P, dim),eoffset); 377 if (iterIS) { 378 ierr = ISRestoreIndices(iterIS, &iterIndices); CHKERRQ(ierr); 379 } 380 ierr = ISDestroy(&iterIS); CHKERRQ(ierr); 381 382 ierr = DMGetLocalVector(dm, &Uloc); CHKERRQ(ierr); 383 ierr = VecGetLocalSize(Uloc, &Ndof); CHKERRQ(ierr); 384 ierr = DMRestoreLocalVector(dm, &Uloc); CHKERRQ(ierr); 385 CeedElemRestrictionCreate(ceed, Nelem, PetscPowInt(P, dim), fieldoff[nfields], 386 1, Ndof, CEED_MEM_HOST, CEED_COPY_VALUES, erestrict, 387 Erestrict); 388 ierr = PetscFree(erestrict); CHKERRQ(ierr); 389 PetscFunctionReturn(0); 390 } 391 392 // Utility function to get Ceed Restriction for each domain 393 static PetscErrorCode GetRestrictionForDomain(Ceed ceed, DM dm, CeedInt height, 394 DMLabel domainLabel, PetscInt value, CeedInt P, CeedInt Q, CeedInt qdatasize, 395 CeedElemRestriction *restrictq, CeedElemRestriction *restrictx, 396 CeedElemRestriction *restrictqdi) { 397 398 DM dmcoord; 399 CeedInt dim, localNelem; 400 CeedInt Qdim; 401 PetscErrorCode ierr; 402 403 PetscFunctionBeginUser; 404 ierr = DMGetDimension(dm, &dim); CHKERRQ(ierr); 405 dim -= height; 406 Qdim = CeedIntPow(Q, dim); 407 ierr = DMGetCoordinateDM(dm, &dmcoord); CHKERRQ(ierr); 408 ierr = DMPlexSetClosurePermutationTensor(dmcoord, PETSC_DETERMINE, NULL); 409 CHKERRQ(ierr); 410 ierr = CreateRestrictionFromPlex(ceed, dm, P, height, domainLabel, value, 411 restrictq); 412 CHKERRQ(ierr); 413 ierr = CreateRestrictionFromPlex(ceed, dmcoord, 2, height, domainLabel, value, 414 restrictx); 415 CHKERRQ(ierr); 416 CeedElemRestrictionGetNumElements(*restrictq, &localNelem); 417 CeedElemRestrictionCreateStrided(ceed, localNelem, Qdim, 418 qdatasize, qdatasize*localNelem*Qdim, 419 CEED_STRIDES_BACKEND, restrictqdi); 420 PetscFunctionReturn(0); 421 } 422 423 // Utility function to create CEED Composite Operator for the entire domain 424 static PetscErrorCode CreateOperatorForDomain(Ceed ceed, DM dm, SimpleBC bc, 425 problemType problemChoice, WindType wind_type, CeedOperator op_applyVol, 426 CeedQFunction qf_applySur, CeedQFunction qf_setupSur,CeedInt height, 427 CeedInt numP_Sur, CeedInt numQ_Sur, CeedInt qdatasizeSur, CeedInt NqptsSur, 428 CeedBasis basisxSur, CeedBasis basisqSur, CeedOperator *op_apply) { 429 430 CeedInt dim, nFace; 431 PetscInt lsize; 432 Vec Xloc; 433 CeedVector xcorners; 434 DMLabel domainLabel; 435 PetscScalar *x; 436 PetscErrorCode ierr; 437 438 PetscFunctionBeginUser; 439 // Composite Operaters 440 CeedCompositeOperatorCreate(ceed, op_apply); 441 // --Apply a Sub-Operator for the volume 442 CeedCompositeOperatorAddSub(*op_apply, op_applyVol); 443 444 // Required data for in/outflow BCs 445 ierr = DMGetCoordinatesLocal(dm, &Xloc); CHKERRQ(ierr); 446 ierr = VecGetLocalSize(Xloc, &lsize); CHKERRQ(ierr); 447 ierr = CeedVectorCreate(ceed, lsize, &xcorners); CHKERRQ(ierr); 448 ierr = VecGetArray(Xloc, &x); CHKERRQ(ierr); 449 CeedVectorSetArray(xcorners, CEED_MEM_HOST, CEED_USE_POINTER, x); 450 ierr = DMGetLabel(dm, "Face Sets", &domainLabel); CHKERRQ(ierr); 451 ierr = DMGetDimension(dm, &dim); CHKERRQ(ierr); 452 453 if (wind_type == ADVECTION_WIND_TRANSLATION 454 || problemChoice == NS_EULER_VORTEX) { 455 // Ignore wall and slip BCs 456 bc->nwall = bc->nslip[0] = bc->nslip[1] = 0; 457 if (wind_type == ADVECTION_WIND_TRANSLATION) bc->nslip[2] = 0; 458 459 // Set number of faces 460 if (dim == 2) nFace = 4; 461 if (dim == 3) nFace = 6; 462 463 // Create CEED Operator for each boundary face 464 PetscInt localNelemSur[6]; 465 CeedVector qdataSur[6]; 466 CeedOperator op_setupSur[6], op_applySur[6]; 467 CeedElemRestriction restrictxSur[6], restrictqSur[6], restrictqdiSur[6]; 468 469 for (CeedInt i=0; i<nFace; i++) { 470 ierr = GetRestrictionForDomain(ceed, dm, height, domainLabel, i+1, numP_Sur, 471 numQ_Sur, qdatasizeSur, &restrictqSur[i], 472 &restrictxSur[i], &restrictqdiSur[i]); 473 CHKERRQ(ierr); 474 // Create the CEED vectors that will be needed in Boundary setup 475 CeedElemRestrictionGetNumElements(restrictqSur[i], &localNelemSur[i]); 476 CeedVectorCreate(ceed, qdatasizeSur*localNelemSur[i]*NqptsSur, 477 &qdataSur[i]); 478 // Create the operator that builds the quadrature data for the Boundary operator 479 CeedOperatorCreate(ceed, qf_setupSur, NULL, NULL, &op_setupSur[i]); 480 CeedOperatorSetField(op_setupSur[i], "dx", restrictxSur[i], basisxSur, 481 CEED_VECTOR_ACTIVE); 482 CeedOperatorSetField(op_setupSur[i], "weight", CEED_ELEMRESTRICTION_NONE, 483 basisxSur, CEED_VECTOR_NONE); 484 CeedOperatorSetField(op_setupSur[i], "qdataSur", restrictqdiSur[i], 485 CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE); 486 // Create Boundary operator 487 CeedOperatorCreate(ceed, qf_applySur, NULL, NULL, &op_applySur[i]); 488 CeedOperatorSetField(op_applySur[i], "q", restrictqSur[i], basisqSur, 489 CEED_VECTOR_ACTIVE); 490 CeedOperatorSetField(op_applySur[i], "qdataSur", restrictqdiSur[i], 491 CEED_BASIS_COLLOCATED, qdataSur[i]); 492 CeedOperatorSetField(op_applySur[i], "x", restrictxSur[i], basisxSur, 493 xcorners); 494 CeedOperatorSetField(op_applySur[i], "v", restrictqSur[i], basisqSur, 495 CEED_VECTOR_ACTIVE); 496 // Apply CEED operator for Boundary setup 497 CeedOperatorApply(op_setupSur[i], xcorners, qdataSur[i], 498 CEED_REQUEST_IMMEDIATE); 499 // --Apply Sub-Operator for the Boundary 500 CeedCompositeOperatorAddSub(*op_apply, op_applySur[i]); 501 } 502 CeedVectorDestroy(&xcorners); 503 } 504 PetscFunctionReturn(0); 505 } 506 507 static int CreateVectorFromPetscVec(Ceed ceed, Vec p, CeedVector *v) { 508 PetscErrorCode ierr; 509 PetscInt m; 510 511 PetscFunctionBeginUser; 512 ierr = VecGetLocalSize(p, &m); CHKERRQ(ierr); 513 ierr = CeedVectorCreate(ceed, m, v); CHKERRQ(ierr); 514 PetscFunctionReturn(0); 515 } 516 517 static int VectorPlacePetscVec(CeedVector c, Vec p) { 518 PetscErrorCode ierr; 519 PetscInt mceed, mpetsc; 520 PetscScalar *a; 521 522 PetscFunctionBeginUser; 523 ierr = CeedVectorGetLength(c, &mceed); CHKERRQ(ierr); 524 ierr = VecGetLocalSize(p, &mpetsc); CHKERRQ(ierr); 525 if (mceed != mpetsc) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, 526 "Cannot place PETSc Vec of length %D in CeedVector of length %D", 527 mpetsc, mceed); 528 ierr = VecGetArray(p, &a); CHKERRQ(ierr); 529 CeedVectorSetArray(c, CEED_MEM_HOST, CEED_USE_POINTER, a); 530 PetscFunctionReturn(0); 531 } 532 533 static PetscErrorCode DMPlexInsertBoundaryValues_NS(DM dm, 534 PetscBool insertEssential, Vec Qloc, PetscReal time, Vec faceGeomFVM, 535 Vec cellGeomFVM, Vec gradFVM) { 536 PetscErrorCode ierr; 537 Vec Qbc; 538 539 PetscFunctionBegin; 540 ierr = DMGetNamedLocalVector(dm, "Qbc", &Qbc); CHKERRQ(ierr); 541 ierr = VecAXPY(Qloc, 1., Qbc); CHKERRQ(ierr); 542 ierr = DMRestoreNamedLocalVector(dm, "Qbc", &Qbc); CHKERRQ(ierr); 543 PetscFunctionReturn(0); 544 } 545 546 // This is the RHS of the ODE, given as u_t = G(t,u) 547 // This function takes in a state vector Q and writes into G 548 static PetscErrorCode RHS_NS(TS ts, PetscReal t, Vec Q, Vec G, void *userData) { 549 PetscErrorCode ierr; 550 User user = *(User *)userData; 551 PetscScalar *q, *g; 552 Vec Qloc, Gloc; 553 554 // Global-to-local 555 PetscFunctionBeginUser; 556 user->ctxEulerData->currentTime = t; 557 ierr = DMGetLocalVector(user->dm, &Qloc); CHKERRQ(ierr); 558 ierr = DMGetLocalVector(user->dm, &Gloc); CHKERRQ(ierr); 559 ierr = VecZeroEntries(Qloc); CHKERRQ(ierr); 560 ierr = DMGlobalToLocal(user->dm, Q, INSERT_VALUES, Qloc); CHKERRQ(ierr); 561 ierr = DMPlexInsertBoundaryValues(user->dm, PETSC_TRUE, Qloc, 0.0, 562 NULL, NULL, NULL); CHKERRQ(ierr); 563 ierr = VecZeroEntries(Gloc); CHKERRQ(ierr); 564 565 // Ceed Vectors 566 ierr = VecGetArrayRead(Qloc, (const PetscScalar **)&q); CHKERRQ(ierr); 567 ierr = VecGetArray(Gloc, &g); CHKERRQ(ierr); 568 CeedVectorSetArray(user->qceed, CEED_MEM_HOST, CEED_USE_POINTER, q); 569 CeedVectorSetArray(user->gceed, CEED_MEM_HOST, CEED_USE_POINTER, g); 570 571 // Apply CEED operator 572 CeedOperatorApply(user->op_rhs, user->qceed, user->gceed, 573 CEED_REQUEST_IMMEDIATE); 574 575 // Restore vectors 576 ierr = VecRestoreArrayRead(Qloc, (const PetscScalar **)&q); CHKERRQ(ierr); 577 ierr = VecRestoreArray(Gloc, &g); CHKERRQ(ierr); 578 579 ierr = VecZeroEntries(G); CHKERRQ(ierr); 580 ierr = DMLocalToGlobal(user->dm, Gloc, ADD_VALUES, G); CHKERRQ(ierr); 581 582 // Inverse of the lumped mass matrix 583 ierr = VecPointwiseMult(G, G, user->M); // M is Minv 584 CHKERRQ(ierr); 585 586 ierr = DMRestoreLocalVector(user->dm, &Qloc); CHKERRQ(ierr); 587 ierr = DMRestoreLocalVector(user->dm, &Gloc); CHKERRQ(ierr); 588 PetscFunctionReturn(0); 589 } 590 591 static PetscErrorCode IFunction_NS(TS ts, PetscReal t, Vec Q, Vec Qdot, Vec G, 592 void *userData) { 593 PetscErrorCode ierr; 594 User user = *(User *)userData; 595 const PetscScalar *q, *qdot; 596 PetscScalar *g; 597 Vec Qloc, Qdotloc, Gloc; 598 599 // Global-to-local 600 PetscFunctionBeginUser; 601 ierr = DMGetLocalVector(user->dm, &Qloc); CHKERRQ(ierr); 602 ierr = DMGetLocalVector(user->dm, &Qdotloc); CHKERRQ(ierr); 603 ierr = DMGetLocalVector(user->dm, &Gloc); CHKERRQ(ierr); 604 ierr = VecZeroEntries(Qloc); CHKERRQ(ierr); 605 ierr = DMGlobalToLocal(user->dm, Q, INSERT_VALUES, Qloc); CHKERRQ(ierr); 606 ierr = DMPlexInsertBoundaryValues(user->dm, PETSC_TRUE, Qloc, 0.0, 607 NULL, NULL, NULL); CHKERRQ(ierr); 608 ierr = VecZeroEntries(Qdotloc); CHKERRQ(ierr); 609 ierr = DMGlobalToLocal(user->dm, Qdot, INSERT_VALUES, Qdotloc); CHKERRQ(ierr); 610 ierr = VecZeroEntries(Gloc); CHKERRQ(ierr); 611 612 // Ceed Vectors 613 ierr = VecGetArrayRead(Qloc, &q); CHKERRQ(ierr); 614 ierr = VecGetArrayRead(Qdotloc, &qdot); CHKERRQ(ierr); 615 ierr = VecGetArray(Gloc, &g); CHKERRQ(ierr); 616 CeedVectorSetArray(user->qceed, CEED_MEM_HOST, CEED_USE_POINTER, 617 (PetscScalar *)q); 618 CeedVectorSetArray(user->qdotceed, CEED_MEM_HOST, CEED_USE_POINTER, 619 (PetscScalar *)qdot); 620 CeedVectorSetArray(user->gceed, CEED_MEM_HOST, CEED_USE_POINTER, g); 621 622 // Apply CEED operator 623 CeedOperatorApply(user->op_ifunction, user->qceed, user->gceed, 624 CEED_REQUEST_IMMEDIATE); 625 626 // Restore vectors 627 ierr = VecRestoreArrayRead(Qloc, &q); CHKERRQ(ierr); 628 ierr = VecRestoreArrayRead(Qdotloc, &qdot); CHKERRQ(ierr); 629 ierr = VecRestoreArray(Gloc, &g); CHKERRQ(ierr); 630 631 ierr = VecZeroEntries(G); CHKERRQ(ierr); 632 ierr = DMLocalToGlobal(user->dm, Gloc, ADD_VALUES, G); CHKERRQ(ierr); 633 634 ierr = DMRestoreLocalVector(user->dm, &Qloc); CHKERRQ(ierr); 635 ierr = DMRestoreLocalVector(user->dm, &Qdotloc); CHKERRQ(ierr); 636 ierr = DMRestoreLocalVector(user->dm, &Gloc); CHKERRQ(ierr); 637 PetscFunctionReturn(0); 638 } 639 640 // User provided TS Monitor 641 static PetscErrorCode TSMonitor_NS(TS ts, PetscInt stepno, PetscReal time, 642 Vec Q, void *ctx) { 643 User user = ctx; 644 Vec Qloc; 645 char filepath[PETSC_MAX_PATH_LEN]; 646 PetscViewer viewer; 647 PetscErrorCode ierr; 648 649 // Set up output 650 PetscFunctionBeginUser; 651 // Print every 'outputfreq' steps 652 if (stepno % user->outputfreq != 0) 653 PetscFunctionReturn(0); 654 ierr = DMGetLocalVector(user->dm, &Qloc); CHKERRQ(ierr); 655 ierr = PetscObjectSetName((PetscObject)Qloc, "StateVec"); CHKERRQ(ierr); 656 ierr = VecZeroEntries(Qloc); CHKERRQ(ierr); 657 ierr = DMGlobalToLocal(user->dm, Q, INSERT_VALUES, Qloc); CHKERRQ(ierr); 658 659 // Output 660 ierr = PetscSNPrintf(filepath, sizeof filepath, "%s/ns-%03D.vtu", 661 user->outputdir, stepno + user->contsteps); 662 CHKERRQ(ierr); 663 ierr = PetscViewerVTKOpen(PetscObjectComm((PetscObject)Q), filepath, 664 FILE_MODE_WRITE, &viewer); CHKERRQ(ierr); 665 ierr = VecView(Qloc, viewer); CHKERRQ(ierr); 666 ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr); 667 if (user->dmviz) { 668 Vec Qrefined, Qrefined_loc; 669 char filepath_refined[PETSC_MAX_PATH_LEN]; 670 PetscViewer viewer_refined; 671 672 ierr = DMGetGlobalVector(user->dmviz, &Qrefined); CHKERRQ(ierr); 673 ierr = DMGetLocalVector(user->dmviz, &Qrefined_loc); CHKERRQ(ierr); 674 ierr = PetscObjectSetName((PetscObject)Qrefined_loc, "Refined"); 675 CHKERRQ(ierr); 676 ierr = MatInterpolate(user->interpviz, Q, Qrefined); CHKERRQ(ierr); 677 ierr = VecZeroEntries(Qrefined_loc); CHKERRQ(ierr); 678 ierr = DMGlobalToLocal(user->dmviz, Qrefined, INSERT_VALUES, Qrefined_loc); 679 CHKERRQ(ierr); 680 ierr = PetscSNPrintf(filepath_refined, sizeof filepath_refined, 681 "%s/nsrefined-%03D.vtu", 682 user->outputdir, stepno + user->contsteps); 683 CHKERRQ(ierr); 684 ierr = PetscViewerVTKOpen(PetscObjectComm((PetscObject)Qrefined), 685 filepath_refined, 686 FILE_MODE_WRITE, &viewer_refined); CHKERRQ(ierr); 687 ierr = VecView(Qrefined_loc, viewer_refined); CHKERRQ(ierr); 688 ierr = DMRestoreLocalVector(user->dmviz, &Qrefined_loc); CHKERRQ(ierr); 689 ierr = DMRestoreGlobalVector(user->dmviz, &Qrefined); CHKERRQ(ierr); 690 ierr = PetscViewerDestroy(&viewer_refined); CHKERRQ(ierr); 691 } 692 ierr = DMRestoreLocalVector(user->dm, &Qloc); CHKERRQ(ierr); 693 694 // Save data in a binary file for continuation of simulations 695 ierr = PetscSNPrintf(filepath, sizeof filepath, "%s/ns-solution.bin", 696 user->outputdir); CHKERRQ(ierr); 697 ierr = PetscViewerBinaryOpen(user->comm, filepath, FILE_MODE_WRITE, &viewer); 698 CHKERRQ(ierr); 699 ierr = VecView(Q, viewer); CHKERRQ(ierr); 700 ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr); 701 702 // Save time stamp 703 // Dimensionalize time back 704 time /= user->units->second; 705 ierr = PetscSNPrintf(filepath, sizeof filepath, "%s/ns-time.bin", 706 user->outputdir); CHKERRQ(ierr); 707 ierr = PetscViewerBinaryOpen(user->comm, filepath, FILE_MODE_WRITE, &viewer); 708 CHKERRQ(ierr); 709 #if PETSC_VERSION_GE(3,13,0) 710 ierr = PetscViewerBinaryWrite(viewer, &time, 1, PETSC_REAL); 711 #else 712 ierr = PetscViewerBinaryWrite(viewer, &time, 1, PETSC_REAL, true); 713 #endif 714 CHKERRQ(ierr); 715 ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr); 716 717 PetscFunctionReturn(0); 718 } 719 720 static PetscErrorCode ICs_FixMultiplicity(CeedOperator op_ics, 721 CeedVector xcorners, CeedVector q0ceed, DM dm, Vec Qloc, Vec Q, 722 CeedElemRestriction restrictq, CeedQFunctionContext ctxSetup, CeedScalar time) { 723 PetscErrorCode ierr; 724 CeedVector multlvec; 725 Vec Multiplicity, MultiplicityLoc; 726 727 SetupContext ctxSetupData; 728 CeedQFunctionContextGetData(ctxSetup, CEED_MEM_HOST, (void **)&ctxSetupData); 729 ctxSetupData->time = time; 730 CeedQFunctionContextRestoreData(ctxSetup, (void **)&ctxSetupData); 731 732 ierr = VecZeroEntries(Qloc); CHKERRQ(ierr); 733 ierr = VectorPlacePetscVec(q0ceed, Qloc); CHKERRQ(ierr); 734 CeedOperatorApply(op_ics, xcorners, q0ceed, CEED_REQUEST_IMMEDIATE); 735 ierr = VecZeroEntries(Q); CHKERRQ(ierr); 736 ierr = DMLocalToGlobal(dm, Qloc, ADD_VALUES, Q); CHKERRQ(ierr); 737 738 // Fix multiplicity for output of ICs 739 ierr = DMGetLocalVector(dm, &MultiplicityLoc); CHKERRQ(ierr); 740 CeedElemRestrictionCreateVector(restrictq, &multlvec, NULL); 741 ierr = VectorPlacePetscVec(multlvec, MultiplicityLoc); CHKERRQ(ierr); 742 CeedElemRestrictionGetMultiplicity(restrictq, multlvec); 743 CeedVectorDestroy(&multlvec); 744 ierr = DMGetGlobalVector(dm, &Multiplicity); CHKERRQ(ierr); 745 ierr = VecZeroEntries(Multiplicity); CHKERRQ(ierr); 746 ierr = DMLocalToGlobal(dm, MultiplicityLoc, ADD_VALUES, Multiplicity); 747 CHKERRQ(ierr); 748 ierr = VecPointwiseDivide(Q, Q, Multiplicity); CHKERRQ(ierr); 749 ierr = VecPointwiseDivide(Qloc, Qloc, MultiplicityLoc); CHKERRQ(ierr); 750 ierr = DMRestoreLocalVector(dm, &MultiplicityLoc); CHKERRQ(ierr); 751 ierr = DMRestoreGlobalVector(dm, &Multiplicity); CHKERRQ(ierr); 752 753 PetscFunctionReturn(0); 754 } 755 756 static PetscErrorCode ComputeLumpedMassMatrix(Ceed ceed, DM dm, 757 CeedElemRestriction restrictq, CeedBasis basisq, 758 CeedElemRestriction restrictqdi, CeedVector qdata, Vec M) { 759 PetscErrorCode ierr; 760 CeedQFunction qf_mass; 761 CeedOperator op_mass; 762 CeedVector mceed; 763 Vec Mloc; 764 CeedInt ncompq, qdatasize; 765 766 PetscFunctionBeginUser; 767 CeedElemRestrictionGetNumComponents(restrictq, &ncompq); 768 CeedElemRestrictionGetNumComponents(restrictqdi, &qdatasize); 769 // Create the Q-function that defines the action of the mass operator 770 CeedQFunctionCreateInterior(ceed, 1, Mass, Mass_loc, &qf_mass); 771 CeedQFunctionAddInput(qf_mass, "q", ncompq, CEED_EVAL_INTERP); 772 CeedQFunctionAddInput(qf_mass, "qdata", qdatasize, CEED_EVAL_NONE); 773 CeedQFunctionAddOutput(qf_mass, "v", ncompq, CEED_EVAL_INTERP); 774 775 // Create the mass operator 776 CeedOperatorCreate(ceed, qf_mass, NULL, NULL, &op_mass); 777 CeedOperatorSetField(op_mass, "q", restrictq, basisq, CEED_VECTOR_ACTIVE); 778 CeedOperatorSetField(op_mass, "qdata", restrictqdi, 779 CEED_BASIS_COLLOCATED, qdata); 780 CeedOperatorSetField(op_mass, "v", restrictq, basisq, CEED_VECTOR_ACTIVE); 781 782 ierr = DMGetLocalVector(dm, &Mloc); CHKERRQ(ierr); 783 ierr = VecZeroEntries(Mloc); CHKERRQ(ierr); 784 CeedElemRestrictionCreateVector(restrictq, &mceed, NULL); 785 ierr = VectorPlacePetscVec(mceed, Mloc); CHKERRQ(ierr); 786 787 { 788 // Compute a lumped mass matrix 789 CeedVector onesvec; 790 CeedElemRestrictionCreateVector(restrictq, &onesvec, NULL); 791 CeedVectorSetValue(onesvec, 1.0); 792 CeedOperatorApply(op_mass, onesvec, mceed, CEED_REQUEST_IMMEDIATE); 793 CeedVectorDestroy(&onesvec); 794 CeedOperatorDestroy(&op_mass); 795 CeedVectorDestroy(&mceed); 796 } 797 CeedQFunctionDestroy(&qf_mass); 798 799 ierr = VecZeroEntries(M); CHKERRQ(ierr); 800 ierr = DMLocalToGlobal(dm, Mloc, ADD_VALUES, M); CHKERRQ(ierr); 801 ierr = DMRestoreLocalVector(dm, &Mloc); CHKERRQ(ierr); 802 803 // Invert diagonally lumped mass vector for RHS function 804 ierr = VecReciprocal(M); CHKERRQ(ierr); 805 PetscFunctionReturn(0); 806 } 807 808 static PetscErrorCode SetUpDM(DM dm, problemData *problem, PetscInt degree, 809 SimpleBC bc, void *ctxSetupData, void *ctxMMS) { 810 PetscErrorCode ierr; 811 812 PetscFunctionBeginUser; 813 { 814 // Configure the finite element space and boundary conditions 815 PetscFE fe; 816 PetscInt ncompq = 5; 817 ierr = PetscFECreateLagrange(PETSC_COMM_SELF, problem->dim, ncompq, 818 PETSC_FALSE, degree, PETSC_DECIDE, 819 &fe); CHKERRQ(ierr); 820 ierr = PetscObjectSetName((PetscObject)fe, "Q"); CHKERRQ(ierr); 821 ierr = DMAddField(dm, NULL,(PetscObject)fe); CHKERRQ(ierr); 822 ierr = DMCreateDS(dm); CHKERRQ(ierr); 823 { 824 PetscInt comps[1] = {1}; 825 ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "slipx", "Face Sets", 0, 826 1, comps, (void(*)(void))NULL, NULL, bc->nslip[0], 827 bc->slips[0], ctxSetupData); CHKERRQ(ierr); 828 comps[0] = 2; 829 ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "slipy", "Face Sets", 0, 830 1, comps, (void(*)(void))NULL, NULL, bc->nslip[1], 831 bc->slips[1], ctxSetupData); CHKERRQ(ierr); 832 comps[0] = 3; 833 ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "slipz", "Face Sets", 0, 834 1, comps, (void(*)(void))NULL, NULL, bc->nslip[2], 835 bc->slips[2], ctxSetupData); CHKERRQ(ierr); 836 } 837 if (bc->userbc == PETSC_TRUE) { 838 for (PetscInt c = 0; c < 3; c++) { 839 for (PetscInt s = 0; s < bc->nslip[c]; s++) { 840 for (PetscInt w = 0; w < bc->nwall; w++) { 841 if (bc->slips[c][s] == bc->walls[w]) 842 SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, 843 "Boundary condition already set on face %D!\n", 844 bc->walls[w]); 845 } 846 } 847 } 848 } 849 // Wall boundary conditions are zero energy density and zero flux for 850 // velocity in advection/advection2d, and zero velocity and zero flux 851 // for mass density and energy density in density_current 852 { 853 if (problem->bc == Exact_Advection || problem->bc == Exact_Advection2d) { 854 PetscInt comps[1] = {4}; 855 ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", "Face Sets", 0, 856 1, comps, (void(*)(void))problem->bc, NULL, 857 bc->nwall, bc->walls, ctxSetupData); CHKERRQ(ierr); 858 } else if (problem->bc == Exact_DC) { 859 PetscInt comps[3] = {1, 2, 3}; 860 ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", "Face Sets", 0, 861 3, comps, (void(*)(void))problem->bc, NULL, 862 bc->nwall, bc->walls, ctxSetupData); CHKERRQ(ierr); 863 } else if (problem->bc == Exact_Euler) { 864 PetscInt comps[3] = {1, 2, 3}; 865 ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", "Face Sets", 0, 866 3, comps, (void(*)(void))problem->bc, NULL, 867 bc->nwall, bc->walls, ctxMMS); CHKERRQ(ierr); 868 } else 869 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, 870 "Undefined boundary conditions for this problem"); 871 } 872 ierr = DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL); 873 CHKERRQ(ierr); 874 ierr = PetscFEDestroy(&fe); CHKERRQ(ierr); 875 } 876 { 877 // Empty name for conserved field (because there is only one field) 878 PetscSection section; 879 ierr = DMGetLocalSection(dm, §ion); CHKERRQ(ierr); 880 ierr = PetscSectionSetFieldName(section, 0, ""); CHKERRQ(ierr); 881 ierr = PetscSectionSetComponentName(section, 0, 0, "Density"); 882 CHKERRQ(ierr); 883 ierr = PetscSectionSetComponentName(section, 0, 1, "MomentumX"); 884 CHKERRQ(ierr); 885 ierr = PetscSectionSetComponentName(section, 0, 2, "MomentumY"); 886 CHKERRQ(ierr); 887 ierr = PetscSectionSetComponentName(section, 0, 3, "MomentumZ"); 888 CHKERRQ(ierr); 889 ierr = PetscSectionSetComponentName(section, 0, 4, "EnergyDensity"); 890 CHKERRQ(ierr); 891 } 892 PetscFunctionReturn(0); 893 } 894 895 int main(int argc, char **argv) { 896 PetscInt ierr; 897 MPI_Comm comm; 898 DM dm, dmcoord, dmviz; 899 Mat interpviz; 900 TS ts; 901 TSAdapt adapt; 902 User user; 903 Units units; 904 EulerContext ctxEulerData; 905 char ceedresource[4096] = "/cpu/self"; 906 PetscInt localNelemVol, lnodes, gnodes, steps; 907 const PetscInt ncompq = 5; 908 PetscMPIInt rank; 909 PetscScalar ftime; 910 Vec Q, Qloc, Xloc; 911 Ceed ceed; 912 CeedInt numP, numQ; 913 CeedVector xcorners, qdata, q0ceed; 914 CeedBasis basisx, basisxc, basisq; 915 CeedElemRestriction restrictx, restrictq, restrictqdi; 916 CeedQFunction qf_setupVol, qf_ics, qf_rhsVol, qf_ifunctionVol; 917 CeedQFunctionContext ctxSetup, ctxNS, ctxAdvection2d, ctxSurface, ctxEuler; 918 CeedOperator op_setupVol, op_ics; 919 CeedScalar Rd; 920 CeedMemType memtyperequested; 921 PetscScalar WpermK, Pascal, JperkgK, mpersquareds, kgpercubicm, 922 kgpersquaredms, Joulepercubicm, Joule; 923 problemType problemChoice; 924 problemData *problem = NULL; 925 WindType wind_type; 926 StabilizationType stab; 927 EulerTestType euler_test; 928 PetscBool implicit; 929 PetscInt viz_refine = 0; 930 struct SimpleBC_ bc = { 931 .nslip = {2, 2, 2}, 932 .slips = {{5, 6}, {3, 4}, {1, 2}} 933 }; 934 double start, cpu_time_used; 935 // Test variables 936 PetscBool test; 937 PetscScalar testtol = 0.; 938 char filepath[PETSC_MAX_PATH_LEN]; 939 // Check PETSc CUDA support 940 PetscBool petschavecuda, setmemtyperequest = PETSC_FALSE; 941 // *INDENT-OFF* 942 #ifdef PETSC_HAVE_CUDA 943 petschavecuda = PETSC_TRUE; 944 #else 945 petschavecuda = PETSC_FALSE; 946 #endif 947 // *INDENT-ON* 948 949 // Create the libCEED contexts 950 PetscScalar meter = 1e-2; // 1 meter in scaled length units 951 PetscScalar second = 1e-2; // 1 second in scaled time units 952 PetscScalar kilogram = 1e-6; // 1 kilogram in scaled mass units 953 PetscScalar Kelvin = 1; // 1 Kelvin in scaled temperature units 954 CeedScalar theta0 = 300.; // K 955 CeedScalar thetaC = -15.; // K 956 CeedScalar P0 = 1.e5; // Pa 957 CeedScalar E_wind = 1.e6; // J 958 CeedScalar N = 0.01; // 1/s 959 CeedScalar cv = 717.; // J/(kg K) 960 CeedScalar cp = 1004.; // J/(kg K) 961 CeedScalar vortex_strength = 5.; // - 962 CeedScalar T_inlet = 1.; // K 963 CeedScalar P_inlet = 1.e3; // Pa 964 CeedScalar g = 9.81; // m/s^2 965 CeedScalar lambda = -2./3.; // - 966 CeedScalar mu = 75.; // Pa s, dynamic viscosity 967 // mu = 75 is not physical for air, but is good for numerical stability 968 CeedScalar k = 0.02638; // W/(m K) 969 CeedScalar CtauS = 0.; // dimensionless 970 CeedScalar strong_form = 0.; // [0,1] 971 PetscScalar lx = 8000.; // m 972 PetscScalar ly = 8000.; // m 973 PetscScalar lz = 4000.; // m 974 CeedScalar rc = 1000.; // m (Radius of bubble) 975 PetscScalar resx = 1000.; // m (resolution in x) 976 PetscScalar resy = 1000.; // m (resolution in y) 977 PetscScalar resz = 1000.; // m (resolution in z) 978 PetscInt outputfreq = 10; // - 979 PetscInt contsteps = 0; // - 980 PetscInt degree = 1; // - 981 PetscInt qextra = 2; // - 982 PetscInt qextraSur = 2; // - 983 PetscReal center[3], dc_axis[3] = {0, 0, 0}, wind[3] = {1., 0, 0}, 984 etv_mean_velocity[3] = {1., 1., 0}; 985 ierr = PetscInitialize(&argc, &argv, NULL, help); 986 if (ierr) return ierr; 987 988 // Allocate PETSc context 989 ierr = PetscCalloc1(1, &user); CHKERRQ(ierr); 990 ierr = PetscMalloc1(1, &units); CHKERRQ(ierr); 991 ierr = PetscMalloc1(1, &ctxEulerData); CHKERRQ(ierr); 992 993 // Parse command line options 994 comm = PETSC_COMM_WORLD; 995 ierr = PetscOptionsBegin(comm, NULL, "Navier-Stokes in PETSc with libCEED", 996 NULL); CHKERRQ(ierr); 997 ierr = PetscOptionsString("-ceed", "CEED resource specifier", 998 NULL, ceedresource, ceedresource, 999 sizeof(ceedresource), NULL); CHKERRQ(ierr); 1000 ierr = PetscOptionsBool("-test", "Run in test mode", 1001 NULL, test=PETSC_FALSE, &test, NULL); CHKERRQ(ierr); 1002 ierr = PetscOptionsScalar("-compare_final_state_atol", 1003 "Test absolute tolerance", 1004 NULL, testtol, &testtol, NULL); CHKERRQ(ierr); 1005 ierr = PetscOptionsString("-compare_final_state_filename", "Test filename", 1006 NULL, filepath, filepath, 1007 sizeof(filepath), NULL); CHKERRQ(ierr); 1008 problemChoice = NS_DENSITY_CURRENT; 1009 ierr = PetscOptionsEnum("-problem", "Problem to solve", NULL, 1010 problemTypes, (PetscEnum)problemChoice, 1011 (PetscEnum *)&problemChoice, NULL); CHKERRQ(ierr); 1012 problem = &problemOptions[problemChoice]; 1013 ierr = PetscOptionsEnum("-problem_advection_wind", "Wind type in Advection", 1014 NULL, WindTypes, 1015 (PetscEnum)(wind_type = ADVECTION_WIND_ROTATION), 1016 (PetscEnum *)&wind_type, NULL); CHKERRQ(ierr); 1017 PetscInt n = problem->dim; 1018 PetscBool userWind; 1019 ierr = PetscOptionsRealArray("-problem_advection_wind_translation", 1020 "Constant wind vector", 1021 NULL, wind, &n, &userWind); CHKERRQ(ierr); 1022 if (wind_type == ADVECTION_WIND_ROTATION && userWind) { 1023 ierr = PetscPrintf(comm, 1024 "Warning! Use -problem_advection_wind_translation only with -problem_advection_wind translation\n"); 1025 CHKERRQ(ierr); 1026 } 1027 if (wind_type == ADVECTION_WIND_TRANSLATION 1028 && (problemChoice == NS_DENSITY_CURRENT || 1029 problemChoice == NS_EULER_VORTEX)) { 1030 SETERRQ(comm, PETSC_ERR_ARG_INCOMP, 1031 "-problem_advection_wind translation is not defined for -problem density_current or -problem euler_vortex"); 1032 } 1033 n = problem->dim; 1034 ierr = PetscOptionsRealArray("-problem_euler_mean_velocity", 1035 "Mean velocity vector", 1036 NULL, etv_mean_velocity, &n, NULL); 1037 CHKERRQ(ierr); 1038 ierr = PetscOptionsEnum("-stab", "Stabilization method", NULL, 1039 StabilizationTypes, (PetscEnum)(stab = STAB_NONE), 1040 (PetscEnum *)&stab, NULL); CHKERRQ(ierr); 1041 ierr = PetscOptionsEnum("-euler_test", "Euler test option", NULL, 1042 EulerTestTypes, (PetscEnum)(euler_test = EULER_TEST_NONE), 1043 (PetscEnum *)&euler_test, NULL); CHKERRQ(ierr); 1044 ierr = PetscOptionsBool("-implicit", "Use implicit (IFunction) formulation", 1045 NULL, implicit=PETSC_FALSE, &implicit, NULL); 1046 CHKERRQ(ierr); 1047 if (!implicit && stab != STAB_NONE) { 1048 ierr = PetscPrintf(comm, "Warning! Use -stab only with -implicit\n"); 1049 CHKERRQ(ierr); 1050 } 1051 { 1052 PetscInt len; 1053 PetscBool flg; 1054 ierr = PetscOptionsIntArray("-bc_wall", 1055 "Use wall boundary conditions on this list of faces", 1056 NULL, bc.walls, 1057 (len = sizeof(bc.walls) / sizeof(bc.walls[0]), 1058 &len), &flg); CHKERRQ(ierr); 1059 if (flg) { 1060 bc.nwall = len; 1061 // Using a no-slip wall disables automatic slip walls (they must be set explicitly) 1062 bc.nslip[0] = bc.nslip[1] = bc.nslip[2] = 0; 1063 } 1064 for (PetscInt j=0; j<3; j++) { 1065 const char *flags[3] = {"-bc_slip_x", "-bc_slip_y", "-bc_slip_z"}; 1066 ierr = PetscOptionsIntArray(flags[j], 1067 "Use slip boundary conditions on this list of faces", 1068 NULL, bc.slips[j], 1069 (len = sizeof(bc.slips[j]) / sizeof(bc.slips[j][0]), 1070 &len), &flg); 1071 CHKERRQ(ierr); 1072 if (flg) { 1073 bc.nslip[j] = len; 1074 bc.userbc = PETSC_TRUE; 1075 } 1076 } 1077 } 1078 ierr = PetscOptionsInt("-viz_refine", 1079 "Regular refinement levels for visualization", 1080 NULL, viz_refine, &viz_refine, NULL); 1081 CHKERRQ(ierr); 1082 ierr = PetscOptionsScalar("-units_meter", "1 meter in scaled length units", 1083 NULL, meter, &meter, NULL); CHKERRQ(ierr); 1084 meter = fabs(meter); 1085 ierr = PetscOptionsScalar("-units_second","1 second in scaled time units", 1086 NULL, second, &second, NULL); CHKERRQ(ierr); 1087 second = fabs(second); 1088 ierr = PetscOptionsScalar("-units_kilogram","1 kilogram in scaled mass units", 1089 NULL, kilogram, &kilogram, NULL); CHKERRQ(ierr); 1090 kilogram = fabs(kilogram); 1091 ierr = PetscOptionsScalar("-units_Kelvin", 1092 "1 Kelvin in scaled temperature units", 1093 NULL, Kelvin, &Kelvin, NULL); CHKERRQ(ierr); 1094 Kelvin = fabs(Kelvin); 1095 ierr = PetscOptionsScalar("-theta0", "Reference potential temperature", 1096 NULL, theta0, &theta0, NULL); CHKERRQ(ierr); 1097 ierr = PetscOptionsScalar("-thetaC", "Perturbation of potential temperature", 1098 NULL, thetaC, &thetaC, NULL); CHKERRQ(ierr); 1099 ierr = PetscOptionsScalar("-P0", "Atmospheric pressure", 1100 NULL, P0, &P0, NULL); CHKERRQ(ierr); 1101 ierr = PetscOptionsScalar("-E_wind", "Total energy of inflow wind", 1102 NULL, E_wind, &E_wind, NULL); CHKERRQ(ierr); 1103 ierr = PetscOptionsScalar("-N", "Brunt-Vaisala frequency", 1104 NULL, N, &N, NULL); CHKERRQ(ierr); 1105 ierr = PetscOptionsScalar("-cv", "Heat capacity at constant volume", 1106 NULL, cv, &cv, NULL); CHKERRQ(ierr); 1107 ierr = PetscOptionsScalar("-cp", "Heat capacity at constant pressure", 1108 NULL, cp, &cp, NULL); CHKERRQ(ierr); 1109 PetscBool userVortex; 1110 ierr = PetscOptionsScalar("-vortex_strength", "Strength of Vortex", 1111 NULL, vortex_strength, &vortex_strength, &userVortex); 1112 CHKERRQ(ierr); 1113 if (problemChoice != NS_EULER_VORTEX && userVortex) { 1114 ierr = PetscPrintf(comm, 1115 "Warning! Use -vortex_strength only with -problem euler_vortex\n"); 1116 CHKERRQ(ierr); 1117 } 1118 PetscBool userTinlet; 1119 ierr = PetscOptionsScalar("-T_inlet", "Incoming Temperature", 1120 NULL, T_inlet, &T_inlet, &userTinlet); 1121 CHKERRQ(ierr); 1122 if (problemChoice != NS_EULER_VORTEX && userTinlet) { 1123 ierr = PetscPrintf(comm, 1124 "Warning! Use -T_inlet only with -problem euler_vortex\n"); 1125 CHKERRQ(ierr); 1126 } 1127 PetscBool userPinlet; 1128 ierr = PetscOptionsScalar("-P_inlet", "Incoming Pressure", 1129 NULL, P_inlet, &P_inlet, &userPinlet); 1130 CHKERRQ(ierr); 1131 if (problemChoice != NS_EULER_VORTEX && userPinlet) { 1132 ierr = PetscPrintf(comm, 1133 "Warning! Use -P_inlet only with -problem euler_vortex\n"); 1134 CHKERRQ(ierr); 1135 } 1136 ierr = PetscOptionsScalar("-g", "Gravitational acceleration", 1137 NULL, g, &g, NULL); CHKERRQ(ierr); 1138 ierr = PetscOptionsScalar("-lambda", 1139 "Stokes hypothesis second viscosity coefficient", 1140 NULL, lambda, &lambda, NULL); CHKERRQ(ierr); 1141 ierr = PetscOptionsScalar("-mu", "Shear dynamic viscosity coefficient", 1142 NULL, mu, &mu, NULL); CHKERRQ(ierr); 1143 ierr = PetscOptionsScalar("-k", "Thermal conductivity", 1144 NULL, k, &k, NULL); CHKERRQ(ierr); 1145 ierr = PetscOptionsScalar("-CtauS", 1146 "Scale coefficient for tau (nondimensional)", 1147 NULL, CtauS, &CtauS, NULL); CHKERRQ(ierr); 1148 if (stab == STAB_NONE && CtauS != 0) { 1149 ierr = PetscPrintf(comm, 1150 "Warning! Use -CtauS only with -stab su or -stab supg\n"); 1151 CHKERRQ(ierr); 1152 } 1153 ierr = PetscOptionsScalar("-strong_form", 1154 "Strong (1) or weak/integrated by parts (0) advection residual", 1155 NULL, strong_form, &strong_form, NULL); 1156 CHKERRQ(ierr); 1157 if (problemChoice == NS_DENSITY_CURRENT && (CtauS != 0 || strong_form != 0)) { 1158 ierr = PetscPrintf(comm, 1159 "Warning! Problem density_current does not support -CtauS or -strong_form\n"); 1160 CHKERRQ(ierr); 1161 } 1162 ierr = PetscOptionsScalar("-lx", "Length scale in x direction", 1163 NULL, lx, &lx, NULL); CHKERRQ(ierr); 1164 ierr = PetscOptionsScalar("-ly", "Length scale in y direction", 1165 NULL, ly, &ly, NULL); CHKERRQ(ierr); 1166 ierr = PetscOptionsScalar("-lz", "Length scale in z direction", 1167 NULL, lz, &lz, NULL); CHKERRQ(ierr); 1168 ierr = PetscOptionsScalar("-rc", "Characteristic radius of thermal bubble", 1169 NULL, rc, &rc, NULL); CHKERRQ(ierr); 1170 ierr = PetscOptionsScalar("-resx","Target resolution in x", 1171 NULL, resx, &resx, NULL); CHKERRQ(ierr); 1172 ierr = PetscOptionsScalar("-resy","Target resolution in y", 1173 NULL, resy, &resy, NULL); CHKERRQ(ierr); 1174 ierr = PetscOptionsScalar("-resz","Target resolution in z", 1175 NULL, resz, &resz, NULL); CHKERRQ(ierr); 1176 n = problem->dim; 1177 center[0] = 0.5 * lx; 1178 center[1] = 0.5 * ly; 1179 center[2] = 0.5 * lz; 1180 ierr = PetscOptionsRealArray("-center", "Location of bubble center", 1181 NULL, center, &n, NULL); CHKERRQ(ierr); 1182 n = problem->dim; 1183 ierr = PetscOptionsRealArray("-dc_axis", 1184 "Axis of density current cylindrical anomaly, or {0,0,0} for spherically symmetric", 1185 NULL, dc_axis, &n, NULL); CHKERRQ(ierr); 1186 { 1187 PetscReal norm = PetscSqrtReal(PetscSqr(dc_axis[0]) + 1188 PetscSqr(dc_axis[1]) + PetscSqr(dc_axis[2])); 1189 if (norm > 0) { 1190 for (int i=0; i<3; i++) dc_axis[i] /= norm; 1191 } 1192 } 1193 ierr = PetscOptionsInt("-output_freq", 1194 "Frequency of output, in number of steps", 1195 NULL, outputfreq, &outputfreq, NULL); CHKERRQ(ierr); 1196 ierr = PetscOptionsInt("-continue", "Continue from previous solution", 1197 NULL, contsteps, &contsteps, NULL); CHKERRQ(ierr); 1198 ierr = PetscOptionsInt("-degree", "Polynomial degree of finite elements", 1199 NULL, degree, °ree, NULL); CHKERRQ(ierr); 1200 ierr = PetscOptionsInt("-qextra", "Number of extra quadrature points", 1201 NULL, qextra, &qextra, NULL); CHKERRQ(ierr); 1202 PetscBool userQextraSur; 1203 ierr = PetscOptionsInt("-qextra_boundary", 1204 "Number of extra quadrature points on in/outflow faces", 1205 NULL, qextraSur, &qextraSur, &userQextraSur); 1206 CHKERRQ(ierr); 1207 if ((wind_type == ADVECTION_WIND_ROTATION 1208 || problemChoice == NS_DENSITY_CURRENT) && userQextraSur) { 1209 ierr = PetscPrintf(comm, 1210 "Warning! Use -qextra_boundary only with -problem_advection_wind translation\n"); 1211 CHKERRQ(ierr); 1212 } 1213 ierr = PetscStrncpy(user->outputdir, ".", 2); CHKERRQ(ierr); 1214 ierr = PetscOptionsString("-output_dir", "Output directory", 1215 NULL, user->outputdir, user->outputdir, 1216 sizeof(user->outputdir), NULL); CHKERRQ(ierr); 1217 memtyperequested = petschavecuda ? CEED_MEM_DEVICE : CEED_MEM_HOST; 1218 ierr = PetscOptionsEnum("-memtype", 1219 "CEED MemType requested", NULL, 1220 memTypes, (PetscEnum)memtyperequested, 1221 (PetscEnum *)&memtyperequested, &setmemtyperequest); 1222 CHKERRQ(ierr); 1223 ierr = PetscOptionsEnd(); CHKERRQ(ierr); 1224 1225 // Define derived units 1226 Pascal = kilogram / (meter * PetscSqr(second)); 1227 JperkgK = PetscSqr(meter) / (PetscSqr(second) * Kelvin); 1228 mpersquareds = meter / PetscSqr(second); 1229 WpermK = kilogram * meter / (pow(second,3) * Kelvin); 1230 kgpercubicm = kilogram / pow(meter,3); 1231 kgpersquaredms = kilogram / (PetscSqr(meter) * second); 1232 Joulepercubicm = kilogram / (meter * PetscSqr(second)); 1233 Joule = kilogram * PetscSqr(meter) / PetscSqr(second); 1234 1235 // Scale variables to desired units 1236 theta0 *= Kelvin; 1237 thetaC *= Kelvin; 1238 P0 *= Pascal; 1239 E_wind *= Joule; 1240 N *= (1./second); 1241 cv *= JperkgK; 1242 cp *= JperkgK; 1243 Rd = cp - cv; 1244 T_inlet *= Kelvin; 1245 P_inlet *= Pascal; 1246 g *= mpersquareds; 1247 mu *= Pascal * second; 1248 k *= WpermK; 1249 lx = fabs(lx) * meter; 1250 ly = fabs(ly) * meter; 1251 lz = fabs(lz) * meter; 1252 rc = fabs(rc) * meter; 1253 resx = fabs(resx) * meter; 1254 resy = fabs(resy) * meter; 1255 resz = fabs(resz) * meter; 1256 for (int i=0; i<3; i++) center[i] *= meter; 1257 1258 const CeedInt dim = problem->dim, ncompx = problem->dim, 1259 qdatasizeVol = problem->qdatasizeVol; 1260 // Set up the libCEED context 1261 struct SetupContext_ ctxSetupData = { 1262 .theta0 = theta0, 1263 .thetaC = thetaC, 1264 .P0 = P0, 1265 .N = N, 1266 .cv = cv, 1267 .cp = cp, 1268 .Rd = Rd, 1269 .g = g, 1270 .rc = rc, 1271 .lx = lx, 1272 .ly = ly, 1273 .lz = lz, 1274 .center[0] = center[0], 1275 .center[1] = center[1], 1276 .center[2] = center[2], 1277 .dc_axis[0] = dc_axis[0], 1278 .dc_axis[1] = dc_axis[1], 1279 .dc_axis[2] = dc_axis[2], 1280 .wind[0] = wind[0], 1281 .wind[1] = wind[1], 1282 .wind[2] = wind[2], 1283 .time = 0, 1284 .vortex_strength = vortex_strength, 1285 .wind_type = wind_type, 1286 }; 1287 1288 // Create the mesh 1289 { 1290 const PetscReal scale[3] = {lx, ly, lz}; 1291 ierr = DMPlexCreateBoxMesh(comm, dim, PETSC_FALSE, NULL, NULL, scale, 1292 NULL, PETSC_TRUE, &dm); 1293 CHKERRQ(ierr); 1294 } 1295 1296 // Distribute the mesh over processes 1297 { 1298 DM dmDist = NULL; 1299 PetscPartitioner part; 1300 1301 ierr = DMPlexGetPartitioner(dm, &part); CHKERRQ(ierr); 1302 ierr = PetscPartitionerSetFromOptions(part); CHKERRQ(ierr); 1303 ierr = DMPlexDistribute(dm, 0, NULL, &dmDist); CHKERRQ(ierr); 1304 if (dmDist) { 1305 ierr = DMDestroy(&dm); CHKERRQ(ierr); 1306 dm = dmDist; 1307 } 1308 } 1309 ierr = DMViewFromOptions(dm, NULL, "-dm_view"); CHKERRQ(ierr); 1310 1311 // Setup DM 1312 ierr = DMLocalizeCoordinates(dm); CHKERRQ(ierr); 1313 ierr = DMSetFromOptions(dm); CHKERRQ(ierr); 1314 ierr = SetUpDM(dm, problem, degree, &bc, &ctxSetupData, ctxEulerData); 1315 CHKERRQ(ierr); 1316 1317 // Refine DM for high-order viz 1318 dmviz = NULL; 1319 interpviz = NULL; 1320 if (viz_refine) { 1321 DM dmhierarchy[viz_refine+1]; 1322 1323 ierr = DMPlexSetRefinementUniform(dm, PETSC_TRUE); CHKERRQ(ierr); 1324 dmhierarchy[0] = dm; 1325 for (PetscInt i = 0, d = degree; i < viz_refine; i++) { 1326 Mat interp_next; 1327 1328 ierr = DMRefine(dmhierarchy[i], MPI_COMM_NULL, &dmhierarchy[i+1]); 1329 CHKERRQ(ierr); 1330 ierr = DMClearDS(dmhierarchy[i+1]); CHKERRQ(ierr); 1331 ierr = DMClearFields(dmhierarchy[i+1]); CHKERRQ(ierr); 1332 ierr = DMSetCoarseDM(dmhierarchy[i+1], dmhierarchy[i]); CHKERRQ(ierr); 1333 d = (d + 1) / 2; 1334 if (i + 1 == viz_refine) d = 1; 1335 ierr = SetUpDM(dmhierarchy[i+1], problem, d, &bc, &ctxSetupData, 1336 ctxEulerData); CHKERRQ(ierr); 1337 ierr = DMCreateInterpolation(dmhierarchy[i], dmhierarchy[i+1], 1338 &interp_next, NULL); CHKERRQ(ierr); 1339 if (!i) interpviz = interp_next; 1340 else { 1341 Mat C; 1342 ierr = MatMatMult(interp_next, interpviz, MAT_INITIAL_MATRIX, 1343 PETSC_DECIDE, &C); CHKERRQ(ierr); 1344 ierr = MatDestroy(&interp_next); CHKERRQ(ierr); 1345 ierr = MatDestroy(&interpviz); CHKERRQ(ierr); 1346 interpviz = C; 1347 } 1348 } 1349 for (PetscInt i=1; i<viz_refine; i++) { 1350 ierr = DMDestroy(&dmhierarchy[i]); CHKERRQ(ierr); 1351 } 1352 dmviz = dmhierarchy[viz_refine]; 1353 } 1354 ierr = DMCreateGlobalVector(dm, &Q); CHKERRQ(ierr); 1355 ierr = DMGetLocalVector(dm, &Qloc); CHKERRQ(ierr); 1356 ierr = VecGetSize(Qloc, &lnodes); CHKERRQ(ierr); 1357 lnodes /= ncompq; 1358 1359 // Initialize CEED 1360 CeedInit(ceedresource, &ceed); 1361 // Set memtype 1362 CeedMemType memtypebackend; 1363 CeedGetPreferredMemType(ceed, &memtypebackend); 1364 // Check memtype compatibility 1365 if (!setmemtyperequest) 1366 memtyperequested = memtypebackend; 1367 else if (!petschavecuda && memtyperequested == CEED_MEM_DEVICE) 1368 SETERRQ1(PETSC_COMM_WORLD, PETSC_ERR_SUP_SYS, 1369 "PETSc was not built with CUDA. " 1370 "Requested MemType CEED_MEM_DEVICE is not supported.", NULL); 1371 1372 // Set number of 1D nodes and quadrature points 1373 numP = degree + 1; 1374 numQ = numP + qextra; 1375 1376 // Print summary 1377 if (!test) { 1378 CeedInt gdofs, odofs; 1379 int comm_size; 1380 char box_faces_str[PETSC_MAX_PATH_LEN] = "NONE"; 1381 ierr = VecGetSize(Q, &gdofs); CHKERRQ(ierr); 1382 ierr = VecGetLocalSize(Q, &odofs); CHKERRQ(ierr); 1383 gnodes = gdofs/ncompq; 1384 ierr = MPI_Comm_size(comm, &comm_size); CHKERRQ(ierr); 1385 ierr = PetscOptionsGetString(NULL, NULL, "-dm_plex_box_faces", box_faces_str, 1386 sizeof(box_faces_str), NULL); CHKERRQ(ierr); 1387 const char *usedresource; 1388 CeedGetResource(ceed, &usedresource); 1389 1390 ierr = PetscPrintf(comm, 1391 "\n-- Navier-Stokes solver - libCEED + PETSc --\n" 1392 " rank(s) : %d\n" 1393 " Problem:\n" 1394 " Problem Name : %s\n" 1395 " Stabilization : %s\n" 1396 " PETSc:\n" 1397 " Box Faces : %s\n" 1398 " libCEED:\n" 1399 " libCEED Backend : %s\n" 1400 " libCEED Backend MemType : %s\n" 1401 " libCEED User Requested MemType : %s\n" 1402 " Mesh:\n" 1403 " Number of 1D Basis Nodes (P) : %d\n" 1404 " Number of 1D Quadrature Points (Q) : %d\n" 1405 " Global DoFs : %D\n" 1406 " Owned DoFs : %D\n" 1407 " DoFs per node : %D\n" 1408 " Global nodes : %D\n" 1409 " Owned nodes : %D\n", 1410 comm_size, problemTypes[problemChoice], 1411 StabilizationTypes[stab], box_faces_str, usedresource, 1412 CeedMemTypes[memtypebackend], 1413 (setmemtyperequest) ? 1414 CeedMemTypes[memtyperequested] : "none", 1415 numP, numQ, gdofs, odofs, ncompq, gnodes, lnodes); 1416 CHKERRQ(ierr); 1417 } 1418 1419 // Set up global mass vector 1420 ierr = VecDuplicate(Q, &user->M); CHKERRQ(ierr); 1421 1422 // Set up libCEED 1423 // CEED Bases 1424 CeedInit(ceedresource, &ceed); 1425 CeedBasisCreateTensorH1Lagrange(ceed, dim, ncompq, numP, numQ, CEED_GAUSS, 1426 &basisq); 1427 CeedBasisCreateTensorH1Lagrange(ceed, dim, ncompx, 2, numQ, CEED_GAUSS, 1428 &basisx); 1429 CeedBasisCreateTensorH1Lagrange(ceed, dim, ncompx, 2, numP, 1430 CEED_GAUSS_LOBATTO, &basisxc); 1431 ierr = DMGetCoordinateDM(dm, &dmcoord); CHKERRQ(ierr); 1432 ierr = DMPlexSetClosurePermutationTensor(dmcoord, PETSC_DETERMINE, NULL); 1433 CHKERRQ(ierr); 1434 1435 // CEED Restrictions 1436 ierr = GetRestrictionForDomain(ceed, dm, 0, 0, 0, numP, numQ, 1437 qdatasizeVol, &restrictq, &restrictx, 1438 &restrictqdi); CHKERRQ(ierr); 1439 1440 ierr = DMGetCoordinatesLocal(dm, &Xloc); CHKERRQ(ierr); 1441 ierr = CreateVectorFromPetscVec(ceed, Xloc, &xcorners); CHKERRQ(ierr); 1442 1443 // Create the CEED vectors that will be needed in setup 1444 CeedInt NqptsVol; 1445 CeedBasisGetNumQuadraturePoints(basisq, &NqptsVol); 1446 CeedElemRestrictionGetNumElements(restrictq, &localNelemVol); 1447 CeedVectorCreate(ceed, qdatasizeVol*localNelemVol*NqptsVol, &qdata); 1448 CeedElemRestrictionCreateVector(restrictq, &q0ceed, NULL); 1449 1450 // Create the Q-function that builds the quadrature data for the NS operator 1451 CeedQFunctionCreateInterior(ceed, 1, problem->setupVol, problem->setupVol_loc, 1452 &qf_setupVol); 1453 CeedQFunctionAddInput(qf_setupVol, "dx", ncompx*dim, CEED_EVAL_GRAD); 1454 CeedQFunctionAddInput(qf_setupVol, "weight", 1, CEED_EVAL_WEIGHT); 1455 CeedQFunctionAddOutput(qf_setupVol, "qdata", qdatasizeVol, CEED_EVAL_NONE); 1456 1457 // Create the Q-function that sets the ICs of the operator 1458 CeedQFunctionCreateInterior(ceed, 1, problem->ics, problem->ics_loc, &qf_ics); 1459 CeedQFunctionAddInput(qf_ics, "x", ncompx, CEED_EVAL_INTERP); 1460 CeedQFunctionAddOutput(qf_ics, "q0", ncompq, CEED_EVAL_NONE); 1461 1462 qf_rhsVol = NULL; 1463 if (problem->applyVol_rhs) { // Create the Q-function that defines the action of the RHS operator 1464 CeedQFunctionCreateInterior(ceed, 1, problem->applyVol_rhs, 1465 problem->applyVol_rhs_loc, &qf_rhsVol); 1466 CeedQFunctionAddInput(qf_rhsVol, "q", ncompq, CEED_EVAL_INTERP); 1467 CeedQFunctionAddInput(qf_rhsVol, "dq", ncompq*dim, CEED_EVAL_GRAD); 1468 CeedQFunctionAddInput(qf_rhsVol, "qdata", qdatasizeVol, CEED_EVAL_NONE); 1469 CeedQFunctionAddInput(qf_rhsVol, "x", ncompx, CEED_EVAL_INTERP); 1470 CeedQFunctionAddOutput(qf_rhsVol, "v", ncompq, CEED_EVAL_INTERP); 1471 CeedQFunctionAddOutput(qf_rhsVol, "dv", ncompq*dim, CEED_EVAL_GRAD); 1472 } 1473 1474 qf_ifunctionVol = NULL; 1475 if (problem->applyVol_ifunction) { // Create the Q-function that defines the action of the IFunction 1476 CeedQFunctionCreateInterior(ceed, 1, problem->applyVol_ifunction, 1477 problem->applyVol_ifunction_loc, &qf_ifunctionVol); 1478 CeedQFunctionAddInput(qf_ifunctionVol, "q", ncompq, CEED_EVAL_INTERP); 1479 CeedQFunctionAddInput(qf_ifunctionVol, "dq", ncompq*dim, CEED_EVAL_GRAD); 1480 CeedQFunctionAddInput(qf_ifunctionVol, "qdot", ncompq, CEED_EVAL_INTERP); 1481 CeedQFunctionAddInput(qf_ifunctionVol, "qdata", qdatasizeVol, CEED_EVAL_NONE); 1482 CeedQFunctionAddInput(qf_ifunctionVol, "x", ncompx, CEED_EVAL_INTERP); 1483 CeedQFunctionAddOutput(qf_ifunctionVol, "v", ncompq, CEED_EVAL_INTERP); 1484 CeedQFunctionAddOutput(qf_ifunctionVol, "dv", ncompq*dim, CEED_EVAL_GRAD); 1485 } 1486 1487 // Create the operator that builds the quadrature data for the NS operator 1488 CeedOperatorCreate(ceed, qf_setupVol, NULL, NULL, &op_setupVol); 1489 CeedOperatorSetField(op_setupVol, "dx", restrictx, basisx, CEED_VECTOR_ACTIVE); 1490 CeedOperatorSetField(op_setupVol, "weight", CEED_ELEMRESTRICTION_NONE, 1491 basisx, CEED_VECTOR_NONE); 1492 CeedOperatorSetField(op_setupVol, "qdata", restrictqdi, 1493 CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE); 1494 1495 // Create the operator that sets the ICs 1496 CeedOperatorCreate(ceed, qf_ics, NULL, NULL, &op_ics); 1497 CeedOperatorSetField(op_ics, "x", restrictx, basisxc, CEED_VECTOR_ACTIVE); 1498 CeedOperatorSetField(op_ics, "q0", restrictq, 1499 CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE); 1500 1501 CeedElemRestrictionCreateVector(restrictq, &user->qceed, NULL); 1502 CeedElemRestrictionCreateVector(restrictq, &user->qdotceed, NULL); 1503 CeedElemRestrictionCreateVector(restrictq, &user->gceed, NULL); 1504 1505 if (qf_rhsVol) { // Create the RHS physics operator 1506 CeedOperator op; 1507 CeedOperatorCreate(ceed, qf_rhsVol, NULL, NULL, &op); 1508 CeedOperatorSetField(op, "q", restrictq, basisq, CEED_VECTOR_ACTIVE); 1509 CeedOperatorSetField(op, "dq", restrictq, basisq, CEED_VECTOR_ACTIVE); 1510 CeedOperatorSetField(op, "qdata", restrictqdi, 1511 CEED_BASIS_COLLOCATED, qdata); 1512 CeedOperatorSetField(op, "x", restrictx, basisx, xcorners); 1513 CeedOperatorSetField(op, "v", restrictq, basisq, CEED_VECTOR_ACTIVE); 1514 CeedOperatorSetField(op, "dv", restrictq, basisq, CEED_VECTOR_ACTIVE); 1515 user->op_rhs_vol = op; 1516 } 1517 1518 if (qf_ifunctionVol) { // Create the IFunction operator 1519 CeedOperator op; 1520 CeedOperatorCreate(ceed, qf_ifunctionVol, NULL, NULL, &op); 1521 CeedOperatorSetField(op, "q", restrictq, basisq, CEED_VECTOR_ACTIVE); 1522 CeedOperatorSetField(op, "dq", restrictq, basisq, CEED_VECTOR_ACTIVE); 1523 CeedOperatorSetField(op, "qdot", restrictq, basisq, user->qdotceed); 1524 CeedOperatorSetField(op, "qdata", restrictqdi, 1525 CEED_BASIS_COLLOCATED, qdata); 1526 CeedOperatorSetField(op, "x", restrictx, basisx, xcorners); 1527 CeedOperatorSetField(op, "v", restrictq, basisq, CEED_VECTOR_ACTIVE); 1528 CeedOperatorSetField(op, "dv", restrictq, basisq, CEED_VECTOR_ACTIVE); 1529 user->op_ifunction_vol = op; 1530 } 1531 1532 // Set up CEED for the boundaries 1533 CeedInt height = 1; 1534 CeedInt dimSur = dim - height; 1535 CeedInt numP_Sur = degree + 1; 1536 CeedInt numQ_Sur = numP_Sur + qextraSur; 1537 const CeedInt qdatasizeSur = problem->qdatasizeSur; 1538 CeedBasis basisxSur, basisxcSur, basisqSur; 1539 CeedInt NqptsSur; 1540 CeedQFunction qf_setupSur, qf_applySur; 1541 1542 // CEED bases for the boundaries 1543 CeedBasisCreateTensorH1Lagrange(ceed, dimSur, ncompq, numP_Sur, numQ_Sur, 1544 CEED_GAUSS, 1545 &basisqSur); 1546 CeedBasisCreateTensorH1Lagrange(ceed, dimSur, ncompx, 2, numQ_Sur, CEED_GAUSS, 1547 &basisxSur); 1548 CeedBasisCreateTensorH1Lagrange(ceed, dimSur, ncompx, 2, numP_Sur, 1549 CEED_GAUSS_LOBATTO, &basisxcSur); 1550 CeedBasisGetNumQuadraturePoints(basisqSur, &NqptsSur); 1551 1552 // Create the Q-function that builds the quadrature data for the Surface operator 1553 CeedQFunctionCreateInterior(ceed, 1, problem->setupSur, problem->setupSur_loc, 1554 &qf_setupSur); 1555 CeedQFunctionAddInput(qf_setupSur, "dx", ncompx*dimSur, CEED_EVAL_GRAD); 1556 CeedQFunctionAddInput(qf_setupSur, "weight", 1, CEED_EVAL_WEIGHT); 1557 CeedQFunctionAddOutput(qf_setupSur, "qdataSur", qdatasizeSur, CEED_EVAL_NONE); 1558 1559 // Creat Q-Function for Boundaries 1560 // -- Defined for Advection(2d) test cases 1561 qf_applySur = NULL; 1562 if (problem->applySur) { 1563 CeedQFunctionCreateInterior(ceed, 1, problem->applySur, 1564 problem->applySur_loc, &qf_applySur); 1565 CeedQFunctionAddInput(qf_applySur, "q", ncompq, CEED_EVAL_INTERP); 1566 CeedQFunctionAddInput(qf_applySur, "qdataSur", qdatasizeSur, CEED_EVAL_NONE); 1567 CeedQFunctionAddInput(qf_applySur, "x", ncompx, CEED_EVAL_INTERP); 1568 CeedQFunctionAddOutput(qf_applySur, "v", ncompq, CEED_EVAL_INTERP); 1569 } 1570 1571 // Create CEED Operator for the whole domain 1572 if (!implicit) 1573 ierr = CreateOperatorForDomain(ceed, dm, &bc, problemChoice, wind_type, 1574 user->op_rhs_vol, qf_applySur, 1575 qf_setupSur, height, numP_Sur, numQ_Sur, 1576 qdatasizeSur, NqptsSur, basisxSur, 1577 basisqSur, &user->op_rhs); 1578 CHKERRQ(ierr); 1579 if (implicit) 1580 ierr = CreateOperatorForDomain(ceed, dm, &bc, problemChoice, wind_type, 1581 user->op_ifunction_vol, qf_applySur, 1582 qf_setupSur, height, numP_Sur, numQ_Sur, 1583 qdatasizeSur, NqptsSur, basisxSur, 1584 basisqSur, &user->op_ifunction); 1585 CHKERRQ(ierr); 1586 // Set up contex for QFunctions 1587 CeedQFunctionContextCreate(ceed, &ctxSetup); 1588 CeedQFunctionContextSetData(ctxSetup, CEED_MEM_HOST, CEED_USE_POINTER, 1589 sizeof ctxSetupData, &ctxSetupData); 1590 if (qf_ics && problemChoice != NS_EULER_VORTEX) 1591 CeedQFunctionSetContext(qf_ics, ctxSetup); 1592 1593 CeedScalar ctxNSData[8] = {lambda, mu, k, cv, cp, g, Rd}; 1594 CeedQFunctionContextCreate(ceed, &ctxNS); 1595 CeedQFunctionContextSetData(ctxNS, CEED_MEM_HOST, CEED_USE_POINTER, 1596 sizeof ctxNSData, &ctxNSData); 1597 1598 struct Advection2dContext_ ctxAdvection2dData = { 1599 .CtauS = CtauS, 1600 .strong_form = strong_form, 1601 .stabilization = stab, 1602 }; 1603 CeedQFunctionContextCreate(ceed, &ctxAdvection2d); 1604 CeedQFunctionContextSetData(ctxAdvection2d, CEED_MEM_HOST, CEED_USE_POINTER, 1605 sizeof ctxAdvection2dData, &ctxAdvection2dData); 1606 1607 struct SurfaceContext_ ctxSurfaceData = { 1608 .E_wind = E_wind, 1609 .strong_form = strong_form, 1610 .T_inlet = T_inlet, 1611 .P_inlet = P_inlet, 1612 .etv_mean_velocity[0] = etv_mean_velocity[0], 1613 .etv_mean_velocity[1] = etv_mean_velocity[1], 1614 .etv_mean_velocity[2] = etv_mean_velocity[2], 1615 .implicit = implicit, 1616 }; 1617 CeedQFunctionContextCreate(ceed, &ctxSurface); 1618 CeedQFunctionContextSetData(ctxSurface, CEED_MEM_HOST, CEED_USE_POINTER, 1619 sizeof ctxSurfaceData, &ctxSurfaceData); 1620 1621 // Set up ctxEulerData structure 1622 ctxEulerData->time = 0.; 1623 ctxEulerData->currentTime = 0.; 1624 ctxEulerData->euler_test = euler_test; 1625 ctxEulerData->center[0] = center[0]; 1626 ctxEulerData->center[1] = center[1]; 1627 ctxEulerData->center[2] = center[2]; 1628 ctxEulerData->vortex_strength = vortex_strength; 1629 ctxEulerData->etv_mean_velocity[0] = etv_mean_velocity[0]; 1630 ctxEulerData->etv_mean_velocity[1] = etv_mean_velocity[1]; 1631 ctxEulerData->etv_mean_velocity[2] = etv_mean_velocity[2]; 1632 user->ctxEulerData = ctxEulerData; 1633 1634 CeedQFunctionContextCreate(ceed, &ctxEuler); 1635 CeedQFunctionContextSetData(ctxEuler, CEED_MEM_HOST, CEED_USE_POINTER, 1636 sizeof *ctxEulerData, ctxEulerData); 1637 1638 switch (problemChoice) { 1639 case NS_DENSITY_CURRENT: 1640 if (qf_rhsVol) CeedQFunctionSetContext(qf_rhsVol, ctxNS); 1641 if (qf_ifunctionVol) CeedQFunctionSetContext(qf_ifunctionVol, ctxNS); 1642 break; 1643 case NS_ADVECTION: 1644 case NS_ADVECTION2D: 1645 if (qf_rhsVol) CeedQFunctionSetContext(qf_rhsVol, ctxAdvection2d); 1646 if (qf_ifunctionVol) CeedQFunctionSetContext(qf_ifunctionVol, ctxAdvection2d); 1647 if (qf_applySur) CeedQFunctionSetContext(qf_applySur, ctxSurface); 1648 case NS_EULER_VORTEX: 1649 if (qf_ics) CeedQFunctionSetContext(qf_ics, ctxEuler); 1650 if (qf_rhsVol) CeedQFunctionSetContext(qf_rhsVol, ctxEuler); 1651 if (qf_applySur) CeedQFunctionSetContext(qf_applySur, ctxSurface); 1652 } 1653 1654 // Set up PETSc context 1655 // Set up units structure 1656 units->meter = meter; 1657 units->kilogram = kilogram; 1658 units->second = second; 1659 units->Kelvin = Kelvin; 1660 units->Pascal = Pascal; 1661 units->JperkgK = JperkgK; 1662 units->mpersquareds = mpersquareds; 1663 units->WpermK = WpermK; 1664 units->kgpercubicm = kgpercubicm; 1665 units->kgpersquaredms = kgpersquaredms; 1666 units->Joulepercubicm = Joulepercubicm; 1667 units->Joule = Joule; 1668 1669 // Set up user structure 1670 user->comm = comm; 1671 user->outputfreq = outputfreq; 1672 user->contsteps = contsteps; 1673 user->units = units; 1674 user->dm = dm; 1675 user->dmviz = dmviz; 1676 user->interpviz = interpviz; 1677 user->ceed = ceed; 1678 1679 // Calculate qdata and ICs 1680 // Set up state global and local vectors 1681 ierr = VecZeroEntries(Q); CHKERRQ(ierr); 1682 1683 ierr = VectorPlacePetscVec(q0ceed, Qloc); CHKERRQ(ierr); 1684 1685 // Apply Setup Ceed Operators 1686 ierr = VectorPlacePetscVec(xcorners, Xloc); CHKERRQ(ierr); 1687 CeedOperatorApply(op_setupVol, xcorners, qdata, CEED_REQUEST_IMMEDIATE); 1688 ierr = ComputeLumpedMassMatrix(ceed, dm, restrictq, basisq, restrictqdi, qdata, 1689 user->M); CHKERRQ(ierr); 1690 1691 ierr = ICs_FixMultiplicity(op_ics, xcorners, q0ceed, dm, Qloc, Q, restrictq, 1692 ctxSetup, 0.0); CHKERRQ(ierr); 1693 if (1) { // Record boundary values from initial condition and override DMPlexInsertBoundaryValues() 1694 // We use this for the main simulation DM because the reference DMPlexInsertBoundaryValues() is very slow. If we 1695 // disable this, we should still get the same results due to the problem->bc function, but with potentially much 1696 // slower execution. 1697 Vec Qbc; 1698 ierr = DMGetNamedLocalVector(dm, "Qbc", &Qbc); CHKERRQ(ierr); 1699 ierr = VecCopy(Qloc, Qbc); CHKERRQ(ierr); 1700 ierr = VecZeroEntries(Qloc); CHKERRQ(ierr); 1701 ierr = DMGlobalToLocal(dm, Q, INSERT_VALUES, Qloc); CHKERRQ(ierr); 1702 ierr = VecAXPY(Qbc, -1., Qloc); CHKERRQ(ierr); 1703 ierr = DMRestoreNamedLocalVector(dm, "Qbc", &Qbc); CHKERRQ(ierr); 1704 ierr = PetscObjectComposeFunction((PetscObject)dm, 1705 "DMPlexInsertBoundaryValues_C", DMPlexInsertBoundaryValues_NS); 1706 CHKERRQ(ierr); 1707 } 1708 1709 MPI_Comm_rank(comm, &rank); 1710 if (!rank) {ierr = PetscMkdir(user->outputdir); CHKERRQ(ierr);} 1711 // Gather initial Q values 1712 // In case of continuation of simulation, set up initial values from binary file 1713 if (contsteps) { // continue from existent solution 1714 PetscViewer viewer; 1715 char filepath[PETSC_MAX_PATH_LEN]; 1716 // Read input 1717 ierr = PetscSNPrintf(filepath, sizeof filepath, "%s/ns-solution.bin", 1718 user->outputdir); 1719 CHKERRQ(ierr); 1720 ierr = PetscViewerBinaryOpen(comm, filepath, FILE_MODE_READ, &viewer); 1721 CHKERRQ(ierr); 1722 ierr = VecLoad(Q, viewer); CHKERRQ(ierr); 1723 ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr); 1724 } 1725 ierr = DMRestoreLocalVector(dm, &Qloc); CHKERRQ(ierr); 1726 1727 // Create and setup TS 1728 ierr = TSCreate(comm, &ts); CHKERRQ(ierr); 1729 ierr = TSSetDM(ts, dm); CHKERRQ(ierr); 1730 if (implicit) { 1731 ierr = TSSetType(ts, TSBDF); CHKERRQ(ierr); 1732 if (user->op_ifunction) { 1733 ierr = TSSetIFunction(ts, NULL, IFunction_NS, &user); CHKERRQ(ierr); 1734 } else { // Implicit integrators can fall back to using an RHSFunction 1735 ierr = TSSetRHSFunction(ts, NULL, RHS_NS, &user); CHKERRQ(ierr); 1736 } 1737 } else { 1738 if (!user->op_rhs) SETERRQ(comm, PETSC_ERR_ARG_NULL, 1739 "Problem does not provide RHSFunction"); 1740 ierr = TSSetType(ts, TSRK); CHKERRQ(ierr); 1741 ierr = TSRKSetType(ts, TSRK5F); CHKERRQ(ierr); 1742 ierr = TSSetRHSFunction(ts, NULL, RHS_NS, &user); CHKERRQ(ierr); 1743 } 1744 ierr = TSSetMaxTime(ts, 500. * units->second); CHKERRQ(ierr); 1745 ierr = TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER); CHKERRQ(ierr); 1746 ierr = TSSetTimeStep(ts, 1.e-2 * units->second); CHKERRQ(ierr); 1747 if (test) {ierr = TSSetMaxSteps(ts, 10); CHKERRQ(ierr);} 1748 ierr = TSGetAdapt(ts, &adapt); CHKERRQ(ierr); 1749 ierr = TSAdaptSetStepLimits(adapt, 1750 1.e-12 * units->second, 1751 1.e2 * units->second); CHKERRQ(ierr); 1752 ierr = TSSetFromOptions(ts); CHKERRQ(ierr); 1753 if (!contsteps) { // print initial condition 1754 if (!test) { 1755 ierr = TSMonitor_NS(ts, 0, 0., Q, user); CHKERRQ(ierr); 1756 } 1757 } else { // continue from time of last output 1758 PetscReal time; 1759 PetscInt count; 1760 PetscViewer viewer; 1761 char filepath[PETSC_MAX_PATH_LEN]; 1762 ierr = PetscSNPrintf(filepath, sizeof filepath, "%s/ns-time.bin", 1763 user->outputdir); CHKERRQ(ierr); 1764 ierr = PetscViewerBinaryOpen(comm, filepath, FILE_MODE_READ, &viewer); 1765 CHKERRQ(ierr); 1766 ierr = PetscViewerBinaryRead(viewer, &time, 1, &count, PETSC_REAL); 1767 CHKERRQ(ierr); 1768 ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr); 1769 ierr = TSSetTime(ts, time * user->units->second); CHKERRQ(ierr); 1770 } 1771 if (!test) { 1772 ierr = TSMonitorSet(ts, TSMonitor_NS, user, NULL); CHKERRQ(ierr); 1773 } 1774 1775 // Solve 1776 start = MPI_Wtime(); 1777 ierr = PetscBarrier((PetscObject)ts); CHKERRQ(ierr); 1778 ierr = TSSolve(ts, Q); CHKERRQ(ierr); 1779 cpu_time_used = MPI_Wtime() - start; 1780 ierr = TSGetSolveTime(ts, &ftime); CHKERRQ(ierr); 1781 ierr = MPI_Allreduce(MPI_IN_PLACE, &cpu_time_used, 1, MPI_DOUBLE, MPI_MIN, 1782 comm); CHKERRQ(ierr); 1783 if (!test) { 1784 ierr = PetscPrintf(PETSC_COMM_WORLD, 1785 "Time taken for solution (sec): %g\n", 1786 (double)cpu_time_used); CHKERRQ(ierr); 1787 } 1788 1789 // Get error 1790 if (problem->non_zero_time && !test) { 1791 Vec Qexact, Qexactloc; 1792 PetscReal norm; 1793 ierr = DMCreateGlobalVector(dm, &Qexact); CHKERRQ(ierr); 1794 ierr = DMGetLocalVector(dm, &Qexactloc); CHKERRQ(ierr); 1795 ierr = VecGetSize(Qexactloc, &lnodes); CHKERRQ(ierr); 1796 1797 ierr = ICs_FixMultiplicity(op_ics, xcorners, q0ceed, dm, Qexactloc, Qexact, 1798 restrictq, ctxSetup, ftime); CHKERRQ(ierr); 1799 1800 ierr = VecAXPY(Q, -1.0, Qexact); CHKERRQ(ierr); 1801 ierr = VecNorm(Q, NORM_MAX, &norm); CHKERRQ(ierr); 1802 CeedVectorDestroy(&q0ceed); 1803 ierr = PetscPrintf(PETSC_COMM_WORLD, 1804 "Max Error: %g\n", 1805 (double)norm); CHKERRQ(ierr); 1806 // Clean up vectors 1807 ierr = DMRestoreLocalVector(dm, &Qexactloc); CHKERRQ(ierr); 1808 ierr = VecDestroy(&Qexact); CHKERRQ(ierr); 1809 } 1810 1811 // Output Statistics 1812 ierr = TSGetStepNumber(ts, &steps); CHKERRQ(ierr); 1813 if (!test) { 1814 ierr = PetscPrintf(PETSC_COMM_WORLD, 1815 "Time integrator took %D time steps to reach final time %g\n", 1816 steps, (double)ftime); CHKERRQ(ierr); 1817 } 1818 // Output numerical values from command line 1819 ierr = VecViewFromOptions(Q, NULL, "-vec_view"); CHKERRQ(ierr); 1820 1821 // Compare reference solution values with current test run for CI 1822 if (test) { 1823 PetscViewer viewer; 1824 // Read reference file 1825 Vec Qref; 1826 PetscReal error, Qrefnorm; 1827 ierr = VecDuplicate(Q, &Qref); CHKERRQ(ierr); 1828 ierr = PetscViewerBinaryOpen(comm, filepath, FILE_MODE_READ, &viewer); 1829 CHKERRQ(ierr); 1830 ierr = VecLoad(Qref, viewer); CHKERRQ(ierr); 1831 ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr); 1832 1833 // Compute error with respect to reference solution 1834 ierr = VecAXPY(Q, -1.0, Qref); CHKERRQ(ierr); 1835 ierr = VecNorm(Qref, NORM_MAX, &Qrefnorm); CHKERRQ(ierr); 1836 ierr = VecScale(Q, 1./Qrefnorm); CHKERRQ(ierr); 1837 ierr = VecNorm(Q, NORM_MAX, &error); CHKERRQ(ierr); 1838 ierr = VecDestroy(&Qref); CHKERRQ(ierr); 1839 // Check error 1840 if (error > testtol) { 1841 ierr = PetscPrintf(PETSC_COMM_WORLD, 1842 "Test failed with error norm %g\n", 1843 (double)error); CHKERRQ(ierr); 1844 } 1845 ierr = PetscViewerDestroy(&viewer); CHKERRQ(ierr); 1846 } 1847 1848 // Clean up libCEED 1849 CeedVectorDestroy(&qdata); 1850 CeedVectorDestroy(&user->qceed); 1851 CeedVectorDestroy(&user->qdotceed); 1852 CeedVectorDestroy(&user->gceed); 1853 CeedVectorDestroy(&xcorners); 1854 CeedBasisDestroy(&basisq); 1855 CeedBasisDestroy(&basisx); 1856 CeedBasisDestroy(&basisxc); 1857 CeedElemRestrictionDestroy(&restrictq); 1858 CeedElemRestrictionDestroy(&restrictx); 1859 CeedElemRestrictionDestroy(&restrictqdi); 1860 CeedQFunctionDestroy(&qf_setupVol); 1861 CeedQFunctionDestroy(&qf_ics); 1862 CeedQFunctionDestroy(&qf_rhsVol); 1863 CeedQFunctionDestroy(&qf_ifunctionVol); 1864 CeedQFunctionContextDestroy(&ctxSetup); 1865 CeedQFunctionContextDestroy(&ctxNS); 1866 CeedQFunctionContextDestroy(&ctxAdvection2d); 1867 CeedQFunctionContextDestroy(&ctxSurface); 1868 CeedQFunctionContextDestroy(&ctxEuler); 1869 CeedOperatorDestroy(&op_setupVol); 1870 CeedOperatorDestroy(&op_ics); 1871 CeedOperatorDestroy(&user->op_rhs_vol); 1872 CeedOperatorDestroy(&user->op_ifunction_vol); 1873 CeedDestroy(&ceed); 1874 CeedBasisDestroy(&basisqSur); 1875 CeedBasisDestroy(&basisxSur); 1876 CeedBasisDestroy(&basisxcSur); 1877 CeedQFunctionDestroy(&qf_setupSur); 1878 CeedQFunctionDestroy(&qf_applySur); 1879 CeedOperatorDestroy(&user->op_rhs); 1880 CeedOperatorDestroy(&user->op_ifunction); 1881 1882 // Clean up PETSc 1883 ierr = VecDestroy(&Q); CHKERRQ(ierr); 1884 ierr = VecDestroy(&user->M); CHKERRQ(ierr); 1885 ierr = MatDestroy(&interpviz); CHKERRQ(ierr); 1886 ierr = DMDestroy(&dmviz); CHKERRQ(ierr); 1887 ierr = TSDestroy(&ts); CHKERRQ(ierr); 1888 ierr = DMDestroy(&dm); CHKERRQ(ierr); 1889 ierr = PetscFree(units); CHKERRQ(ierr); 1890 ierr = PetscFree(user); CHKERRQ(ierr); 1891 ierr = PetscFree(ctxEulerData); CHKERRQ(ierr); 1892 return PetscFinalize(); 1893 } 1894