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