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