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