1 #define PETSCDM_DLL 2 #include <petsc/private/dmswarmimpl.h> /*I "petscdmswarm.h" I*/ 3 #include <petsc/private/hashsetij.h> 4 #include <petsc/private/petscfeimpl.h> 5 #include <petscviewer.h> 6 #include <petscdraw.h> 7 #include <petscdmplex.h> 8 #include <petscblaslapack.h> 9 #include "../src/dm/impls/swarm/data_bucket.h" 10 #include <petscdmlabel.h> 11 #include <petscsection.h> 12 13 PetscLogEvent DMSWARM_Migrate, DMSWARM_SetSizes, DMSWARM_AddPoints, DMSWARM_RemovePoints, DMSWARM_Sort; 14 PetscLogEvent DMSWARM_DataExchangerTopologySetup, DMSWARM_DataExchangerBegin, DMSWARM_DataExchangerEnd; 15 PetscLogEvent DMSWARM_DataExchangerSendCount, DMSWARM_DataExchangerPack; 16 17 const char *DMSwarmTypeNames[] = {"basic", "pic", NULL}; 18 const char *DMSwarmMigrateTypeNames[] = {"basic", "dmcellnscatter", "dmcellexact", "user", NULL}; 19 const char *DMSwarmCollectTypeNames[] = {"basic", "boundingbox", "general", "user", NULL}; 20 const char *DMSwarmPICLayoutTypeNames[] = {"regular", "gauss", "subdivision", NULL}; 21 22 const char DMSwarmField_pid[] = "DMSwarm_pid"; 23 const char DMSwarmField_rank[] = "DMSwarm_rank"; 24 const char DMSwarmPICField_coor[] = "DMSwarmPIC_coor"; 25 const char DMSwarmPICField_cellid[] = "DMSwarm_cellid"; 26 27 PetscInt SwarmDataFieldId = -1; 28 29 #if defined(PETSC_HAVE_HDF5) 30 #include <petscviewerhdf5.h> 31 32 static PetscErrorCode VecView_Swarm_HDF5_Internal(Vec v, PetscViewer viewer) 33 { 34 DM dm; 35 PetscReal seqval; 36 PetscInt seqnum, bs; 37 PetscBool isseq; 38 39 PetscFunctionBegin; 40 PetscCall(VecGetDM(v, &dm)); 41 PetscCall(VecGetBlockSize(v, &bs)); 42 PetscCall(PetscViewerHDF5PushGroup(viewer, "/particle_fields")); 43 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 44 PetscCall(DMGetOutputSequenceNumber(dm, &seqnum, &seqval)); 45 PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum)); 46 /* PetscCall(DMSequenceView_HDF5(dm, "time", seqnum, (PetscScalar) seqval, viewer)); */ 47 PetscCall(VecViewNative(v, viewer)); 48 PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)v, "Nc", PETSC_INT, (void *)&bs)); 49 PetscCall(PetscViewerHDF5PopGroup(viewer)); 50 PetscFunctionReturn(PETSC_SUCCESS); 51 } 52 53 static PetscErrorCode DMSwarmView_HDF5(DM dm, PetscViewer viewer) 54 { 55 Vec coordinates; 56 PetscInt Np; 57 PetscBool isseq; 58 59 PetscFunctionBegin; 60 PetscCall(DMSwarmGetSize(dm, &Np)); 61 PetscCall(DMSwarmCreateGlobalVectorFromField(dm, DMSwarmPICField_coor, &coordinates)); 62 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 63 PetscCall(PetscViewerHDF5PushGroup(viewer, "/particles")); 64 PetscCall(PetscObjectTypeCompare((PetscObject)coordinates, VECSEQ, &isseq)); 65 PetscCall(VecViewNative(coordinates, viewer)); 66 PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)coordinates, "Np", PETSC_INT, (void *)&Np)); 67 PetscCall(PetscViewerHDF5PopGroup(viewer)); 68 PetscCall(DMSwarmDestroyGlobalVectorFromField(dm, DMSwarmPICField_coor, &coordinates)); 69 PetscFunctionReturn(PETSC_SUCCESS); 70 } 71 #endif 72 73 static PetscErrorCode VecView_Swarm(Vec v, PetscViewer viewer) 74 { 75 DM dm; 76 #if defined(PETSC_HAVE_HDF5) 77 PetscBool ishdf5; 78 #endif 79 80 PetscFunctionBegin; 81 PetscCall(VecGetDM(v, &dm)); 82 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 83 #if defined(PETSC_HAVE_HDF5) 84 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 85 if (ishdf5) { 86 PetscCall(VecView_Swarm_HDF5_Internal(v, viewer)); 87 PetscFunctionReturn(PETSC_SUCCESS); 88 } 89 #endif 90 PetscCall(VecViewNative(v, viewer)); 91 PetscFunctionReturn(PETSC_SUCCESS); 92 } 93 94 /*@C 95 DMSwarmVectorGetField - Gets the field from which to define a `Vec` object 96 when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called 97 98 Not collective 99 100 Input Parameter: 101 . dm - a `DMSWARM` 102 103 Output Parameter: 104 . fieldname - the textual name given to a registered field, or the empty string if it has not been set 105 106 Level: beginner 107 108 .seealso: `DM`, `DMSWARM`, `DMSwarmVectorDefineField()` `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()` 109 @*/ 110 PetscErrorCode DMSwarmVectorGetField(DM dm, const char *fieldname[]) 111 { 112 PetscFunctionBegin; 113 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 114 PetscAssertPointer(fieldname, 2); 115 *fieldname = ((DM_Swarm *)dm->data)->vec_field_name; 116 PetscFunctionReturn(PETSC_SUCCESS); 117 } 118 119 /*@C 120 DMSwarmVectorDefineField - Sets the field from which to define a `Vec` object 121 when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called 122 123 Collective 124 125 Input Parameters: 126 + dm - a `DMSWARM` 127 - fieldname - the textual name given to a registered field 128 129 Level: beginner 130 131 Notes: 132 The field with name `fieldname` must be defined as having a data type of `PetscScalar`. 133 134 This function must be called prior to calling `DMCreateLocalVector()`, `DMCreateGlobalVector()`. 135 Multiple calls to `DMSwarmVectorDefineField()` are permitted. 136 137 .seealso: `DM`, `DMSWARM`, `DMSwarmVectorGetField()`, `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()` 138 @*/ 139 PetscErrorCode DMSwarmVectorDefineField(DM dm, const char fieldname[]) 140 { 141 DM_Swarm *swarm = (DM_Swarm *)dm->data; 142 PetscInt bs, n; 143 PetscScalar *array; 144 PetscDataType type; 145 146 PetscFunctionBegin; 147 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 148 if (fieldname) PetscAssertPointer(fieldname, 2); 149 if (!swarm->issetup) PetscCall(DMSetUp(dm)); 150 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL)); 151 PetscCall(DMSwarmGetField(dm, fieldname, &bs, &type, (void **)&array)); 152 153 /* Check all fields are of type PETSC_REAL or PETSC_SCALAR */ 154 PetscCheck(type == PETSC_REAL, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid for PETSC_REAL"); 155 PetscCall(PetscSNPrintf(swarm->vec_field_name, PETSC_MAX_PATH_LEN - 1, "%s", fieldname)); 156 swarm->vec_field_set = PETSC_TRUE; 157 swarm->vec_field_bs = bs; 158 swarm->vec_field_nlocal = n; 159 PetscCall(DMSwarmRestoreField(dm, fieldname, &bs, &type, (void **)&array)); 160 PetscFunctionReturn(PETSC_SUCCESS); 161 } 162 163 /* requires DMSwarmDefineFieldVector has been called */ 164 static PetscErrorCode DMCreateGlobalVector_Swarm(DM dm, Vec *vec) 165 { 166 DM_Swarm *swarm = (DM_Swarm *)dm->data; 167 Vec x; 168 char name[PETSC_MAX_PATH_LEN]; 169 170 PetscFunctionBegin; 171 if (!swarm->issetup) PetscCall(DMSetUp(dm)); 172 PetscCheck(swarm->vec_field_set, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmVectorDefineField first"); 173 PetscCheck(swarm->vec_field_nlocal == swarm->db->L, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSwarm sizes have changed since last call to VectorDefineField first"); /* Stale data */ 174 175 PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "DMSwarmField_%s", swarm->vec_field_name)); 176 PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &x)); 177 PetscCall(PetscObjectSetName((PetscObject)x, name)); 178 PetscCall(VecSetSizes(x, swarm->db->L * swarm->vec_field_bs, PETSC_DETERMINE)); 179 PetscCall(VecSetBlockSize(x, swarm->vec_field_bs)); 180 PetscCall(VecSetDM(x, dm)); 181 PetscCall(VecSetFromOptions(x)); 182 PetscCall(VecSetDM(x, dm)); 183 PetscCall(VecSetOperation(x, VECOP_VIEW, (void (*)(void))VecView_Swarm)); 184 *vec = x; 185 PetscFunctionReturn(PETSC_SUCCESS); 186 } 187 188 /* requires DMSwarmDefineFieldVector has been called */ 189 static PetscErrorCode DMCreateLocalVector_Swarm(DM dm, Vec *vec) 190 { 191 DM_Swarm *swarm = (DM_Swarm *)dm->data; 192 Vec x; 193 char name[PETSC_MAX_PATH_LEN]; 194 195 PetscFunctionBegin; 196 if (!swarm->issetup) PetscCall(DMSetUp(dm)); 197 PetscCheck(swarm->vec_field_set, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmVectorDefineField first"); 198 PetscCheck(swarm->vec_field_nlocal == swarm->db->L, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSwarm sizes have changed since last call to VectorDefineField first"); 199 200 PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "DMSwarmField_%s", swarm->vec_field_name)); 201 PetscCall(VecCreate(PETSC_COMM_SELF, &x)); 202 PetscCall(PetscObjectSetName((PetscObject)x, name)); 203 PetscCall(VecSetSizes(x, swarm->db->L * swarm->vec_field_bs, PETSC_DETERMINE)); 204 PetscCall(VecSetBlockSize(x, swarm->vec_field_bs)); 205 PetscCall(VecSetDM(x, dm)); 206 PetscCall(VecSetFromOptions(x)); 207 *vec = x; 208 PetscFunctionReturn(PETSC_SUCCESS); 209 } 210 211 static PetscErrorCode DMSwarmDestroyVectorFromField_Private(DM dm, const char fieldname[], Vec *vec) 212 { 213 DM_Swarm *swarm = (DM_Swarm *)dm->data; 214 DMSwarmDataField gfield; 215 PetscInt bs, nlocal, fid = -1, cfid = -2; 216 PetscBool flg; 217 218 PetscFunctionBegin; 219 /* check vector is an inplace array */ 220 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldname, &fid)); 221 PetscCall(PetscObjectComposedDataGetInt((PetscObject)*vec, SwarmDataFieldId, cfid, flg)); 222 PetscCheck(cfid == fid, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Vector being destroyed was not created from DMSwarm field(%s)! %" PetscInt_FMT " != %" PetscInt_FMT "", fieldname, cfid, fid); 223 PetscCall(VecGetLocalSize(*vec, &nlocal)); 224 PetscCall(VecGetBlockSize(*vec, &bs)); 225 PetscCheck(nlocal / bs == swarm->db->L, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSwarm sizes have changed since vector was created - cannot ensure pointers are valid"); 226 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield)); 227 PetscCall(DMSwarmDataFieldRestoreAccess(gfield)); 228 PetscCall(VecResetArray(*vec)); 229 PetscCall(VecDestroy(vec)); 230 PetscFunctionReturn(PETSC_SUCCESS); 231 } 232 233 static PetscErrorCode DMSwarmCreateVectorFromField_Private(DM dm, const char fieldname[], MPI_Comm comm, Vec *vec) 234 { 235 DM_Swarm *swarm = (DM_Swarm *)dm->data; 236 PetscDataType type; 237 PetscScalar *array; 238 PetscInt bs, n, fid; 239 char name[PETSC_MAX_PATH_LEN]; 240 PetscMPIInt size; 241 PetscBool iscuda, iskokkos; 242 243 PetscFunctionBegin; 244 if (!swarm->issetup) PetscCall(DMSetUp(dm)); 245 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL)); 246 PetscCall(DMSwarmGetField(dm, fieldname, &bs, &type, (void **)&array)); 247 PetscCheck(type == PETSC_REAL, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid for PETSC_REAL"); 248 249 PetscCallMPI(MPI_Comm_size(comm, &size)); 250 PetscCall(PetscStrcmp(dm->vectype, VECKOKKOS, &iskokkos)); 251 PetscCall(PetscStrcmp(dm->vectype, VECCUDA, &iscuda)); 252 PetscCall(VecCreate(comm, vec)); 253 PetscCall(VecSetSizes(*vec, n * bs, PETSC_DETERMINE)); 254 PetscCall(VecSetBlockSize(*vec, bs)); 255 if (iskokkos) PetscCall(VecSetType(*vec, VECKOKKOS)); 256 else if (iscuda) PetscCall(VecSetType(*vec, VECCUDA)); 257 else PetscCall(VecSetType(*vec, VECSTANDARD)); 258 PetscCall(VecPlaceArray(*vec, array)); 259 260 PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "DMSwarmSharedField_%s", fieldname)); 261 PetscCall(PetscObjectSetName((PetscObject)*vec, name)); 262 263 /* Set guard */ 264 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldname, &fid)); 265 PetscCall(PetscObjectComposedDataSetInt((PetscObject)*vec, SwarmDataFieldId, fid)); 266 267 PetscCall(VecSetDM(*vec, dm)); 268 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Swarm)); 269 PetscFunctionReturn(PETSC_SUCCESS); 270 } 271 272 /* This creates a "mass matrix" between a finite element and particle space. If a finite element interpolant is given by 273 274 \hat f = \sum_i f_i \phi_i 275 276 and a particle function is given by 277 278 f = \sum_i w_i \delta(x - x_i) 279 280 then we want to require that 281 282 M \hat f = M_p f 283 284 where the particle mass matrix is given by 285 286 (M_p)_{ij} = \int \phi_i \delta(x - x_j) 287 288 The way Dave May does particles, they amount to quadratue weights rather than delta functions, so he has |J| is in 289 his integral. We allow this with the boolean flag. 290 */ 291 static PetscErrorCode DMSwarmComputeMassMatrix_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx) 292 { 293 const char *name = "Mass Matrix"; 294 MPI_Comm comm; 295 PetscDS prob; 296 PetscSection fsection, globalFSection; 297 PetscHSetIJ ht; 298 PetscLayout rLayout, colLayout; 299 PetscInt *dnz, *onz; 300 PetscInt locRows, locCols, rStart, colStart, colEnd, *rowIDXs; 301 PetscReal *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0}; 302 PetscScalar *elemMat; 303 PetscInt dim, Nf, field, cStart, cEnd, cell, totDim, maxC = 0, totNc = 0; 304 305 PetscFunctionBegin; 306 PetscCall(PetscObjectGetComm((PetscObject)mass, &comm)); 307 PetscCall(DMGetCoordinateDim(dmf, &dim)); 308 PetscCall(DMGetDS(dmf, &prob)); 309 PetscCall(PetscDSGetNumFields(prob, &Nf)); 310 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 311 PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 312 PetscCall(DMGetLocalSection(dmf, &fsection)); 313 PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 314 PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd)); 315 PetscCall(MatGetLocalSize(mass, &locRows, &locCols)); 316 317 PetscCall(PetscLayoutCreate(comm, &colLayout)); 318 PetscCall(PetscLayoutSetLocalSize(colLayout, locCols)); 319 PetscCall(PetscLayoutSetBlockSize(colLayout, 1)); 320 PetscCall(PetscLayoutSetUp(colLayout)); 321 PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd)); 322 PetscCall(PetscLayoutDestroy(&colLayout)); 323 324 PetscCall(PetscLayoutCreate(comm, &rLayout)); 325 PetscCall(PetscLayoutSetLocalSize(rLayout, locRows)); 326 PetscCall(PetscLayoutSetBlockSize(rLayout, 1)); 327 PetscCall(PetscLayoutSetUp(rLayout)); 328 PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL)); 329 PetscCall(PetscLayoutDestroy(&rLayout)); 330 331 PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz)); 332 PetscCall(PetscHSetIJCreate(&ht)); 333 334 PetscCall(PetscSynchronizedFlush(comm, NULL)); 335 for (field = 0; field < Nf; ++field) { 336 PetscObject obj; 337 PetscClassId id; 338 PetscInt Nc; 339 340 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 341 PetscCall(PetscObjectGetClassId(obj, &id)); 342 if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 343 else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 344 totNc += Nc; 345 } 346 /* count non-zeros */ 347 PetscCall(DMSwarmSortGetAccess(dmc)); 348 for (field = 0; field < Nf; ++field) { 349 PetscObject obj; 350 PetscClassId id; 351 PetscInt Nc; 352 353 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 354 PetscCall(PetscObjectGetClassId(obj, &id)); 355 if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 356 else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 357 358 for (cell = cStart; cell < cEnd; ++cell) { 359 PetscInt *findices, *cindices; /* fine is vertices, coarse is particles */ 360 PetscInt numFIndices, numCIndices; 361 362 PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 363 PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices)); 364 maxC = PetscMax(maxC, numCIndices); 365 { 366 PetscHashIJKey key; 367 PetscBool missing; 368 for (PetscInt i = 0; i < numFIndices; ++i) { 369 key.j = findices[i]; /* global column (from Plex) */ 370 if (key.j >= 0) { 371 /* Get indices for coarse elements */ 372 for (PetscInt j = 0; j < numCIndices; ++j) { 373 for (PetscInt c = 0; c < Nc; ++c) { 374 // TODO Need field offset on particle here 375 key.i = cindices[j] * totNc + c + rStart; /* global cols (from Swarm) */ 376 if (key.i < 0) continue; 377 PetscCall(PetscHSetIJQueryAdd(ht, key, &missing)); 378 if (missing) { 379 if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart]; 380 else ++onz[key.i - rStart]; 381 } else SETERRQ(PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Set new value at %" PetscInt_FMT ",%" PetscInt_FMT, key.i, key.j); 382 } 383 } 384 } 385 } 386 PetscCall(PetscFree(cindices)); 387 } 388 PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 389 } 390 } 391 PetscCall(PetscHSetIJDestroy(&ht)); 392 PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL)); 393 PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 394 PetscCall(PetscFree2(dnz, onz)); 395 PetscCall(PetscMalloc3(maxC * totNc * totDim, &elemMat, maxC * totNc, &rowIDXs, maxC * dim, &xi)); 396 for (field = 0; field < Nf; ++field) { 397 PetscTabulation Tcoarse; 398 PetscObject obj; 399 PetscClassId id; 400 PetscReal *fieldVals; 401 PetscInt Nc; 402 403 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 404 PetscCall(PetscObjectGetClassId(obj, &id)); 405 if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 406 else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 407 408 PetscCall(DMSwarmGetField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&fieldVals)); 409 for (cell = cStart; cell < cEnd; ++cell) { 410 PetscInt *findices, *cindices; 411 PetscInt numFIndices, numCIndices; 412 413 /* TODO: Use DMField instead of assuming affine */ 414 PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 415 PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 416 PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices)); 417 for (PetscInt j = 0; j < numCIndices; ++j) CoordinatesRealToRef(dim, dim, v0ref, v0, invJ, &fieldVals[cindices[j] * dim], &xi[j * dim]); 418 if (id == PETSCFE_CLASSID) PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse)); 419 else PetscCall(PetscFVCreateTabulation((PetscFV)obj, 1, numCIndices, xi, 0, &Tcoarse)); 420 /* Get elemMat entries by multiplying by weight */ 421 PetscCall(PetscArrayzero(elemMat, numCIndices * Nc * totDim)); 422 for (PetscInt i = 0; i < numFIndices / Nc; ++i) { 423 for (PetscInt j = 0; j < numCIndices; ++j) { 424 for (PetscInt c = 0; c < Nc; ++c) { 425 // TODO Need field offset on particle and field here 426 /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */ 427 elemMat[(j * totNc + c) * numFIndices + i * Nc + c] += Tcoarse->T[0][(j * numFIndices + i * Nc + c) * Nc + c] * (useDeltaFunction ? 1.0 : detJ); 428 } 429 } 430 } 431 for (PetscInt j = 0; j < numCIndices; ++j) 432 // TODO Need field offset on particle here 433 for (PetscInt c = 0; c < Nc; ++c) rowIDXs[j * Nc + c] = cindices[j] * totNc + c + rStart; 434 if (0) PetscCall(DMPrintCellMatrix(cell, name, numCIndices * Nc, numFIndices, elemMat)); 435 PetscCall(MatSetValues(mass, numCIndices * Nc, rowIDXs, numFIndices, findices, elemMat, ADD_VALUES)); 436 PetscCall(PetscFree(cindices)); 437 PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 438 PetscCall(PetscTabulationDestroy(&Tcoarse)); 439 } 440 PetscCall(DMSwarmRestoreField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&fieldVals)); 441 } 442 PetscCall(PetscFree3(elemMat, rowIDXs, xi)); 443 PetscCall(DMSwarmSortRestoreAccess(dmc)); 444 PetscCall(PetscFree3(v0, J, invJ)); 445 PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY)); 446 PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY)); 447 PetscFunctionReturn(PETSC_SUCCESS); 448 } 449 450 /* Returns empty matrix for use with SNES FD */ 451 static PetscErrorCode DMCreateMatrix_Swarm(DM sw, Mat *m) 452 { 453 Vec field; 454 PetscInt size; 455 456 PetscFunctionBegin; 457 PetscCall(DMGetGlobalVector(sw, &field)); 458 PetscCall(VecGetLocalSize(field, &size)); 459 PetscCall(DMRestoreGlobalVector(sw, &field)); 460 PetscCall(MatCreate(PETSC_COMM_WORLD, m)); 461 PetscCall(MatSetFromOptions(*m)); 462 PetscCall(MatSetSizes(*m, PETSC_DECIDE, PETSC_DECIDE, size, size)); 463 PetscCall(MatSeqAIJSetPreallocation(*m, 1, NULL)); 464 PetscCall(MatZeroEntries(*m)); 465 PetscCall(MatAssemblyBegin(*m, MAT_FINAL_ASSEMBLY)); 466 PetscCall(MatAssemblyEnd(*m, MAT_FINAL_ASSEMBLY)); 467 PetscCall(MatShift(*m, 1.0)); 468 PetscCall(MatSetDM(*m, sw)); 469 PetscFunctionReturn(PETSC_SUCCESS); 470 } 471 472 /* FEM cols, Particle rows */ 473 static PetscErrorCode DMCreateMassMatrix_Swarm(DM dmCoarse, DM dmFine, Mat *mass) 474 { 475 PetscSection gsf; 476 PetscInt m, n, Np, bs = 1; 477 void *ctx; 478 PetscBool set = ((DM_Swarm *)dmCoarse->data)->vec_field_set; 479 char *name = ((DM_Swarm *)dmCoarse->data)->vec_field_name; 480 481 PetscFunctionBegin; 482 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 483 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 484 PetscCall(DMSwarmGetLocalSize(dmCoarse, &Np)); 485 // TODO Include all fields 486 if (set) PetscCall(DMSwarmGetFieldInfo(dmCoarse, name, &bs, NULL)); 487 n = Np * bs; 488 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 489 PetscCall(MatSetSizes(*mass, n, m, PETSC_DETERMINE, PETSC_DETERMINE)); 490 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 491 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 492 493 PetscCall(DMSwarmComputeMassMatrix_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx)); 494 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 495 PetscFunctionReturn(PETSC_SUCCESS); 496 } 497 498 static PetscErrorCode DMSwarmComputeMassMatrixSquare_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx) 499 { 500 const char *name = "Mass Matrix Square"; 501 MPI_Comm comm; 502 PetscDS prob; 503 PetscSection fsection, globalFSection; 504 PetscHSetIJ ht; 505 PetscLayout rLayout, colLayout; 506 PetscInt *dnz, *onz, *adj, depth, maxConeSize, maxSupportSize, maxAdjSize; 507 PetscInt locRows, locCols, rStart, colStart, colEnd, *rowIDXs; 508 PetscReal *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0}; 509 PetscScalar *elemMat, *elemMatSq; 510 PetscInt cdim, Nf, field, cStart, cEnd, cell, totDim, maxC = 0; 511 512 PetscFunctionBegin; 513 PetscCall(PetscObjectGetComm((PetscObject)mass, &comm)); 514 PetscCall(DMGetCoordinateDim(dmf, &cdim)); 515 PetscCall(DMGetDS(dmf, &prob)); 516 PetscCall(PetscDSGetNumFields(prob, &Nf)); 517 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 518 PetscCall(PetscMalloc3(cdim, &v0, cdim * cdim, &J, cdim * cdim, &invJ)); 519 PetscCall(DMGetLocalSection(dmf, &fsection)); 520 PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 521 PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd)); 522 PetscCall(MatGetLocalSize(mass, &locRows, &locCols)); 523 524 PetscCall(PetscLayoutCreate(comm, &colLayout)); 525 PetscCall(PetscLayoutSetLocalSize(colLayout, locCols)); 526 PetscCall(PetscLayoutSetBlockSize(colLayout, 1)); 527 PetscCall(PetscLayoutSetUp(colLayout)); 528 PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd)); 529 PetscCall(PetscLayoutDestroy(&colLayout)); 530 531 PetscCall(PetscLayoutCreate(comm, &rLayout)); 532 PetscCall(PetscLayoutSetLocalSize(rLayout, locRows)); 533 PetscCall(PetscLayoutSetBlockSize(rLayout, 1)); 534 PetscCall(PetscLayoutSetUp(rLayout)); 535 PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL)); 536 PetscCall(PetscLayoutDestroy(&rLayout)); 537 538 PetscCall(DMPlexGetDepth(dmf, &depth)); 539 PetscCall(DMPlexGetMaxSizes(dmf, &maxConeSize, &maxSupportSize)); 540 maxAdjSize = PetscPowInt(maxConeSize * maxSupportSize, depth); 541 PetscCall(PetscMalloc1(maxAdjSize, &adj)); 542 543 PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz)); 544 PetscCall(PetscHSetIJCreate(&ht)); 545 /* Count nonzeros 546 This is just FVM++, but we cannot use the Plex P0 allocation since unknowns in a cell will not be contiguous 547 */ 548 PetscCall(DMSwarmSortGetAccess(dmc)); 549 for (cell = cStart; cell < cEnd; ++cell) { 550 PetscInt i; 551 PetscInt *cindices; 552 PetscInt numCIndices; 553 #if 0 554 PetscInt adjSize = maxAdjSize, a, j; 555 #endif 556 557 PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices)); 558 maxC = PetscMax(maxC, numCIndices); 559 /* Diagonal block */ 560 for (i = 0; i < numCIndices; ++i) dnz[cindices[i]] += numCIndices; 561 #if 0 562 /* Off-diagonal blocks */ 563 PetscCall(DMPlexGetAdjacency(dmf, cell, &adjSize, &adj)); 564 for (a = 0; a < adjSize; ++a) { 565 if (adj[a] >= cStart && adj[a] < cEnd && adj[a] != cell) { 566 const PetscInt ncell = adj[a]; 567 PetscInt *ncindices; 568 PetscInt numNCIndices; 569 570 PetscCall(DMSwarmSortGetPointsPerCell(dmc, ncell, &numNCIndices, &ncindices)); 571 { 572 PetscHashIJKey key; 573 PetscBool missing; 574 575 for (i = 0; i < numCIndices; ++i) { 576 key.i = cindices[i] + rStart; /* global rows (from Swarm) */ 577 if (key.i < 0) continue; 578 for (j = 0; j < numNCIndices; ++j) { 579 key.j = ncindices[j] + rStart; /* global column (from Swarm) */ 580 if (key.j < 0) continue; 581 PetscCall(PetscHSetIJQueryAdd(ht, key, &missing)); 582 if (missing) { 583 if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart]; 584 else ++onz[key.i - rStart]; 585 } 586 } 587 } 588 } 589 PetscCall(PetscFree(ncindices)); 590 } 591 } 592 #endif 593 PetscCall(PetscFree(cindices)); 594 } 595 PetscCall(PetscHSetIJDestroy(&ht)); 596 PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL)); 597 PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 598 PetscCall(PetscFree2(dnz, onz)); 599 PetscCall(PetscMalloc4(maxC * totDim, &elemMat, maxC * maxC, &elemMatSq, maxC, &rowIDXs, maxC * cdim, &xi)); 600 /* Fill in values 601 Each entry is a sum of terms \phi_i(x_p) \phi_i(x_q) 602 Start just by producing block diagonal 603 Could loop over adjacent cells 604 Produce neighboring element matrix 605 TODO Determine which columns and rows correspond to shared dual vector 606 Do MatMatMult with rectangular matrices 607 Insert block 608 */ 609 for (field = 0; field < Nf; ++field) { 610 PetscTabulation Tcoarse; 611 PetscObject obj; 612 PetscReal *coords; 613 PetscInt Nc, i; 614 615 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 616 PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 617 PetscCheck(Nc == 1, PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Can only interpolate a scalar field from particles, Nc = %" PetscInt_FMT, Nc); 618 PetscCall(DMSwarmGetField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 619 for (cell = cStart; cell < cEnd; ++cell) { 620 PetscInt *findices, *cindices; 621 PetscInt numFIndices, numCIndices; 622 PetscInt p, c; 623 624 /* TODO: Use DMField instead of assuming affine */ 625 PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 626 PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 627 PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices)); 628 for (p = 0; p < numCIndices; ++p) CoordinatesRealToRef(cdim, cdim, v0ref, v0, invJ, &coords[cindices[p] * cdim], &xi[p * cdim]); 629 PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse)); 630 /* Get elemMat entries by multiplying by weight */ 631 PetscCall(PetscArrayzero(elemMat, numCIndices * totDim)); 632 for (i = 0; i < numFIndices; ++i) { 633 for (p = 0; p < numCIndices; ++p) { 634 for (c = 0; c < Nc; ++c) { 635 /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */ 636 elemMat[p * numFIndices + i] += Tcoarse->T[0][(p * numFIndices + i) * Nc + c] * (useDeltaFunction ? 1.0 : detJ); 637 } 638 } 639 } 640 PetscCall(PetscTabulationDestroy(&Tcoarse)); 641 for (p = 0; p < numCIndices; ++p) rowIDXs[p] = cindices[p] + rStart; 642 if (0) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 643 /* Block diagonal */ 644 if (numCIndices) { 645 PetscBLASInt blasn, blask; 646 PetscScalar one = 1.0, zero = 0.0; 647 648 PetscCall(PetscBLASIntCast(numCIndices, &blasn)); 649 PetscCall(PetscBLASIntCast(numFIndices, &blask)); 650 PetscCallBLAS("BLASgemm", BLASgemm_("T", "N", &blasn, &blasn, &blask, &one, elemMat, &blask, elemMat, &blask, &zero, elemMatSq, &blasn)); 651 } 652 PetscCall(MatSetValues(mass, numCIndices, rowIDXs, numCIndices, rowIDXs, elemMatSq, ADD_VALUES)); 653 /* TODO off-diagonal */ 654 PetscCall(PetscFree(cindices)); 655 PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 656 } 657 PetscCall(DMSwarmRestoreField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 658 } 659 PetscCall(PetscFree4(elemMat, elemMatSq, rowIDXs, xi)); 660 PetscCall(PetscFree(adj)); 661 PetscCall(DMSwarmSortRestoreAccess(dmc)); 662 PetscCall(PetscFree3(v0, J, invJ)); 663 PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY)); 664 PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY)); 665 PetscFunctionReturn(PETSC_SUCCESS); 666 } 667 668 /*@C 669 DMSwarmCreateMassMatrixSquare - Creates the block-diagonal of the square, M^T_p M_p, of the particle mass matrix M_p 670 671 Collective 672 673 Input Parameters: 674 + dmCoarse - a `DMSWARM` 675 - dmFine - a `DMPLEX` 676 677 Output Parameter: 678 . mass - the square of the particle mass matrix 679 680 Level: advanced 681 682 Note: 683 We only compute the block diagonal since this provides a good preconditioner and is completely local. It would be possible in the 684 future to compute the full normal equations. 685 686 .seealso: `DM`, `DMSWARM`, `DMCreateMassMatrix()` 687 @*/ 688 PetscErrorCode DMSwarmCreateMassMatrixSquare(DM dmCoarse, DM dmFine, Mat *mass) 689 { 690 PetscInt n; 691 void *ctx; 692 693 PetscFunctionBegin; 694 PetscCall(DMSwarmGetLocalSize(dmCoarse, &n)); 695 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 696 PetscCall(MatSetSizes(*mass, n, n, PETSC_DETERMINE, PETSC_DETERMINE)); 697 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 698 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 699 700 PetscCall(DMSwarmComputeMassMatrixSquare_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx)); 701 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_sq_mat_view")); 702 PetscFunctionReturn(PETSC_SUCCESS); 703 } 704 705 /*@C 706 DMSwarmCreateGlobalVectorFromField - Creates a `Vec` object sharing the array associated with a given field 707 708 Collective 709 710 Input Parameters: 711 + dm - a `DMSWARM` 712 - fieldname - the textual name given to a registered field 713 714 Output Parameter: 715 . vec - the vector 716 717 Level: beginner 718 719 Notes: 720 The vector must be returned using a matching call to `DMSwarmDestroyGlobalVectorFromField()`. 721 722 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyGlobalVectorFromField()` 723 @*/ 724 PetscErrorCode DMSwarmCreateGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec) 725 { 726 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 727 728 PetscFunctionBegin; 729 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 730 PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec)); 731 PetscFunctionReturn(PETSC_SUCCESS); 732 } 733 734 /*@C 735 DMSwarmDestroyGlobalVectorFromField - Destroys the `Vec` object which share the array associated with a given field 736 737 Collective 738 739 Input Parameters: 740 + dm - a `DMSWARM` 741 - fieldname - the textual name given to a registered field 742 743 Output Parameter: 744 . vec - the vector 745 746 Level: beginner 747 748 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateGlobalVectorFromField()` 749 @*/ 750 PetscErrorCode DMSwarmDestroyGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec) 751 { 752 PetscFunctionBegin; 753 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 754 PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec)); 755 PetscFunctionReturn(PETSC_SUCCESS); 756 } 757 758 /*@C 759 DMSwarmCreateLocalVectorFromField - Creates a `Vec` object sharing the array associated with a given field 760 761 Collective 762 763 Input Parameters: 764 + dm - a `DMSWARM` 765 - fieldname - the textual name given to a registered field 766 767 Output Parameter: 768 . vec - the vector 769 770 Level: beginner 771 772 Note: 773 The vector must be returned using a matching call to DMSwarmDestroyLocalVectorFromField(). 774 775 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyLocalVectorFromField()` 776 @*/ 777 PetscErrorCode DMSwarmCreateLocalVectorFromField(DM dm, const char fieldname[], Vec *vec) 778 { 779 MPI_Comm comm = PETSC_COMM_SELF; 780 781 PetscFunctionBegin; 782 PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec)); 783 PetscFunctionReturn(PETSC_SUCCESS); 784 } 785 786 /*@C 787 DMSwarmDestroyLocalVectorFromField - Destroys the `Vec` object which share the array associated with a given field 788 789 Collective 790 791 Input Parameters: 792 + dm - a `DMSWARM` 793 - fieldname - the textual name given to a registered field 794 795 Output Parameter: 796 . vec - the vector 797 798 Level: beginner 799 800 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateLocalVectorFromField()` 801 @*/ 802 PetscErrorCode DMSwarmDestroyLocalVectorFromField(DM dm, const char fieldname[], Vec *vec) 803 { 804 PetscFunctionBegin; 805 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 806 PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec)); 807 PetscFunctionReturn(PETSC_SUCCESS); 808 } 809 810 /*@C 811 DMSwarmInitializeFieldRegister - Initiates the registration of fields to a `DMSWARM` 812 813 Collective 814 815 Input Parameter: 816 . dm - a `DMSWARM` 817 818 Level: beginner 819 820 Note: 821 After all fields have been registered, you must call `DMSwarmFinalizeFieldRegister()`. 822 823 .seealso: `DM`, `DMSWARM`, `DMSwarmFinalizeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`, 824 `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()` 825 @*/ 826 PetscErrorCode DMSwarmInitializeFieldRegister(DM dm) 827 { 828 DM_Swarm *swarm = (DM_Swarm *)dm->data; 829 830 PetscFunctionBegin; 831 if (!swarm->field_registration_initialized) { 832 swarm->field_registration_initialized = PETSC_TRUE; 833 PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_pid, 1, PETSC_INT64)); /* unique identifier */ 834 PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_rank, 1, PETSC_INT)); /* used for communication */ 835 } 836 PetscFunctionReturn(PETSC_SUCCESS); 837 } 838 839 /*@ 840 DMSwarmFinalizeFieldRegister - Finalizes the registration of fields to a `DMSWARM` 841 842 Collective 843 844 Input Parameter: 845 . dm - a `DMSWARM` 846 847 Level: beginner 848 849 Note: 850 After `DMSwarmFinalizeFieldRegister()` has been called, no new fields can be defined on the `DMSWARM`. 851 852 .seealso: `DM`, `DMSWARM`, `DMSwarmInitializeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`, 853 `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()` 854 @*/ 855 PetscErrorCode DMSwarmFinalizeFieldRegister(DM dm) 856 { 857 DM_Swarm *swarm = (DM_Swarm *)dm->data; 858 859 PetscFunctionBegin; 860 if (!swarm->field_registration_finalized) PetscCall(DMSwarmDataBucketFinalize(swarm->db)); 861 swarm->field_registration_finalized = PETSC_TRUE; 862 PetscFunctionReturn(PETSC_SUCCESS); 863 } 864 865 /*@ 866 DMSwarmSetLocalSizes - Sets the length of all registered fields on the `DMSWARM` 867 868 Not Collective 869 870 Input Parameters: 871 + dm - a `DMSWARM` 872 . nlocal - the length of each registered field 873 - buffer - the length of the buffer used to efficient dynamic re-sizing 874 875 Level: beginner 876 877 .seealso: `DM`, `DMSWARM`, `DMSwarmGetLocalSize()` 878 @*/ 879 PetscErrorCode DMSwarmSetLocalSizes(DM dm, PetscInt nlocal, PetscInt buffer) 880 { 881 DM_Swarm *swarm = (DM_Swarm *)dm->data; 882 883 PetscFunctionBegin; 884 PetscCall(PetscLogEventBegin(DMSWARM_SetSizes, 0, 0, 0, 0)); 885 PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, buffer)); 886 PetscCall(PetscLogEventEnd(DMSWARM_SetSizes, 0, 0, 0, 0)); 887 PetscFunctionReturn(PETSC_SUCCESS); 888 } 889 890 /*@ 891 DMSwarmSetCellDM - Attaches a `DM` to a `DMSWARM` 892 893 Collective 894 895 Input Parameters: 896 + dm - a `DMSWARM` 897 - dmcell - the `DM` to attach to the `DMSWARM` 898 899 Level: beginner 900 901 Note: 902 The attached `DM` (dmcell) will be queried for point location and 903 neighbor MPI-rank information if `DMSwarmMigrate()` is called. 904 905 .seealso: `DM`, `DMSWARM`, `DMSwarmSetType()`, `DMSwarmGetCellDM()`, `DMSwarmMigrate()` 906 @*/ 907 PetscErrorCode DMSwarmSetCellDM(DM dm, DM dmcell) 908 { 909 DM_Swarm *swarm = (DM_Swarm *)dm->data; 910 911 PetscFunctionBegin; 912 swarm->dmcell = dmcell; 913 PetscFunctionReturn(PETSC_SUCCESS); 914 } 915 916 /*@ 917 DMSwarmGetCellDM - Fetches the attached cell `DM` 918 919 Collective 920 921 Input Parameter: 922 . dm - a `DMSWARM` 923 924 Output Parameter: 925 . dmcell - the `DM` which was attached to the `DMSWARM` 926 927 Level: beginner 928 929 .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()` 930 @*/ 931 PetscErrorCode DMSwarmGetCellDM(DM dm, DM *dmcell) 932 { 933 DM_Swarm *swarm = (DM_Swarm *)dm->data; 934 935 PetscFunctionBegin; 936 *dmcell = swarm->dmcell; 937 PetscFunctionReturn(PETSC_SUCCESS); 938 } 939 940 /*@ 941 DMSwarmGetLocalSize - Retrieves the local length of fields registered 942 943 Not Collective 944 945 Input Parameter: 946 . dm - a `DMSWARM` 947 948 Output Parameter: 949 . nlocal - the length of each registered field 950 951 Level: beginner 952 953 .seealso: `DM`, `DMSWARM`, `DMSwarmGetSize()`, `DMSwarmSetLocalSizes()` 954 @*/ 955 PetscErrorCode DMSwarmGetLocalSize(DM dm, PetscInt *nlocal) 956 { 957 DM_Swarm *swarm = (DM_Swarm *)dm->data; 958 959 PetscFunctionBegin; 960 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, nlocal, NULL, NULL)); 961 PetscFunctionReturn(PETSC_SUCCESS); 962 } 963 964 /*@ 965 DMSwarmGetSize - Retrieves the total length of fields registered 966 967 Collective 968 969 Input Parameter: 970 . dm - a `DMSWARM` 971 972 Output Parameter: 973 . n - the total length of each registered field 974 975 Level: beginner 976 977 Note: 978 This calls `MPI_Allreduce()` upon each call (inefficient but safe) 979 980 .seealso: `DM`, `DMSWARM`, `DMSwarmGetLocalSize()`, `DMSwarmSetLocalSizes()` 981 @*/ 982 PetscErrorCode DMSwarmGetSize(DM dm, PetscInt *n) 983 { 984 DM_Swarm *swarm = (DM_Swarm *)dm->data; 985 PetscInt nlocal; 986 987 PetscFunctionBegin; 988 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL)); 989 PetscCall(MPIU_Allreduce(&nlocal, n, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 990 PetscFunctionReturn(PETSC_SUCCESS); 991 } 992 993 /*@C 994 DMSwarmRegisterPetscDatatypeField - Register a field to a `DMSWARM` with a native PETSc data type 995 996 Collective 997 998 Input Parameters: 999 + dm - a `DMSWARM` 1000 . fieldname - the textual name to identify this field 1001 . blocksize - the number of each data type 1002 - type - a valid PETSc data type (`PETSC_CHAR`, `PETSC_SHORT`, `PETSC_INT`, `PETSC_FLOAT`, `PETSC_REAL`, `PETSC_LONG`) 1003 1004 Level: beginner 1005 1006 Notes: 1007 The textual name for each registered field must be unique. 1008 1009 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()` 1010 @*/ 1011 PetscErrorCode DMSwarmRegisterPetscDatatypeField(DM dm, const char fieldname[], PetscInt blocksize, PetscDataType type) 1012 { 1013 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1014 size_t size; 1015 1016 PetscFunctionBegin; 1017 PetscCheck(swarm->field_registration_initialized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmInitializeFieldRegister() first"); 1018 PetscCheck(!swarm->field_registration_finalized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Cannot register additional fields after calling DMSwarmFinalizeFieldRegister() first"); 1019 1020 PetscCheck(type != PETSC_OBJECT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}"); 1021 PetscCheck(type != PETSC_FUNCTION, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}"); 1022 PetscCheck(type != PETSC_STRING, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}"); 1023 PetscCheck(type != PETSC_STRUCT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}"); 1024 PetscCheck(type != PETSC_DATATYPE_UNKNOWN, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}"); 1025 1026 PetscCall(PetscDataTypeGetSize(type, &size)); 1027 /* Load a specific data type into data bucket, specifying textual name and its size in bytes */ 1028 PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterPetscDatatypeField", fieldname, blocksize * size, NULL)); 1029 { 1030 DMSwarmDataField gfield; 1031 1032 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield)); 1033 PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize)); 1034 } 1035 swarm->db->field[swarm->db->nfields - 1]->petsc_type = type; 1036 PetscFunctionReturn(PETSC_SUCCESS); 1037 } 1038 1039 /*@C 1040 DMSwarmRegisterUserStructField - Register a user defined struct to a `DMSWARM` 1041 1042 Collective 1043 1044 Input Parameters: 1045 + dm - a `DMSWARM` 1046 . fieldname - the textual name to identify this field 1047 - size - the size in bytes of the user struct of each data type 1048 1049 Level: beginner 1050 1051 Note: 1052 The textual name for each registered field must be unique. 1053 1054 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserDatatypeField()` 1055 @*/ 1056 PetscErrorCode DMSwarmRegisterUserStructField(DM dm, const char fieldname[], size_t size) 1057 { 1058 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1059 1060 PetscFunctionBegin; 1061 PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserStructField", fieldname, size, NULL)); 1062 swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_STRUCT; 1063 PetscFunctionReturn(PETSC_SUCCESS); 1064 } 1065 1066 /*@C 1067 DMSwarmRegisterUserDatatypeField - Register a user defined data type to a `DMSWARM` 1068 1069 Collective 1070 1071 Input Parameters: 1072 + dm - a `DMSWARM` 1073 . fieldname - the textual name to identify this field 1074 . size - the size in bytes of the user data type 1075 - blocksize - the number of each data type 1076 1077 Level: beginner 1078 1079 Note: 1080 The textual name for each registered field must be unique. 1081 1082 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserStructField()` 1083 @*/ 1084 PetscErrorCode DMSwarmRegisterUserDatatypeField(DM dm, const char fieldname[], size_t size, PetscInt blocksize) 1085 { 1086 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1087 1088 PetscFunctionBegin; 1089 PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserDatatypeField", fieldname, blocksize * size, NULL)); 1090 { 1091 DMSwarmDataField gfield; 1092 1093 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield)); 1094 PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize)); 1095 } 1096 swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_DATATYPE_UNKNOWN; 1097 PetscFunctionReturn(PETSC_SUCCESS); 1098 } 1099 1100 /*@C 1101 DMSwarmGetField - Get access to the underlying array storing all entries associated with a registered field 1102 1103 Not Collective 1104 1105 Input Parameters: 1106 + dm - a `DMSWARM` 1107 - fieldname - the textual name to identify this field 1108 1109 Output Parameters: 1110 + blocksize - the number of each data type 1111 . type - the data type 1112 - data - pointer to raw array 1113 1114 Level: beginner 1115 1116 Notes: 1117 The array must be returned using a matching call to `DMSwarmRestoreField()`. 1118 1119 .seealso: `DM`, `DMSWARM`, `DMSwarmRestoreField()` 1120 @*/ 1121 PetscErrorCode DMSwarmGetField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data) 1122 { 1123 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1124 DMSwarmDataField gfield; 1125 1126 PetscFunctionBegin; 1127 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 1128 if (!swarm->issetup) PetscCall(DMSetUp(dm)); 1129 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield)); 1130 PetscCall(DMSwarmDataFieldGetAccess(gfield)); 1131 PetscCall(DMSwarmDataFieldGetEntries(gfield, data)); 1132 if (blocksize) *blocksize = gfield->bs; 1133 if (type) *type = gfield->petsc_type; 1134 PetscFunctionReturn(PETSC_SUCCESS); 1135 } 1136 1137 /*@C 1138 DMSwarmRestoreField - Restore access to the underlying array storing all entries associated with a registered field 1139 1140 Not Collective 1141 1142 Input Parameters: 1143 + dm - a `DMSWARM` 1144 - fieldname - the textual name to identify this field 1145 1146 Output Parameters: 1147 + blocksize - the number of each data type 1148 . type - the data type 1149 - data - pointer to raw array 1150 1151 Level: beginner 1152 1153 Notes: 1154 The user must call `DMSwarmGetField()` prior to calling `DMSwarmRestoreField()`. 1155 1156 .seealso: `DM`, `DMSWARM`, `DMSwarmGetField()` 1157 @*/ 1158 PetscErrorCode DMSwarmRestoreField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data) 1159 { 1160 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1161 DMSwarmDataField gfield; 1162 1163 PetscFunctionBegin; 1164 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 1165 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield)); 1166 PetscCall(DMSwarmDataFieldRestoreAccess(gfield)); 1167 if (data) *data = NULL; 1168 PetscFunctionReturn(PETSC_SUCCESS); 1169 } 1170 1171 PetscErrorCode DMSwarmGetFieldInfo(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type) 1172 { 1173 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1174 DMSwarmDataField gfield; 1175 1176 PetscFunctionBegin; 1177 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 1178 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield)); 1179 if (blocksize) *blocksize = gfield->bs; 1180 if (type) *type = gfield->petsc_type; 1181 PetscFunctionReturn(PETSC_SUCCESS); 1182 } 1183 1184 /*@ 1185 DMSwarmAddPoint - Add space for one new point in the `DMSWARM` 1186 1187 Not Collective 1188 1189 Input Parameter: 1190 . dm - a `DMSWARM` 1191 1192 Level: beginner 1193 1194 Notes: 1195 The new point will have all fields initialized to zero. 1196 1197 .seealso: `DM`, `DMSWARM`, `DMSwarmAddNPoints()` 1198 @*/ 1199 PetscErrorCode DMSwarmAddPoint(DM dm) 1200 { 1201 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1202 1203 PetscFunctionBegin; 1204 if (!swarm->issetup) PetscCall(DMSetUp(dm)); 1205 PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0)); 1206 PetscCall(DMSwarmDataBucketAddPoint(swarm->db)); 1207 PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0)); 1208 PetscFunctionReturn(PETSC_SUCCESS); 1209 } 1210 1211 /*@ 1212 DMSwarmAddNPoints - Add space for a number of new points in the `DMSWARM` 1213 1214 Not Collective 1215 1216 Input Parameters: 1217 + dm - a `DMSWARM` 1218 - npoints - the number of new points to add 1219 1220 Level: beginner 1221 1222 Notes: 1223 The new point will have all fields initialized to zero. 1224 1225 .seealso: `DM`, `DMSWARM`, `DMSwarmAddPoint()` 1226 @*/ 1227 PetscErrorCode DMSwarmAddNPoints(DM dm, PetscInt npoints) 1228 { 1229 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1230 PetscInt nlocal; 1231 1232 PetscFunctionBegin; 1233 PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0)); 1234 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL)); 1235 nlocal = nlocal + npoints; 1236 PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT)); 1237 PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0)); 1238 PetscFunctionReturn(PETSC_SUCCESS); 1239 } 1240 1241 /*@ 1242 DMSwarmRemovePoint - Remove the last point from the `DMSWARM` 1243 1244 Not Collective 1245 1246 Input Parameter: 1247 . dm - a `DMSWARM` 1248 1249 Level: beginner 1250 1251 .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePointAtIndex()` 1252 @*/ 1253 PetscErrorCode DMSwarmRemovePoint(DM dm) 1254 { 1255 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1256 1257 PetscFunctionBegin; 1258 PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0)); 1259 PetscCall(DMSwarmDataBucketRemovePoint(swarm->db)); 1260 PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0)); 1261 PetscFunctionReturn(PETSC_SUCCESS); 1262 } 1263 1264 /*@ 1265 DMSwarmRemovePointAtIndex - Removes a specific point from the `DMSWARM` 1266 1267 Not Collective 1268 1269 Input Parameters: 1270 + dm - a `DMSWARM` 1271 - idx - index of point to remove 1272 1273 Level: beginner 1274 1275 .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePoint()` 1276 @*/ 1277 PetscErrorCode DMSwarmRemovePointAtIndex(DM dm, PetscInt idx) 1278 { 1279 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1280 1281 PetscFunctionBegin; 1282 PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0)); 1283 PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, idx)); 1284 PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0)); 1285 PetscFunctionReturn(PETSC_SUCCESS); 1286 } 1287 1288 /*@ 1289 DMSwarmCopyPoint - Copy point pj to point pi in the `DMSWARM` 1290 1291 Not Collective 1292 1293 Input Parameters: 1294 + dm - a `DMSWARM` 1295 . pi - the index of the point to copy 1296 - pj - the point index where the copy should be located 1297 1298 Level: beginner 1299 1300 .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePoint()` 1301 @*/ 1302 PetscErrorCode DMSwarmCopyPoint(DM dm, PetscInt pi, PetscInt pj) 1303 { 1304 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1305 1306 PetscFunctionBegin; 1307 if (!swarm->issetup) PetscCall(DMSetUp(dm)); 1308 PetscCall(DMSwarmDataBucketCopyPoint(swarm->db, pi, swarm->db, pj)); 1309 PetscFunctionReturn(PETSC_SUCCESS); 1310 } 1311 1312 static PetscErrorCode DMSwarmMigrate_Basic(DM dm, PetscBool remove_sent_points) 1313 { 1314 PetscFunctionBegin; 1315 PetscCall(DMSwarmMigrate_Push_Basic(dm, remove_sent_points)); 1316 PetscFunctionReturn(PETSC_SUCCESS); 1317 } 1318 1319 /*@ 1320 DMSwarmMigrate - Relocates points defined in the `DMSWARM` to other MPI-ranks 1321 1322 Collective 1323 1324 Input Parameters: 1325 + dm - the `DMSWARM` 1326 - remove_sent_points - flag indicating if sent points should be removed from the current MPI-rank 1327 1328 Level: advanced 1329 1330 Notes: 1331 The `DM` will be modified to accommodate received points. 1332 If `remove_sent_points` is `PETSC_TRUE`, any points that were sent will be removed from the `DM`. 1333 Different styles of migration are supported. See `DMSwarmSetMigrateType()`. 1334 1335 .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()` 1336 @*/ 1337 PetscErrorCode DMSwarmMigrate(DM dm, PetscBool remove_sent_points) 1338 { 1339 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1340 1341 PetscFunctionBegin; 1342 PetscCall(PetscLogEventBegin(DMSWARM_Migrate, 0, 0, 0, 0)); 1343 switch (swarm->migrate_type) { 1344 case DMSWARM_MIGRATE_BASIC: 1345 PetscCall(DMSwarmMigrate_Basic(dm, remove_sent_points)); 1346 break; 1347 case DMSWARM_MIGRATE_DMCELLNSCATTER: 1348 PetscCall(DMSwarmMigrate_CellDMScatter(dm, remove_sent_points)); 1349 break; 1350 case DMSWARM_MIGRATE_DMCELLEXACT: 1351 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_DMCELLEXACT not implemented"); 1352 case DMSWARM_MIGRATE_USER: 1353 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_USER not implemented"); 1354 default: 1355 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE type unknown"); 1356 } 1357 PetscCall(PetscLogEventEnd(DMSWARM_Migrate, 0, 0, 0, 0)); 1358 PetscCall(DMClearGlobalVectors(dm)); 1359 PetscFunctionReturn(PETSC_SUCCESS); 1360 } 1361 1362 PetscErrorCode DMSwarmMigrate_GlobalToLocal_Basic(DM dm, PetscInt *globalsize); 1363 1364 /* 1365 DMSwarmCollectViewCreate 1366 1367 * Applies a collection method and gathers point neighbour points into dm 1368 1369 Notes: 1370 Users should call DMSwarmCollectViewDestroy() after 1371 they have finished computations associated with the collected points 1372 */ 1373 1374 /*@ 1375 DMSwarmCollectViewCreate - Applies a collection method and gathers points 1376 in neighbour ranks into the `DMSWARM` 1377 1378 Collective 1379 1380 Input Parameter: 1381 . dm - the `DMSWARM` 1382 1383 Level: advanced 1384 1385 Notes: 1386 Users should call `DMSwarmCollectViewDestroy()` after 1387 they have finished computations associated with the collected points 1388 Different collect methods are supported. See `DMSwarmSetCollectType()`. 1389 1390 .seealso: `DM`, `DMSWARM`, `DMSwarmCollectViewDestroy()`, `DMSwarmSetCollectType()` 1391 @*/ 1392 PetscErrorCode DMSwarmCollectViewCreate(DM dm) 1393 { 1394 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1395 PetscInt ng; 1396 1397 PetscFunctionBegin; 1398 PetscCheck(!swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView currently active"); 1399 PetscCall(DMSwarmGetLocalSize(dm, &ng)); 1400 switch (swarm->collect_type) { 1401 case DMSWARM_COLLECT_BASIC: 1402 PetscCall(DMSwarmMigrate_GlobalToLocal_Basic(dm, &ng)); 1403 break; 1404 case DMSWARM_COLLECT_DMDABOUNDINGBOX: 1405 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_DMDABOUNDINGBOX not implemented"); 1406 case DMSWARM_COLLECT_GENERAL: 1407 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_GENERAL not implemented"); 1408 default: 1409 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT type unknown"); 1410 } 1411 swarm->collect_view_active = PETSC_TRUE; 1412 swarm->collect_view_reset_nlocal = ng; 1413 PetscFunctionReturn(PETSC_SUCCESS); 1414 } 1415 1416 /*@ 1417 DMSwarmCollectViewDestroy - Resets the `DMSWARM` to the size prior to calling `DMSwarmCollectViewCreate()` 1418 1419 Collective 1420 1421 Input Parameters: 1422 . dm - the `DMSWARM` 1423 1424 Notes: 1425 Users should call `DMSwarmCollectViewCreate()` before this function is called. 1426 1427 Level: advanced 1428 1429 .seealso: `DM`, `DMSWARM`, `DMSwarmCollectViewCreate()`, `DMSwarmSetCollectType()` 1430 @*/ 1431 PetscErrorCode DMSwarmCollectViewDestroy(DM dm) 1432 { 1433 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1434 1435 PetscFunctionBegin; 1436 PetscCheck(swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView is currently not active"); 1437 PetscCall(DMSwarmSetLocalSizes(dm, swarm->collect_view_reset_nlocal, -1)); 1438 swarm->collect_view_active = PETSC_FALSE; 1439 PetscFunctionReturn(PETSC_SUCCESS); 1440 } 1441 1442 static PetscErrorCode DMSwarmSetUpPIC(DM dm) 1443 { 1444 PetscInt dim; 1445 1446 PetscFunctionBegin; 1447 PetscCall(DMSwarmSetNumSpecies(dm, 1)); 1448 PetscCall(DMGetDimension(dm, &dim)); 1449 PetscCheck(dim >= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim); 1450 PetscCheck(dim <= 3, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim); 1451 PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmPICField_coor, dim, PETSC_DOUBLE)); 1452 PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmPICField_cellid, 1, PETSC_INT)); 1453 PetscFunctionReturn(PETSC_SUCCESS); 1454 } 1455 1456 /*@ 1457 DMSwarmSetPointCoordinatesRandom - Sets initial coordinates for particles in each cell 1458 1459 Collective 1460 1461 Input Parameters: 1462 + dm - the `DMSWARM` 1463 - Npc - The number of particles per cell in the cell `DM` 1464 1465 Level: intermediate 1466 1467 Notes: 1468 The user must use `DMSwarmSetCellDM()` to set the cell `DM` first. The particles are placed randomly inside each cell. If only 1469 one particle is in each cell, it is placed at the centroid. 1470 1471 .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()` 1472 @*/ 1473 PetscErrorCode DMSwarmSetPointCoordinatesRandom(DM dm, PetscInt Npc) 1474 { 1475 DM cdm; 1476 PetscRandom rnd; 1477 DMPolytopeType ct; 1478 PetscBool simplex; 1479 PetscReal *centroid, *coords, *xi0, *v0, *J, *invJ, detJ; 1480 PetscInt dim, d, cStart, cEnd, c, p; 1481 1482 PetscFunctionBeginUser; 1483 PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)dm), &rnd)); 1484 PetscCall(PetscRandomSetInterval(rnd, -1.0, 1.0)); 1485 PetscCall(PetscRandomSetType(rnd, PETSCRAND48)); 1486 1487 PetscCall(DMSwarmGetCellDM(dm, &cdm)); 1488 PetscCall(DMGetDimension(cdm, &dim)); 1489 PetscCall(DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd)); 1490 PetscCall(DMPlexGetCellType(cdm, cStart, &ct)); 1491 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 1492 1493 PetscCall(PetscMalloc5(dim, ¢roid, dim, &xi0, dim, &v0, dim * dim, &J, dim * dim, &invJ)); 1494 for (d = 0; d < dim; ++d) xi0[d] = -1.0; 1495 PetscCall(DMSwarmGetField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 1496 for (c = cStart; c < cEnd; ++c) { 1497 if (Npc == 1) { 1498 PetscCall(DMPlexComputeCellGeometryFVM(cdm, c, NULL, centroid, NULL)); 1499 for (d = 0; d < dim; ++d) coords[c * dim + d] = centroid[d]; 1500 } else { 1501 PetscCall(DMPlexComputeCellGeometryFEM(cdm, c, NULL, v0, J, invJ, &detJ)); /* affine */ 1502 for (p = 0; p < Npc; ++p) { 1503 const PetscInt n = c * Npc + p; 1504 PetscReal sum = 0.0, refcoords[3]; 1505 1506 for (d = 0; d < dim; ++d) { 1507 PetscCall(PetscRandomGetValueReal(rnd, &refcoords[d])); 1508 sum += refcoords[d]; 1509 } 1510 if (simplex && sum > 0.0) 1511 for (d = 0; d < dim; ++d) refcoords[d] -= PetscSqrtReal(dim) * sum; 1512 CoordinatesRefToReal(dim, dim, xi0, v0, J, refcoords, &coords[n * dim]); 1513 } 1514 } 1515 } 1516 PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 1517 PetscCall(PetscFree5(centroid, xi0, v0, J, invJ)); 1518 PetscCall(PetscRandomDestroy(&rnd)); 1519 PetscFunctionReturn(PETSC_SUCCESS); 1520 } 1521 1522 /*@ 1523 DMSwarmSetType - Set particular flavor of `DMSWARM` 1524 1525 Collective 1526 1527 Input Parameters: 1528 + dm - the `DMSWARM` 1529 - stype - the `DMSWARM` type (e.g. `DMSWARM_PIC`) 1530 1531 Level: advanced 1532 1533 .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()`, `DMSwarmSetCollectType()`, `DMSwarmType`, `DMSWARM_PIC`, `DMSWARM_BASIC` 1534 @*/ 1535 PetscErrorCode DMSwarmSetType(DM dm, DMSwarmType stype) 1536 { 1537 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1538 1539 PetscFunctionBegin; 1540 swarm->swarm_type = stype; 1541 if (swarm->swarm_type == DMSWARM_PIC) PetscCall(DMSwarmSetUpPIC(dm)); 1542 PetscFunctionReturn(PETSC_SUCCESS); 1543 } 1544 1545 static PetscErrorCode DMSetup_Swarm(DM dm) 1546 { 1547 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1548 PetscMPIInt rank; 1549 PetscInt p, npoints, *rankval; 1550 1551 PetscFunctionBegin; 1552 if (swarm->issetup) PetscFunctionReturn(PETSC_SUCCESS); 1553 swarm->issetup = PETSC_TRUE; 1554 1555 if (swarm->swarm_type == DMSWARM_PIC) { 1556 /* check dmcell exists */ 1557 PetscCheck(swarm->dmcell, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires you call DMSwarmSetCellDM"); 1558 1559 if (swarm->dmcell->ops->locatepointssubdomain) { 1560 /* check methods exists for exact ownership identificiation */ 1561 PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->ops->LocatePointsSubdomain\n")); 1562 swarm->migrate_type = DMSWARM_MIGRATE_DMCELLEXACT; 1563 } else { 1564 /* check methods exist for point location AND rank neighbor identification */ 1565 if (swarm->dmcell->ops->locatepoints) { 1566 PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->LocatePoints\n")); 1567 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->locatepoints be defined"); 1568 1569 if (swarm->dmcell->ops->getneighbors) { 1570 PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->GetNeigbors\n")); 1571 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->getneighbors be defined"); 1572 1573 swarm->migrate_type = DMSWARM_MIGRATE_DMCELLNSCATTER; 1574 } 1575 } 1576 1577 PetscCall(DMSwarmFinalizeFieldRegister(dm)); 1578 1579 /* check some fields were registered */ 1580 PetscCheck(swarm->db->nfields > 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "At least one field user must be registered via DMSwarmRegisterXXX()"); 1581 1582 /* check local sizes were set */ 1583 PetscCheck(swarm->db->L != -1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Local sizes must be set via DMSwarmSetLocalSizes()"); 1584 1585 /* initialize values in pid and rank placeholders */ 1586 /* TODO: [pid - use MPI_Scan] */ 1587 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1588 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); 1589 PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval)); 1590 for (p = 0; p < npoints; p++) rankval[p] = (PetscInt)rank; 1591 PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval)); 1592 PetscFunctionReturn(PETSC_SUCCESS); 1593 } 1594 1595 extern PetscErrorCode DMSwarmSortDestroy(DMSwarmSort *_ctx); 1596 1597 static PetscErrorCode DMDestroy_Swarm(DM dm) 1598 { 1599 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1600 1601 PetscFunctionBegin; 1602 if (--swarm->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 1603 PetscCall(DMSwarmDataBucketDestroy(&swarm->db)); 1604 if (swarm->sort_context) PetscCall(DMSwarmSortDestroy(&swarm->sort_context)); 1605 PetscCall(PetscFree(swarm)); 1606 PetscFunctionReturn(PETSC_SUCCESS); 1607 } 1608 1609 static PetscErrorCode DMSwarmView_Draw(DM dm, PetscViewer viewer) 1610 { 1611 DM cdm; 1612 PetscDraw draw; 1613 PetscReal *coords, oldPause, radius = 0.01; 1614 PetscInt Np, p, bs; 1615 1616 PetscFunctionBegin; 1617 PetscCall(PetscOptionsGetReal(NULL, ((PetscObject)dm)->prefix, "-dm_view_swarm_radius", &radius, NULL)); 1618 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1619 PetscCall(DMSwarmGetCellDM(dm, &cdm)); 1620 PetscCall(PetscDrawGetPause(draw, &oldPause)); 1621 PetscCall(PetscDrawSetPause(draw, 0.0)); 1622 PetscCall(DMView(cdm, viewer)); 1623 PetscCall(PetscDrawSetPause(draw, oldPause)); 1624 1625 PetscCall(DMSwarmGetLocalSize(dm, &Np)); 1626 PetscCall(DMSwarmGetField(dm, DMSwarmPICField_coor, &bs, NULL, (void **)&coords)); 1627 for (p = 0; p < Np; ++p) { 1628 const PetscInt i = p * bs; 1629 1630 PetscCall(PetscDrawEllipse(draw, coords[i], coords[i + 1], radius, radius, PETSC_DRAW_BLUE)); 1631 } 1632 PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_coor, &bs, NULL, (void **)&coords)); 1633 PetscCall(PetscDrawFlush(draw)); 1634 PetscCall(PetscDrawPause(draw)); 1635 PetscCall(PetscDrawSave(draw)); 1636 PetscFunctionReturn(PETSC_SUCCESS); 1637 } 1638 1639 static PetscErrorCode DMView_Swarm_Ascii(DM dm, PetscViewer viewer) 1640 { 1641 PetscViewerFormat format; 1642 PetscInt *sizes; 1643 PetscInt dim, Np, maxSize = 17; 1644 MPI_Comm comm; 1645 PetscMPIInt rank, size, p; 1646 const char *name; 1647 1648 PetscFunctionBegin; 1649 PetscCall(PetscViewerGetFormat(viewer, &format)); 1650 PetscCall(DMGetDimension(dm, &dim)); 1651 PetscCall(DMSwarmGetLocalSize(dm, &Np)); 1652 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1653 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1654 PetscCallMPI(MPI_Comm_size(comm, &size)); 1655 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1656 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1657 else PetscCall(PetscViewerASCIIPrintf(viewer, "Swarm in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1658 if (size < maxSize) PetscCall(PetscCalloc1(size, &sizes)); 1659 else PetscCall(PetscCalloc1(3, &sizes)); 1660 if (size < maxSize) { 1661 PetscCallMPI(MPI_Gather(&Np, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1662 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of particles per rank:")); 1663 for (p = 0; p < size; ++p) { 1664 if (rank == 0) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p])); 1665 } 1666 } else { 1667 PetscInt locMinMax[2] = {Np, Np}; 1668 1669 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1670 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of particles per rank: %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1671 } 1672 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1673 PetscCall(PetscFree(sizes)); 1674 if (format == PETSC_VIEWER_ASCII_INFO) { 1675 PetscInt *cell; 1676 1677 PetscCall(PetscViewerASCIIPrintf(viewer, " Cells containing each particle:\n")); 1678 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1679 PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&cell)); 1680 for (p = 0; p < Np; ++p) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " p%d: %" PetscInt_FMT "\n", p, cell[p])); 1681 PetscCall(PetscViewerFlush(viewer)); 1682 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1683 PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&cell)); 1684 } 1685 PetscFunctionReturn(PETSC_SUCCESS); 1686 } 1687 1688 static PetscErrorCode DMView_Swarm(DM dm, PetscViewer viewer) 1689 { 1690 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1691 PetscBool iascii, ibinary, isvtk, isdraw; 1692 #if defined(PETSC_HAVE_HDF5) 1693 PetscBool ishdf5; 1694 #endif 1695 1696 PetscFunctionBegin; 1697 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1698 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1699 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1700 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &ibinary)); 1701 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1702 #if defined(PETSC_HAVE_HDF5) 1703 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1704 #endif 1705 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1706 if (iascii) { 1707 PetscViewerFormat format; 1708 1709 PetscCall(PetscViewerGetFormat(viewer, &format)); 1710 switch (format) { 1711 case PETSC_VIEWER_ASCII_INFO_DETAIL: 1712 PetscCall(DMSwarmDataBucketView(PetscObjectComm((PetscObject)dm), swarm->db, NULL, DATABUCKET_VIEW_STDOUT)); 1713 break; 1714 default: 1715 PetscCall(DMView_Swarm_Ascii(dm, viewer)); 1716 } 1717 } else { 1718 #if defined(PETSC_HAVE_HDF5) 1719 if (ishdf5) PetscCall(DMSwarmView_HDF5(dm, viewer)); 1720 #endif 1721 if (isdraw) PetscCall(DMSwarmView_Draw(dm, viewer)); 1722 } 1723 PetscFunctionReturn(PETSC_SUCCESS); 1724 } 1725 1726 /*@C 1727 DMSwarmGetCellSwarm - Extracts a single cell from the `DMSWARM` object, returns it as a single cell `DMSWARM`. 1728 The cell `DM` is filtered for fields of that cell, and the filtered `DM` is used as the cell `DM` of the new swarm object. 1729 1730 Noncollective 1731 1732 Input Parameters: 1733 + sw - the `DMSWARM` 1734 . cellID - the integer id of the cell to be extracted and filtered 1735 - cellswarm - The `DMSWARM` to receive the cell 1736 1737 Level: beginner 1738 1739 Notes: 1740 This presently only supports `DMSWARM_PIC` type 1741 1742 Should be restored with `DMSwarmRestoreCellSwarm()` 1743 1744 Changes to this cell of the swarm will be lost if they are made prior to restoring this cell. 1745 1746 .seealso: `DM`, `DMSWARM`, `DMSwarmRestoreCellSwarm()` 1747 @*/ 1748 PETSC_EXTERN PetscErrorCode DMSwarmGetCellSwarm(DM sw, PetscInt cellID, DM cellswarm) 1749 { 1750 DM_Swarm *original = (DM_Swarm *)sw->data; 1751 DMLabel label; 1752 DM dmc, subdmc; 1753 PetscInt *pids, particles, dim; 1754 1755 PetscFunctionBegin; 1756 /* Configure new swarm */ 1757 PetscCall(DMSetType(cellswarm, DMSWARM)); 1758 PetscCall(DMGetDimension(sw, &dim)); 1759 PetscCall(DMSetDimension(cellswarm, dim)); 1760 PetscCall(DMSwarmSetType(cellswarm, DMSWARM_PIC)); 1761 /* Destroy the unused, unconfigured data bucket to prevent stragglers in memory */ 1762 PetscCall(DMSwarmDataBucketDestroy(&((DM_Swarm *)cellswarm->data)->db)); 1763 PetscCall(DMSwarmSortGetAccess(sw)); 1764 PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, cellID, &particles)); 1765 PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids)); 1766 PetscCall(DMSwarmDataBucketCreateFromSubset(original->db, particles, pids, &((DM_Swarm *)cellswarm->data)->db)); 1767 PetscCall(DMSwarmSortRestoreAccess(sw)); 1768 PetscCall(PetscFree(pids)); 1769 PetscCall(DMSwarmGetCellDM(sw, &dmc)); 1770 PetscCall(DMLabelCreate(PetscObjectComm((PetscObject)sw), "singlecell", &label)); 1771 PetscCall(DMAddLabel(dmc, label)); 1772 PetscCall(DMLabelSetValue(label, cellID, 1)); 1773 PetscCall(DMPlexFilter(dmc, label, 1, &subdmc)); 1774 PetscCall(DMSwarmSetCellDM(cellswarm, subdmc)); 1775 PetscCall(DMLabelDestroy(&label)); 1776 PetscFunctionReturn(PETSC_SUCCESS); 1777 } 1778 1779 /*@C 1780 DMSwarmRestoreCellSwarm - Restores a `DMSWARM` object obtained with `DMSwarmGetCellSwarm()`. All fields are copied back into the parent swarm. 1781 1782 Noncollective 1783 1784 Input Parameters: 1785 + sw - the parent `DMSWARM` 1786 . cellID - the integer id of the cell to be copied back into the parent swarm 1787 - cellswarm - the cell swarm object 1788 1789 Level: beginner 1790 1791 Note: 1792 This only supports `DMSWARM_PIC` types of `DMSWARM`s 1793 1794 .seealso: `DM`, `DMSWARM`, `DMSwarmGetCellSwarm()` 1795 @*/ 1796 PETSC_EXTERN PetscErrorCode DMSwarmRestoreCellSwarm(DM sw, PetscInt cellID, DM cellswarm) 1797 { 1798 DM dmc; 1799 PetscInt *pids, particles, p; 1800 1801 PetscFunctionBegin; 1802 PetscCall(DMSwarmSortGetAccess(sw)); 1803 PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids)); 1804 PetscCall(DMSwarmSortRestoreAccess(sw)); 1805 /* Pointwise copy of each particle based on pid. The parent swarm may not be altered during this process. */ 1806 for (p = 0; p < particles; ++p) PetscCall(DMSwarmDataBucketCopyPoint(((DM_Swarm *)cellswarm->data)->db, pids[p], ((DM_Swarm *)sw->data)->db, pids[p])); 1807 /* Free memory, destroy cell dm */ 1808 PetscCall(DMSwarmGetCellDM(cellswarm, &dmc)); 1809 PetscCall(DMDestroy(&dmc)); 1810 PetscCall(PetscFree(pids)); 1811 PetscFunctionReturn(PETSC_SUCCESS); 1812 } 1813 1814 PETSC_INTERN PetscErrorCode DMClone_Swarm(DM, DM *); 1815 1816 static PetscErrorCode DMInitialize_Swarm(DM sw) 1817 { 1818 PetscFunctionBegin; 1819 sw->dim = 0; 1820 sw->ops->view = DMView_Swarm; 1821 sw->ops->load = NULL; 1822 sw->ops->setfromoptions = NULL; 1823 sw->ops->clone = DMClone_Swarm; 1824 sw->ops->setup = DMSetup_Swarm; 1825 sw->ops->createlocalsection = NULL; 1826 sw->ops->createsectionpermutation = NULL; 1827 sw->ops->createdefaultconstraints = NULL; 1828 sw->ops->createglobalvector = DMCreateGlobalVector_Swarm; 1829 sw->ops->createlocalvector = DMCreateLocalVector_Swarm; 1830 sw->ops->getlocaltoglobalmapping = NULL; 1831 sw->ops->createfieldis = NULL; 1832 sw->ops->createcoordinatedm = NULL; 1833 sw->ops->getcoloring = NULL; 1834 sw->ops->creatematrix = DMCreateMatrix_Swarm; 1835 sw->ops->createinterpolation = NULL; 1836 sw->ops->createinjection = NULL; 1837 sw->ops->createmassmatrix = DMCreateMassMatrix_Swarm; 1838 sw->ops->refine = NULL; 1839 sw->ops->coarsen = NULL; 1840 sw->ops->refinehierarchy = NULL; 1841 sw->ops->coarsenhierarchy = NULL; 1842 sw->ops->globaltolocalbegin = NULL; 1843 sw->ops->globaltolocalend = NULL; 1844 sw->ops->localtoglobalbegin = NULL; 1845 sw->ops->localtoglobalend = NULL; 1846 sw->ops->destroy = DMDestroy_Swarm; 1847 sw->ops->createsubdm = NULL; 1848 sw->ops->getdimpoints = NULL; 1849 sw->ops->locatepoints = NULL; 1850 PetscFunctionReturn(PETSC_SUCCESS); 1851 } 1852 1853 PETSC_INTERN PetscErrorCode DMClone_Swarm(DM dm, DM *newdm) 1854 { 1855 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1856 1857 PetscFunctionBegin; 1858 swarm->refct++; 1859 (*newdm)->data = swarm; 1860 PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMSWARM)); 1861 PetscCall(DMInitialize_Swarm(*newdm)); 1862 (*newdm)->dim = dm->dim; 1863 PetscFunctionReturn(PETSC_SUCCESS); 1864 } 1865 1866 /*MC 1867 1868 DMSWARM = "swarm" - A `DM` object used to represent arrays of data (fields) of arbitrary data type. 1869 This implementation was designed for particle methods in which the underlying 1870 data required to be represented is both (i) dynamic in length, (ii) and of arbitrary data type. 1871 1872 Level: intermediate 1873 1874 Notes: 1875 User data can be represented by `DMSWARM` through a registering "fields". 1876 To register a field, the user must provide; 1877 (a) a unique name; 1878 (b) the data type (or size in bytes); 1879 (c) the block size of the data. 1880 1881 For example, suppose the application requires a unique id, energy, momentum and density to be stored 1882 on a set of particles. Then the following code could be used 1883 .vb 1884 DMSwarmInitializeFieldRegister(dm) 1885 DMSwarmRegisterPetscDatatypeField(dm,"uid",1,PETSC_LONG); 1886 DMSwarmRegisterPetscDatatypeField(dm,"energy",1,PETSC_REAL); 1887 DMSwarmRegisterPetscDatatypeField(dm,"momentum",3,PETSC_REAL); 1888 DMSwarmRegisterPetscDatatypeField(dm,"density",1,PETSC_FLOAT); 1889 DMSwarmFinalizeFieldRegister(dm) 1890 .ve 1891 1892 The fields represented by `DMSWARM` are dynamic and can be re-sized at any time. 1893 The only restriction imposed by `DMSWARM` is that all fields contain the same number of points. 1894 1895 To support particle methods, "migration" techniques are provided. These methods migrate data 1896 between ranks. 1897 1898 `DMSWARM` supports the methods `DMCreateGlobalVector()` and `DMCreateLocalVector()`. 1899 As a `DMSWARM` may internally define and store values of different data types, 1900 before calling `DMCreateGlobalVector()` or `DMCreateLocalVector()`, the user must inform `DMSWARM` which 1901 fields should be used to define a `Vec` object via 1902 `DMSwarmVectorDefineField()` 1903 The specified field can be changed at any time - thereby permitting vectors 1904 compatible with different fields to be created. 1905 1906 A dual representation of fields in the `DMSWARM` and a Vec object is permitted via 1907 `DMSwarmCreateGlobalVectorFromField()` 1908 Here the data defining the field in the `DMSWARM` is shared with a Vec. 1909 This is inherently unsafe if you alter the size of the field at any time between 1910 calls to `DMSwarmCreateGlobalVectorFromField()` and `DMSwarmDestroyGlobalVectorFromField()`. 1911 If the local size of the `DMSWARM` does not match the local size of the global vector 1912 when `DMSwarmDestroyGlobalVectorFromField()` is called, an error is thrown. 1913 1914 Additional high-level support is provided for Particle-In-Cell methods. 1915 Please refer to `DMSwarmSetType()`. 1916 1917 .seealso: `DM`, `DMSWARM`, `DMType`, `DMCreate()`, `DMSetType()` 1918 M*/ 1919 PETSC_EXTERN PetscErrorCode DMCreate_Swarm(DM dm) 1920 { 1921 DM_Swarm *swarm; 1922 1923 PetscFunctionBegin; 1924 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1925 PetscCall(PetscNew(&swarm)); 1926 dm->data = swarm; 1927 PetscCall(DMSwarmDataBucketCreate(&swarm->db)); 1928 PetscCall(DMSwarmInitializeFieldRegister(dm)); 1929 swarm->refct = 1; 1930 swarm->vec_field_set = PETSC_FALSE; 1931 swarm->issetup = PETSC_FALSE; 1932 swarm->swarm_type = DMSWARM_BASIC; 1933 swarm->migrate_type = DMSWARM_MIGRATE_BASIC; 1934 swarm->collect_type = DMSWARM_COLLECT_BASIC; 1935 swarm->migrate_error_on_missing_point = PETSC_FALSE; 1936 swarm->dmcell = NULL; 1937 swarm->collect_view_active = PETSC_FALSE; 1938 swarm->collect_view_reset_nlocal = -1; 1939 PetscCall(DMInitialize_Swarm(dm)); 1940 if (SwarmDataFieldId == -1) PetscCall(PetscObjectComposedDataRegister(&SwarmDataFieldId)); 1941 PetscFunctionReturn(PETSC_SUCCESS); 1942 } 1943