1 #include "petscdmswarm.h" 2 #define PETSCDM_DLL 3 #include <petsc/private/dmswarmimpl.h> /*I "petscdmswarm.h" I*/ 4 #include <petsc/private/hashsetij.h> 5 #include <petsc/private/petscfeimpl.h> 6 #include <petscviewer.h> 7 #include <petscdraw.h> 8 #include <petscdmplex.h> 9 #include <petscblaslapack.h> 10 #include "../src/dm/impls/swarm/data_bucket.h" 11 #include <petscdmlabel.h> 12 #include <petscsection.h> 13 14 PetscLogEvent DMSWARM_Migrate, DMSWARM_SetSizes, DMSWARM_AddPoints, DMSWARM_RemovePoints, DMSWARM_Sort; 15 PetscLogEvent DMSWARM_DataExchangerTopologySetup, DMSWARM_DataExchangerBegin, DMSWARM_DataExchangerEnd; 16 PetscLogEvent DMSWARM_DataExchangerSendCount, DMSWARM_DataExchangerPack; 17 18 const char *DMSwarmTypeNames[] = {"basic", "pic", NULL}; 19 const char *DMSwarmMigrateTypeNames[] = {"basic", "dmcellnscatter", "dmcellexact", "user", NULL}; 20 const char *DMSwarmCollectTypeNames[] = {"basic", "boundingbox", "general", "user", NULL}; 21 const char *DMSwarmRemapTypeNames[] = {"none", "pfak", "colella", "DMSwarmRemapType", "DMSWARM_REMAP_", NULL}; 22 const char *DMSwarmPICLayoutTypeNames[] = {"regular", "gauss", "subdivision", NULL}; 23 24 const char DMSwarmField_pid[] = "DMSwarm_pid"; 25 const char DMSwarmField_rank[] = "DMSwarm_rank"; 26 const char DMSwarmPICField_coor[] = "DMSwarmPIC_coor"; 27 28 PetscInt SwarmDataFieldId = -1; 29 30 #if defined(PETSC_HAVE_HDF5) 31 #include <petscviewerhdf5.h> 32 33 static PetscErrorCode VecView_Swarm_HDF5_Internal(Vec v, PetscViewer viewer) 34 { 35 DM dm; 36 PetscReal seqval; 37 PetscInt seqnum, bs; 38 PetscBool isseq, ists; 39 40 PetscFunctionBegin; 41 PetscCall(VecGetDM(v, &dm)); 42 PetscCall(VecGetBlockSize(v, &bs)); 43 PetscCall(PetscViewerHDF5PushGroup(viewer, "/particle_fields")); 44 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 45 PetscCall(DMGetOutputSequenceNumber(dm, &seqnum, &seqval)); 46 PetscCall(PetscViewerHDF5IsTimestepping(viewer, &ists)); 47 if (ists) PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum)); 48 /* PetscCall(DMSequenceView_HDF5(dm, "time", seqnum, (PetscScalar) seqval, viewer)); */ 49 PetscCall(VecViewNative(v, viewer)); 50 PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)v, "Nc", PETSC_INT, (void *)&bs)); 51 PetscCall(PetscViewerHDF5PopGroup(viewer)); 52 PetscFunctionReturn(PETSC_SUCCESS); 53 } 54 55 static PetscErrorCode DMSwarmView_HDF5(DM dm, PetscViewer viewer) 56 { 57 DMSwarmCellDM celldm; 58 Vec coordinates; 59 PetscInt Np, Nfc; 60 PetscBool isseq; 61 const char **coordFields; 62 63 PetscFunctionBegin; 64 PetscCall(DMSwarmGetCellDMActive(dm, &celldm)); 65 PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields)); 66 PetscCheck(Nfc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "We only support a single coordinate field right now, not %" PetscInt_FMT, Nfc); 67 PetscCall(DMSwarmGetSize(dm, &Np)); 68 PetscCall(DMSwarmCreateGlobalVectorFromField(dm, coordFields[0], &coordinates)); 69 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 70 PetscCall(PetscViewerHDF5PushGroup(viewer, "/particles")); 71 PetscCall(PetscObjectTypeCompare((PetscObject)coordinates, VECSEQ, &isseq)); 72 PetscCall(VecViewNative(coordinates, viewer)); 73 PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)coordinates, "Np", PETSC_INT, (void *)&Np)); 74 PetscCall(PetscViewerHDF5PopGroup(viewer)); 75 PetscCall(DMSwarmDestroyGlobalVectorFromField(dm, coordFields[0], &coordinates)); 76 PetscFunctionReturn(PETSC_SUCCESS); 77 } 78 #endif 79 80 static PetscErrorCode VecView_Swarm(Vec v, PetscViewer viewer) 81 { 82 DM dm; 83 #if defined(PETSC_HAVE_HDF5) 84 PetscBool ishdf5; 85 #endif 86 87 PetscFunctionBegin; 88 PetscCall(VecGetDM(v, &dm)); 89 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 90 #if defined(PETSC_HAVE_HDF5) 91 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 92 if (ishdf5) { 93 PetscCall(VecView_Swarm_HDF5_Internal(v, viewer)); 94 PetscFunctionReturn(PETSC_SUCCESS); 95 } 96 #endif 97 PetscCall(VecViewNative(v, viewer)); 98 PetscFunctionReturn(PETSC_SUCCESS); 99 } 100 101 /*@C 102 DMSwarmVectorGetField - Gets the fields from which to define a `Vec` object 103 when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called 104 105 Not collective 106 107 Input Parameter: 108 . sw - a `DMSWARM` 109 110 Output Parameters: 111 + Nf - the number of fields 112 - fieldnames - the textual name given to each registered field, or NULL if it has not been set 113 114 Level: beginner 115 116 .seealso: `DM`, `DMSWARM`, `DMSwarmVectorDefineField()`, `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()` 117 @*/ 118 PetscErrorCode DMSwarmVectorGetField(DM sw, PetscInt *Nf, const char **fieldnames[]) 119 { 120 DMSwarmCellDM celldm; 121 122 PetscFunctionBegin; 123 PetscValidHeaderSpecificType(sw, DM_CLASSID, 1, DMSWARM); 124 PetscCall(DMSwarmGetCellDMActive(sw, &celldm)); 125 PetscCall(DMSwarmCellDMGetFields(celldm, Nf, fieldnames)); 126 PetscFunctionReturn(PETSC_SUCCESS); 127 } 128 129 /*@ 130 DMSwarmVectorDefineField - Sets the field from which to define a `Vec` object 131 when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called 132 133 Collective 134 135 Input Parameters: 136 + dm - a `DMSWARM` 137 - fieldname - the textual name given to each registered field 138 139 Level: beginner 140 141 Notes: 142 The field with name `fieldname` must be defined as having a data type of `PetscScalar`. 143 144 This function must be called prior to calling `DMCreateLocalVector()`, `DMCreateGlobalVector()`. 145 Multiple calls to `DMSwarmVectorDefineField()` are permitted. 146 147 .seealso: `DM`, `DMSWARM`, `DMSwarmVectorDefineFields()`, `DMSwarmVectorGetField()`, `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()` 148 @*/ 149 PetscErrorCode DMSwarmVectorDefineField(DM dm, const char fieldname[]) 150 { 151 PetscFunctionBegin; 152 PetscCall(DMSwarmVectorDefineFields(dm, 1, &fieldname)); 153 PetscFunctionReturn(PETSC_SUCCESS); 154 } 155 156 /*@C 157 DMSwarmVectorDefineFields - Sets the fields from which to define a `Vec` object 158 when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called 159 160 Collective, No Fortran support 161 162 Input Parameters: 163 + sw - a `DMSWARM` 164 . Nf - the number of fields 165 - fieldnames - the textual name given to each registered field 166 167 Level: beginner 168 169 Notes: 170 Each field with name in `fieldnames` must be defined as having a data type of `PetscScalar`. 171 172 This function must be called prior to calling `DMCreateLocalVector()`, `DMCreateGlobalVector()`. 173 Multiple calls to `DMSwarmVectorDefineField()` are permitted. 174 175 .seealso: `DM`, `DMSWARM`, `DMSwarmVectorDefineField()`, `DMSwarmVectorGetField()`, `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()` 176 @*/ 177 PetscErrorCode DMSwarmVectorDefineFields(DM sw, PetscInt Nf, const char *fieldnames[]) 178 { 179 DM_Swarm *swarm = (DM_Swarm *)sw->data; 180 DMSwarmCellDM celldm; 181 182 PetscFunctionBegin; 183 PetscValidHeaderSpecificType(sw, DM_CLASSID, 1, DMSWARM); 184 if (fieldnames) PetscAssertPointer(fieldnames, 3); 185 if (!swarm->issetup) PetscCall(DMSetUp(sw)); 186 PetscCheck(Nf >= 0, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields must be non-negative, not %" PetscInt_FMT, Nf); 187 // Create a dummy cell DM if none has been specified (I think we should not support this mode) 188 if (!swarm->activeCellDM) { 189 DM dm; 190 DMSwarmCellDM celldm; 191 192 PetscCall(DMCreate(PetscObjectComm((PetscObject)sw), &dm)); 193 PetscCall(DMSetType(dm, DMSHELL)); 194 PetscCall(PetscObjectSetName((PetscObject)dm, "dummy")); 195 PetscCall(DMSwarmCellDMCreate(dm, 0, NULL, 0, NULL, &celldm)); 196 PetscCall(DMDestroy(&dm)); 197 PetscCall(DMSwarmAddCellDM(sw, celldm)); 198 PetscCall(DMSwarmCellDMDestroy(&celldm)); 199 PetscCall(DMSwarmSetCellDMActive(sw, "dummy")); 200 } 201 PetscCall(DMSwarmGetCellDMActive(sw, &celldm)); 202 for (PetscInt f = 0; f < celldm->Nf; ++f) PetscCall(PetscFree(celldm->dmFields[f])); 203 PetscCall(PetscFree(celldm->dmFields)); 204 205 celldm->Nf = Nf; 206 PetscCall(PetscMalloc1(Nf, &celldm->dmFields)); 207 for (PetscInt f = 0; f < Nf; ++f) { 208 PetscDataType type; 209 210 // Check all fields are of type PETSC_REAL or PETSC_SCALAR 211 PetscCall(DMSwarmGetFieldInfo(sw, fieldnames[f], NULL, &type)); 212 PetscCheck(type == PETSC_REAL, PetscObjectComm((PetscObject)sw), PETSC_ERR_SUP, "Only valid for PETSC_REAL"); 213 PetscCall(PetscStrallocpy(fieldnames[f], (char **)&celldm->dmFields[f])); 214 } 215 PetscFunctionReturn(PETSC_SUCCESS); 216 } 217 218 /* requires DMSwarmDefineFieldVector has been called */ 219 static PetscErrorCode DMCreateGlobalVector_Swarm(DM sw, Vec *vec) 220 { 221 DM_Swarm *swarm = (DM_Swarm *)sw->data; 222 DMSwarmCellDM celldm; 223 Vec x; 224 char name[PETSC_MAX_PATH_LEN]; 225 PetscInt bs = 0, n; 226 227 PetscFunctionBegin; 228 if (!swarm->issetup) PetscCall(DMSetUp(sw)); 229 PetscCall(DMSwarmGetCellDMActive(sw, &celldm)); 230 PetscCheck(celldm->Nf, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "Active cell DM does not define any fields"); 231 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL)); 232 233 PetscCall(PetscStrncpy(name, "DMSwarmField", PETSC_MAX_PATH_LEN)); 234 for (PetscInt f = 0; f < celldm->Nf; ++f) { 235 PetscInt fbs; 236 PetscCall(PetscStrlcat(name, "_", PETSC_MAX_PATH_LEN)); 237 PetscCall(PetscStrlcat(name, celldm->dmFields[f], PETSC_MAX_PATH_LEN)); 238 PetscCall(DMSwarmGetFieldInfo(sw, celldm->dmFields[f], &fbs, NULL)); 239 bs += fbs; 240 } 241 PetscCall(VecCreate(PetscObjectComm((PetscObject)sw), &x)); 242 PetscCall(PetscObjectSetName((PetscObject)x, name)); 243 PetscCall(VecSetSizes(x, n * bs, PETSC_DETERMINE)); 244 PetscCall(VecSetBlockSize(x, bs)); 245 PetscCall(VecSetDM(x, sw)); 246 PetscCall(VecSetFromOptions(x)); 247 PetscCall(VecSetOperation(x, VECOP_VIEW, (void (*)(void))VecView_Swarm)); 248 *vec = x; 249 PetscFunctionReturn(PETSC_SUCCESS); 250 } 251 252 /* requires DMSwarmDefineFieldVector has been called */ 253 static PetscErrorCode DMCreateLocalVector_Swarm(DM sw, Vec *vec) 254 { 255 DM_Swarm *swarm = (DM_Swarm *)sw->data; 256 DMSwarmCellDM celldm; 257 Vec x; 258 char name[PETSC_MAX_PATH_LEN]; 259 PetscInt bs = 0, n; 260 261 PetscFunctionBegin; 262 if (!swarm->issetup) PetscCall(DMSetUp(sw)); 263 PetscCall(DMSwarmGetCellDMActive(sw, &celldm)); 264 PetscCheck(celldm->Nf, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "Active cell DM does not define any fields"); 265 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL)); 266 267 PetscCall(PetscStrncpy(name, "DMSwarmField", PETSC_MAX_PATH_LEN)); 268 for (PetscInt f = 0; f < celldm->Nf; ++f) { 269 PetscInt fbs; 270 PetscCall(PetscStrlcat(name, "_", PETSC_MAX_PATH_LEN)); 271 PetscCall(PetscStrlcat(name, celldm->dmFields[f], PETSC_MAX_PATH_LEN)); 272 PetscCall(DMSwarmGetFieldInfo(sw, celldm->dmFields[f], &fbs, NULL)); 273 bs += fbs; 274 } 275 PetscCall(VecCreate(PETSC_COMM_SELF, &x)); 276 PetscCall(PetscObjectSetName((PetscObject)x, name)); 277 PetscCall(VecSetSizes(x, n * bs, PETSC_DETERMINE)); 278 PetscCall(VecSetBlockSize(x, bs)); 279 PetscCall(VecSetDM(x, sw)); 280 PetscCall(VecSetFromOptions(x)); 281 *vec = x; 282 PetscFunctionReturn(PETSC_SUCCESS); 283 } 284 285 static PetscErrorCode DMSwarmDestroyVectorFromField_Private(DM dm, const char fieldname[], Vec *vec) 286 { 287 DM_Swarm *swarm = (DM_Swarm *)dm->data; 288 DMSwarmDataField gfield; 289 PetscInt bs, nlocal, fid = -1, cfid = -2; 290 PetscBool flg; 291 292 PetscFunctionBegin; 293 /* check vector is an inplace array */ 294 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldname, &fid)); 295 PetscCall(PetscObjectComposedDataGetInt((PetscObject)*vec, SwarmDataFieldId, cfid, flg)); 296 (void)flg; /* avoid compiler warning */ 297 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); 298 PetscCall(VecGetLocalSize(*vec, &nlocal)); 299 PetscCall(VecGetBlockSize(*vec, &bs)); 300 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"); 301 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield)); 302 PetscCall(DMSwarmDataFieldRestoreAccess(gfield)); 303 PetscCall(VecResetArray(*vec)); 304 PetscCall(VecDestroy(vec)); 305 PetscFunctionReturn(PETSC_SUCCESS); 306 } 307 308 static PetscErrorCode DMSwarmCreateVectorFromField_Private(DM dm, const char fieldname[], MPI_Comm comm, Vec *vec) 309 { 310 DM_Swarm *swarm = (DM_Swarm *)dm->data; 311 PetscDataType type; 312 PetscScalar *array; 313 PetscInt bs, n, fid; 314 char name[PETSC_MAX_PATH_LEN]; 315 PetscMPIInt size; 316 PetscBool iscuda, iskokkos, iship; 317 318 PetscFunctionBegin; 319 if (!swarm->issetup) PetscCall(DMSetUp(dm)); 320 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL)); 321 PetscCall(DMSwarmGetField(dm, fieldname, &bs, &type, (void **)&array)); 322 PetscCheck(type == PETSC_REAL, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid for PETSC_REAL"); 323 324 PetscCallMPI(MPI_Comm_size(comm, &size)); 325 PetscCall(PetscStrcmp(dm->vectype, VECKOKKOS, &iskokkos)); 326 PetscCall(PetscStrcmp(dm->vectype, VECCUDA, &iscuda)); 327 PetscCall(PetscStrcmp(dm->vectype, VECHIP, &iship)); 328 PetscCall(VecCreate(comm, vec)); 329 PetscCall(VecSetSizes(*vec, n * bs, PETSC_DETERMINE)); 330 PetscCall(VecSetBlockSize(*vec, bs)); 331 if (iskokkos) PetscCall(VecSetType(*vec, VECKOKKOS)); 332 else if (iscuda) PetscCall(VecSetType(*vec, VECCUDA)); 333 else if (iship) PetscCall(VecSetType(*vec, VECHIP)); 334 else PetscCall(VecSetType(*vec, VECSTANDARD)); 335 PetscCall(VecPlaceArray(*vec, array)); 336 337 PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "DMSwarmSharedField_%s", fieldname)); 338 PetscCall(PetscObjectSetName((PetscObject)*vec, name)); 339 340 /* Set guard */ 341 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldname, &fid)); 342 PetscCall(PetscObjectComposedDataSetInt((PetscObject)*vec, SwarmDataFieldId, fid)); 343 344 PetscCall(VecSetDM(*vec, dm)); 345 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Swarm)); 346 PetscFunctionReturn(PETSC_SUCCESS); 347 } 348 349 static PetscErrorCode DMSwarmDestroyVectorFromFields_Private(DM sw, PetscInt Nf, const char *fieldnames[], Vec *vec) 350 { 351 DM_Swarm *swarm = (DM_Swarm *)sw->data; 352 const PetscScalar *array; 353 PetscInt bs, n, id = 0, cid = -2; 354 PetscBool flg; 355 356 PetscFunctionBegin; 357 for (PetscInt f = 0; f < Nf; ++f) { 358 PetscInt fid; 359 360 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldnames[f], &fid)); 361 id += fid; 362 } 363 PetscCall(PetscObjectComposedDataGetInt((PetscObject)*vec, SwarmDataFieldId, cid, flg)); 364 (void)flg; /* avoid compiler warning */ 365 PetscCheck(cid == id, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "Vector being destroyed was not created from DMSwarm field(%s)! %" PetscInt_FMT " != %" PetscInt_FMT, fieldnames[0], cid, id); 366 PetscCall(VecGetLocalSize(*vec, &n)); 367 PetscCall(VecGetBlockSize(*vec, &bs)); 368 n /= bs; 369 PetscCheck(n == swarm->db->L, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "DMSwarm sizes have changed since vector was created - cannot ensure pointers are valid"); 370 PetscCall(VecGetArrayRead(*vec, &array)); 371 for (PetscInt f = 0, off = 0; f < Nf; ++f) { 372 PetscScalar *farray; 373 PetscDataType ftype; 374 PetscInt fbs; 375 376 PetscCall(DMSwarmGetField(sw, fieldnames[f], &fbs, &ftype, (void **)&farray)); 377 PetscCheck(off + fbs <= bs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid blocksize %" PetscInt_FMT " < %" PetscInt_FMT, bs, off + fbs); 378 for (PetscInt i = 0; i < n; ++i) { 379 for (PetscInt b = 0; b < fbs; ++b) farray[i * fbs + b] = array[i * bs + off + b]; 380 } 381 off += fbs; 382 PetscCall(DMSwarmRestoreField(sw, fieldnames[f], &fbs, &ftype, (void **)&farray)); 383 } 384 PetscCall(VecRestoreArrayRead(*vec, &array)); 385 PetscCall(VecDestroy(vec)); 386 PetscFunctionReturn(PETSC_SUCCESS); 387 } 388 389 static PetscErrorCode DMSwarmCreateVectorFromFields_Private(DM sw, PetscInt Nf, const char *fieldnames[], MPI_Comm comm, Vec *vec) 390 { 391 DM_Swarm *swarm = (DM_Swarm *)sw->data; 392 PetscScalar *array; 393 PetscInt n, bs = 0, id = 0; 394 char name[PETSC_MAX_PATH_LEN]; 395 396 PetscFunctionBegin; 397 if (!swarm->issetup) PetscCall(DMSetUp(sw)); 398 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL)); 399 for (PetscInt f = 0; f < Nf; ++f) { 400 PetscDataType ftype; 401 PetscInt fbs; 402 403 PetscCall(DMSwarmGetFieldInfo(sw, fieldnames[f], &fbs, &ftype)); 404 PetscCheck(ftype == PETSC_REAL, PetscObjectComm((PetscObject)sw), PETSC_ERR_SUP, "Only valid for PETSC_REAL"); 405 bs += fbs; 406 } 407 408 PetscCall(VecCreate(comm, vec)); 409 PetscCall(VecSetSizes(*vec, n * bs, PETSC_DETERMINE)); 410 PetscCall(VecSetBlockSize(*vec, bs)); 411 PetscCall(VecSetType(*vec, sw->vectype)); 412 413 PetscCall(VecGetArrayWrite(*vec, &array)); 414 for (PetscInt f = 0, off = 0; f < Nf; ++f) { 415 PetscScalar *farray; 416 PetscDataType ftype; 417 PetscInt fbs; 418 419 PetscCall(DMSwarmGetField(sw, fieldnames[f], &fbs, &ftype, (void **)&farray)); 420 for (PetscInt i = 0; i < n; ++i) { 421 for (PetscInt b = 0; b < fbs; ++b) array[i * bs + off + b] = farray[i * fbs + b]; 422 } 423 off += fbs; 424 PetscCall(DMSwarmRestoreField(sw, fieldnames[f], &fbs, &ftype, (void **)&farray)); 425 } 426 PetscCall(VecRestoreArrayWrite(*vec, &array)); 427 428 PetscCall(PetscStrncpy(name, "DMSwarmField", PETSC_MAX_PATH_LEN)); 429 for (PetscInt f = 0; f < Nf; ++f) { 430 PetscCall(PetscStrlcat(name, "_", PETSC_MAX_PATH_LEN)); 431 PetscCall(PetscStrlcat(name, fieldnames[f], PETSC_MAX_PATH_LEN)); 432 } 433 PetscCall(PetscObjectSetName((PetscObject)*vec, name)); 434 435 for (PetscInt f = 0; f < Nf; ++f) { 436 PetscInt fid; 437 438 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldnames[f], &fid)); 439 id += fid; 440 } 441 PetscCall(PetscObjectComposedDataSetInt((PetscObject)*vec, SwarmDataFieldId, id)); 442 443 PetscCall(VecSetDM(*vec, sw)); 444 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Swarm)); 445 PetscFunctionReturn(PETSC_SUCCESS); 446 } 447 448 /* This creates a "mass matrix" between a finite element and particle space. If a finite element interpolant is given by 449 450 \hat f = \sum_i f_i \phi_i 451 452 and a particle function is given by 453 454 f = \sum_i w_i \delta(x - x_i) 455 456 then we want to require that 457 458 M \hat f = M_p f 459 460 where the particle mass matrix is given by 461 462 (M_p)_{ij} = \int \phi_i \delta(x - x_j) 463 464 The way Dave May does particles, they amount to quadratue weights rather than delta functions, so he has |J| is in 465 his integral. We allow this with the boolean flag. 466 */ 467 static PetscErrorCode DMSwarmComputeMassMatrix_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx) 468 { 469 const char *name = "Mass Matrix"; 470 MPI_Comm comm; 471 DMSwarmCellDM celldm; 472 PetscDS prob; 473 PetscSection fsection, globalFSection; 474 PetscHSetIJ ht; 475 PetscLayout rLayout, colLayout; 476 PetscInt *dnz, *onz; 477 PetscInt locRows, locCols, rStart, colStart, colEnd, *rowIDXs; 478 PetscReal *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0}; 479 PetscScalar *elemMat; 480 PetscInt dim, Nf, Nfc, cStart, cEnd, totDim, maxC = 0, totNc = 0; 481 const char **coordFields; 482 PetscReal **coordVals; 483 PetscInt *bs; 484 485 PetscFunctionBegin; 486 PetscCall(PetscObjectGetComm((PetscObject)mass, &comm)); 487 PetscCall(DMGetCoordinateDim(dmf, &dim)); 488 PetscCall(DMGetDS(dmf, &prob)); 489 PetscCall(PetscDSGetNumFields(prob, &Nf)); 490 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 491 PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 492 PetscCall(DMGetLocalSection(dmf, &fsection)); 493 PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 494 PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd)); 495 PetscCall(MatGetLocalSize(mass, &locRows, &locCols)); 496 497 PetscCall(DMSwarmGetCellDMActive(dmc, &celldm)); 498 PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields)); 499 PetscCall(PetscMalloc2(Nfc, &coordVals, Nfc, &bs)); 500 501 PetscCall(PetscLayoutCreate(comm, &colLayout)); 502 PetscCall(PetscLayoutSetLocalSize(colLayout, locCols)); 503 PetscCall(PetscLayoutSetBlockSize(colLayout, 1)); 504 PetscCall(PetscLayoutSetUp(colLayout)); 505 PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd)); 506 PetscCall(PetscLayoutDestroy(&colLayout)); 507 508 PetscCall(PetscLayoutCreate(comm, &rLayout)); 509 PetscCall(PetscLayoutSetLocalSize(rLayout, locRows)); 510 PetscCall(PetscLayoutSetBlockSize(rLayout, 1)); 511 PetscCall(PetscLayoutSetUp(rLayout)); 512 PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL)); 513 PetscCall(PetscLayoutDestroy(&rLayout)); 514 515 PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz)); 516 PetscCall(PetscHSetIJCreate(&ht)); 517 518 PetscCall(PetscSynchronizedFlush(comm, NULL)); 519 for (PetscInt field = 0; field < Nf; ++field) { 520 PetscObject obj; 521 PetscClassId id; 522 PetscInt Nc; 523 524 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 525 PetscCall(PetscObjectGetClassId(obj, &id)); 526 if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 527 else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 528 totNc += Nc; 529 } 530 /* count non-zeros */ 531 PetscCall(DMSwarmSortGetAccess(dmc)); 532 for (PetscInt field = 0; field < Nf; ++field) { 533 PetscObject obj; 534 PetscClassId id; 535 PetscInt Nc; 536 537 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 538 PetscCall(PetscObjectGetClassId(obj, &id)); 539 if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 540 else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 541 542 for (PetscInt cell = cStart; cell < cEnd; ++cell) { 543 PetscInt *findices, *cindices; /* fine is vertices, coarse is particles */ 544 PetscInt numFIndices, numCIndices; 545 546 PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 547 PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices)); 548 maxC = PetscMax(maxC, numCIndices); 549 { 550 PetscHashIJKey key; 551 PetscBool missing; 552 for (PetscInt i = 0; i < numFIndices; ++i) { 553 key.j = findices[i]; /* global column (from Plex) */ 554 if (key.j >= 0) { 555 /* Get indices for coarse elements */ 556 for (PetscInt j = 0; j < numCIndices; ++j) { 557 for (PetscInt c = 0; c < Nc; ++c) { 558 // TODO Need field offset on particle here 559 key.i = cindices[j] * totNc + c + rStart; /* global cols (from Swarm) */ 560 if (key.i < 0) continue; 561 PetscCall(PetscHSetIJQueryAdd(ht, key, &missing)); 562 if (missing) { 563 if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart]; 564 else ++onz[key.i - rStart]; 565 } else SETERRQ(PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Set new value at %" PetscInt_FMT ",%" PetscInt_FMT, key.i, key.j); 566 } 567 } 568 } 569 } 570 PetscCall(DMSwarmSortRestorePointsPerCell(dmc, cell, &numCIndices, &cindices)); 571 } 572 PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 573 } 574 } 575 PetscCall(PetscHSetIJDestroy(&ht)); 576 PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL)); 577 PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 578 PetscCall(PetscFree2(dnz, onz)); 579 PetscCall(PetscMalloc3(maxC * totNc * totDim, &elemMat, maxC * totNc, &rowIDXs, maxC * dim, &xi)); 580 for (PetscInt field = 0; field < Nf; ++field) { 581 PetscTabulation Tcoarse; 582 PetscObject obj; 583 PetscClassId id; 584 PetscInt Nc; 585 586 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 587 PetscCall(PetscObjectGetClassId(obj, &id)); 588 if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 589 else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 590 591 for (PetscInt i = 0; i < Nfc; ++i) PetscCall(DMSwarmGetField(dmc, coordFields[i], &bs[i], NULL, (void **)&coordVals[i])); 592 for (PetscInt cell = cStart; cell < cEnd; ++cell) { 593 PetscInt *findices, *cindices; 594 PetscInt numFIndices, numCIndices; 595 596 /* TODO: Use DMField instead of assuming affine */ 597 PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 598 PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 599 PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices)); 600 for (PetscInt j = 0; j < numCIndices; ++j) { 601 PetscReal xr[8]; 602 PetscInt off = 0; 603 604 for (PetscInt i = 0; i < Nfc; ++i) { 605 for (PetscInt b = 0; b < bs[i]; ++b, ++off) xr[off] = coordVals[i][cindices[j] * bs[i] + b]; 606 } 607 PetscCheck(off == dim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The total block size of coordinates is %" PetscInt_FMT " != %" PetscInt_FMT " the DM coordinate dimension", off, dim); 608 CoordinatesRealToRef(dim, dim, v0ref, v0, invJ, xr, &xi[j * dim]); 609 } 610 if (id == PETSCFE_CLASSID) PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse)); 611 else PetscCall(PetscFVCreateTabulation((PetscFV)obj, 1, numCIndices, xi, 0, &Tcoarse)); 612 /* Get elemMat entries by multiplying by weight */ 613 PetscCall(PetscArrayzero(elemMat, numCIndices * Nc * totDim)); 614 for (PetscInt i = 0; i < numFIndices / Nc; ++i) { 615 for (PetscInt j = 0; j < numCIndices; ++j) { 616 for (PetscInt c = 0; c < Nc; ++c) { 617 // TODO Need field offset on particle and field here 618 /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */ 619 elemMat[(j * totNc + c) * numFIndices + i * Nc + c] += Tcoarse->T[0][(j * numFIndices + i * Nc + c) * Nc + c] * (useDeltaFunction ? 1.0 : detJ); 620 } 621 } 622 } 623 for (PetscInt j = 0; j < numCIndices; ++j) 624 // TODO Need field offset on particle here 625 for (PetscInt c = 0; c < Nc; ++c) rowIDXs[j * Nc + c] = cindices[j] * totNc + c + rStart; 626 if (0) PetscCall(DMPrintCellMatrix(cell, name, numCIndices * Nc, numFIndices, elemMat)); 627 PetscCall(MatSetValues(mass, numCIndices * Nc, rowIDXs, numFIndices, findices, elemMat, ADD_VALUES)); 628 PetscCall(DMSwarmSortRestorePointsPerCell(dmc, cell, &numCIndices, &cindices)); 629 PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 630 PetscCall(PetscTabulationDestroy(&Tcoarse)); 631 } 632 for (PetscInt i = 0; i < Nfc; ++i) PetscCall(DMSwarmRestoreField(dmc, coordFields[i], &bs[i], NULL, (void **)&coordVals[i])); 633 } 634 PetscCall(PetscFree3(elemMat, rowIDXs, xi)); 635 PetscCall(DMSwarmSortRestoreAccess(dmc)); 636 PetscCall(PetscFree3(v0, J, invJ)); 637 PetscCall(PetscFree2(coordVals, bs)); 638 PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY)); 639 PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY)); 640 PetscFunctionReturn(PETSC_SUCCESS); 641 } 642 643 /* Returns empty matrix for use with SNES FD */ 644 static PetscErrorCode DMCreateMatrix_Swarm(DM sw, Mat *m) 645 { 646 Vec field; 647 PetscInt size; 648 649 PetscFunctionBegin; 650 PetscCall(DMGetGlobalVector(sw, &field)); 651 PetscCall(VecGetLocalSize(field, &size)); 652 PetscCall(DMRestoreGlobalVector(sw, &field)); 653 PetscCall(MatCreate(PETSC_COMM_WORLD, m)); 654 PetscCall(MatSetFromOptions(*m)); 655 PetscCall(MatSetSizes(*m, PETSC_DECIDE, PETSC_DECIDE, size, size)); 656 PetscCall(MatSeqAIJSetPreallocation(*m, 1, NULL)); 657 PetscCall(MatZeroEntries(*m)); 658 PetscCall(MatAssemblyBegin(*m, MAT_FINAL_ASSEMBLY)); 659 PetscCall(MatAssemblyEnd(*m, MAT_FINAL_ASSEMBLY)); 660 PetscCall(MatShift(*m, 1.0)); 661 PetscCall(MatSetDM(*m, sw)); 662 PetscFunctionReturn(PETSC_SUCCESS); 663 } 664 665 /* FEM cols, Particle rows */ 666 static PetscErrorCode DMCreateMassMatrix_Swarm(DM dmCoarse, DM dmFine, Mat *mass) 667 { 668 DMSwarmCellDM celldm; 669 PetscSection gsf; 670 PetscInt m, n, Np, bs; 671 void *ctx; 672 673 PetscFunctionBegin; 674 PetscCall(DMSwarmGetCellDMActive(dmCoarse, &celldm)); 675 PetscCheck(celldm->Nf, PetscObjectComm((PetscObject)dmCoarse), PETSC_ERR_USER, "Active cell DM does not define any fields"); 676 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 677 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 678 PetscCall(DMSwarmGetLocalSize(dmCoarse, &Np)); 679 PetscCall(DMSwarmCellDMGetBlockSize(celldm, dmCoarse, &bs)); 680 n = Np * bs; 681 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 682 PetscCall(MatSetSizes(*mass, n, m, PETSC_DETERMINE, PETSC_DETERMINE)); 683 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 684 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 685 686 PetscCall(DMSwarmComputeMassMatrix_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx)); 687 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 688 PetscFunctionReturn(PETSC_SUCCESS); 689 } 690 691 static PetscErrorCode DMSwarmComputeMassMatrixSquare_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx) 692 { 693 const char *name = "Mass Matrix Square"; 694 MPI_Comm comm; 695 DMSwarmCellDM celldm; 696 PetscDS prob; 697 PetscSection fsection, globalFSection; 698 PetscHSetIJ ht; 699 PetscLayout rLayout, colLayout; 700 PetscInt *dnz, *onz, *adj, depth, maxConeSize, maxSupportSize, maxAdjSize; 701 PetscInt locRows, locCols, rStart, colStart, colEnd, *rowIDXs; 702 PetscReal *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0}; 703 PetscScalar *elemMat, *elemMatSq; 704 PetscInt cdim, Nf, Nfc, cStart, cEnd, totDim, maxC = 0; 705 const char **coordFields; 706 PetscReal **coordVals; 707 PetscInt *bs; 708 709 PetscFunctionBegin; 710 PetscCall(PetscObjectGetComm((PetscObject)mass, &comm)); 711 PetscCall(DMGetCoordinateDim(dmf, &cdim)); 712 PetscCall(DMGetDS(dmf, &prob)); 713 PetscCall(PetscDSGetNumFields(prob, &Nf)); 714 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 715 PetscCall(PetscMalloc3(cdim, &v0, cdim * cdim, &J, cdim * cdim, &invJ)); 716 PetscCall(DMGetLocalSection(dmf, &fsection)); 717 PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 718 PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd)); 719 PetscCall(MatGetLocalSize(mass, &locRows, &locCols)); 720 721 PetscCall(DMSwarmGetCellDMActive(dmc, &celldm)); 722 PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields)); 723 PetscCall(PetscMalloc2(Nfc, &coordVals, Nfc, &bs)); 724 725 PetscCall(PetscLayoutCreate(comm, &colLayout)); 726 PetscCall(PetscLayoutSetLocalSize(colLayout, locCols)); 727 PetscCall(PetscLayoutSetBlockSize(colLayout, 1)); 728 PetscCall(PetscLayoutSetUp(colLayout)); 729 PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd)); 730 PetscCall(PetscLayoutDestroy(&colLayout)); 731 732 PetscCall(PetscLayoutCreate(comm, &rLayout)); 733 PetscCall(PetscLayoutSetLocalSize(rLayout, locRows)); 734 PetscCall(PetscLayoutSetBlockSize(rLayout, 1)); 735 PetscCall(PetscLayoutSetUp(rLayout)); 736 PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL)); 737 PetscCall(PetscLayoutDestroy(&rLayout)); 738 739 PetscCall(DMPlexGetDepth(dmf, &depth)); 740 PetscCall(DMPlexGetMaxSizes(dmf, &maxConeSize, &maxSupportSize)); 741 maxAdjSize = PetscPowInt(maxConeSize * maxSupportSize, depth); 742 PetscCall(PetscMalloc1(maxAdjSize, &adj)); 743 744 PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz)); 745 PetscCall(PetscHSetIJCreate(&ht)); 746 /* Count nonzeros 747 This is just FVM++, but we cannot use the Plex P0 allocation since unknowns in a cell will not be contiguous 748 */ 749 PetscCall(DMSwarmSortGetAccess(dmc)); 750 for (PetscInt cell = cStart; cell < cEnd; ++cell) { 751 PetscInt *cindices; 752 PetscInt numCIndices; 753 #if 0 754 PetscInt adjSize = maxAdjSize, a, j; 755 #endif 756 757 PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices)); 758 maxC = PetscMax(maxC, numCIndices); 759 /* Diagonal block */ 760 for (PetscInt i = 0; i < numCIndices; ++i) dnz[cindices[i]] += numCIndices; 761 #if 0 762 /* Off-diagonal blocks */ 763 PetscCall(DMPlexGetAdjacency(dmf, cell, &adjSize, &adj)); 764 for (a = 0; a < adjSize; ++a) { 765 if (adj[a] >= cStart && adj[a] < cEnd && adj[a] != cell) { 766 const PetscInt ncell = adj[a]; 767 PetscInt *ncindices; 768 PetscInt numNCIndices; 769 770 PetscCall(DMSwarmSortGetPointsPerCell(dmc, ncell, &numNCIndices, &ncindices)); 771 { 772 PetscHashIJKey key; 773 PetscBool missing; 774 775 for (i = 0; i < numCIndices; ++i) { 776 key.i = cindices[i] + rStart; /* global rows (from Swarm) */ 777 if (key.i < 0) continue; 778 for (j = 0; j < numNCIndices; ++j) { 779 key.j = ncindices[j] + rStart; /* global column (from Swarm) */ 780 if (key.j < 0) continue; 781 PetscCall(PetscHSetIJQueryAdd(ht, key, &missing)); 782 if (missing) { 783 if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart]; 784 else ++onz[key.i - rStart]; 785 } 786 } 787 } 788 } 789 PetscCall(DMSwarmSortRestorePointsPerCell(dmc, ncell, &numNCIndices, &ncindices)); 790 } 791 } 792 #endif 793 PetscCall(DMSwarmSortRestorePointsPerCell(dmc, cell, &numCIndices, &cindices)); 794 } 795 PetscCall(PetscHSetIJDestroy(&ht)); 796 PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL)); 797 PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 798 PetscCall(PetscFree2(dnz, onz)); 799 PetscCall(PetscMalloc4(maxC * totDim, &elemMat, maxC * maxC, &elemMatSq, maxC, &rowIDXs, maxC * cdim, &xi)); 800 /* Fill in values 801 Each entry is a sum of terms \phi_i(x_p) \phi_i(x_q) 802 Start just by producing block diagonal 803 Could loop over adjacent cells 804 Produce neighboring element matrix 805 TODO Determine which columns and rows correspond to shared dual vector 806 Do MatMatMult with rectangular matrices 807 Insert block 808 */ 809 for (PetscInt field = 0; field < Nf; ++field) { 810 PetscTabulation Tcoarse; 811 PetscObject obj; 812 PetscInt Nc; 813 814 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 815 PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 816 PetscCheck(Nc == 1, PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Can only interpolate a scalar field from particles, Nc = %" PetscInt_FMT, Nc); 817 for (PetscInt i = 0; i < Nfc; ++i) PetscCall(DMSwarmGetField(dmc, coordFields[i], &bs[i], NULL, (void **)&coordVals[i])); 818 for (PetscInt cell = cStart; cell < cEnd; ++cell) { 819 PetscInt *findices, *cindices; 820 PetscInt numFIndices, numCIndices; 821 822 /* TODO: Use DMField instead of assuming affine */ 823 PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 824 PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 825 PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices)); 826 for (PetscInt p = 0; p < numCIndices; ++p) { 827 PetscReal xr[8]; 828 PetscInt off = 0; 829 830 for (PetscInt i = 0; i < Nfc; ++i) { 831 for (PetscInt b = 0; b < bs[i]; ++b, ++off) xr[off] = coordVals[i][cindices[p] * bs[i] + b]; 832 } 833 PetscCheck(off == cdim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The total block size of coordinates is %" PetscInt_FMT " != %" PetscInt_FMT " the DM coordinate dimension", off, cdim); 834 CoordinatesRealToRef(cdim, cdim, v0ref, v0, invJ, xr, &xi[p * cdim]); 835 } 836 PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse)); 837 /* Get elemMat entries by multiplying by weight */ 838 PetscCall(PetscArrayzero(elemMat, numCIndices * totDim)); 839 for (PetscInt i = 0; i < numFIndices; ++i) { 840 for (PetscInt p = 0; p < numCIndices; ++p) { 841 for (PetscInt c = 0; c < Nc; ++c) { 842 /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */ 843 elemMat[p * numFIndices + i] += Tcoarse->T[0][(p * numFIndices + i) * Nc + c] * (useDeltaFunction ? 1.0 : detJ); 844 } 845 } 846 } 847 PetscCall(PetscTabulationDestroy(&Tcoarse)); 848 for (PetscInt p = 0; p < numCIndices; ++p) rowIDXs[p] = cindices[p] + rStart; 849 if (0) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 850 /* Block diagonal */ 851 if (numCIndices) { 852 PetscBLASInt blasn, blask; 853 PetscScalar one = 1.0, zero = 0.0; 854 855 PetscCall(PetscBLASIntCast(numCIndices, &blasn)); 856 PetscCall(PetscBLASIntCast(numFIndices, &blask)); 857 PetscCallBLAS("BLASgemm", BLASgemm_("T", "N", &blasn, &blasn, &blask, &one, elemMat, &blask, elemMat, &blask, &zero, elemMatSq, &blasn)); 858 } 859 PetscCall(MatSetValues(mass, numCIndices, rowIDXs, numCIndices, rowIDXs, elemMatSq, ADD_VALUES)); 860 /* TODO off-diagonal */ 861 PetscCall(DMSwarmSortRestorePointsPerCell(dmc, cell, &numCIndices, &cindices)); 862 PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 863 } 864 for (PetscInt i = 0; i < Nfc; ++i) PetscCall(DMSwarmRestoreField(dmc, coordFields[i], &bs[i], NULL, (void **)&coordVals[i])); 865 } 866 PetscCall(PetscFree4(elemMat, elemMatSq, rowIDXs, xi)); 867 PetscCall(PetscFree(adj)); 868 PetscCall(DMSwarmSortRestoreAccess(dmc)); 869 PetscCall(PetscFree3(v0, J, invJ)); 870 PetscCall(PetscFree2(coordVals, bs)); 871 PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY)); 872 PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY)); 873 PetscFunctionReturn(PETSC_SUCCESS); 874 } 875 876 /*@ 877 DMSwarmCreateMassMatrixSquare - Creates the block-diagonal of the square, M^T_p M_p, of the particle mass matrix M_p 878 879 Collective 880 881 Input Parameters: 882 + dmCoarse - a `DMSWARM` 883 - dmFine - a `DMPLEX` 884 885 Output Parameter: 886 . mass - the square of the particle mass matrix 887 888 Level: advanced 889 890 Note: 891 We only compute the block diagonal since this provides a good preconditioner and is completely local. It would be possible in the 892 future to compute the full normal equations. 893 894 .seealso: `DM`, `DMSWARM`, `DMCreateMassMatrix()` 895 @*/ 896 PetscErrorCode DMSwarmCreateMassMatrixSquare(DM dmCoarse, DM dmFine, Mat *mass) 897 { 898 PetscInt n; 899 void *ctx; 900 901 PetscFunctionBegin; 902 PetscCall(DMSwarmGetLocalSize(dmCoarse, &n)); 903 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 904 PetscCall(MatSetSizes(*mass, n, n, PETSC_DETERMINE, PETSC_DETERMINE)); 905 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 906 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 907 908 PetscCall(DMSwarmComputeMassMatrixSquare_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx)); 909 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_sq_mat_view")); 910 PetscFunctionReturn(PETSC_SUCCESS); 911 } 912 913 /*@ 914 DMSwarmCreateGlobalVectorFromField - Creates a `Vec` object sharing the array associated with a given field 915 916 Collective 917 918 Input Parameters: 919 + dm - a `DMSWARM` 920 - fieldname - the textual name given to a registered field 921 922 Output Parameter: 923 . vec - the vector 924 925 Level: beginner 926 927 Note: 928 The vector must be returned using a matching call to `DMSwarmDestroyGlobalVectorFromField()`. 929 930 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyGlobalVectorFromField()` 931 @*/ 932 PetscErrorCode DMSwarmCreateGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec) 933 { 934 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 935 936 PetscFunctionBegin; 937 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 938 PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec)); 939 PetscFunctionReturn(PETSC_SUCCESS); 940 } 941 942 /*@ 943 DMSwarmDestroyGlobalVectorFromField - Destroys the `Vec` object which share the array associated with a given field 944 945 Collective 946 947 Input Parameters: 948 + dm - a `DMSWARM` 949 - fieldname - the textual name given to a registered field 950 951 Output Parameter: 952 . vec - the vector 953 954 Level: beginner 955 956 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateGlobalVectorFromField()` 957 @*/ 958 PetscErrorCode DMSwarmDestroyGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec) 959 { 960 PetscFunctionBegin; 961 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 962 PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec)); 963 PetscFunctionReturn(PETSC_SUCCESS); 964 } 965 966 /*@ 967 DMSwarmCreateLocalVectorFromField - Creates a `Vec` object sharing the array associated with a given field 968 969 Collective 970 971 Input Parameters: 972 + dm - a `DMSWARM` 973 - fieldname - the textual name given to a registered field 974 975 Output Parameter: 976 . vec - the vector 977 978 Level: beginner 979 980 Note: 981 The vector must be returned using a matching call to DMSwarmDestroyLocalVectorFromField(). 982 983 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyLocalVectorFromField()` 984 @*/ 985 PetscErrorCode DMSwarmCreateLocalVectorFromField(DM dm, const char fieldname[], Vec *vec) 986 { 987 MPI_Comm comm = PETSC_COMM_SELF; 988 989 PetscFunctionBegin; 990 PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec)); 991 PetscFunctionReturn(PETSC_SUCCESS); 992 } 993 994 /*@ 995 DMSwarmDestroyLocalVectorFromField - Destroys the `Vec` object which share the array associated with a given field 996 997 Collective 998 999 Input Parameters: 1000 + dm - a `DMSWARM` 1001 - fieldname - the textual name given to a registered field 1002 1003 Output Parameter: 1004 . vec - the vector 1005 1006 Level: beginner 1007 1008 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateLocalVectorFromField()` 1009 @*/ 1010 PetscErrorCode DMSwarmDestroyLocalVectorFromField(DM dm, const char fieldname[], Vec *vec) 1011 { 1012 PetscFunctionBegin; 1013 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 1014 PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec)); 1015 PetscFunctionReturn(PETSC_SUCCESS); 1016 } 1017 1018 /*@ 1019 DMSwarmCreateGlobalVectorFromFields - Creates a `Vec` object sharing the array associated with a given field set 1020 1021 Collective 1022 1023 Input Parameters: 1024 + dm - a `DMSWARM` 1025 . Nf - the number of fields 1026 - fieldnames - the textual names given to the registered fields 1027 1028 Output Parameter: 1029 . vec - the vector 1030 1031 Level: beginner 1032 1033 Notes: 1034 The vector must be returned using a matching call to `DMSwarmDestroyGlobalVectorFromFields()`. 1035 1036 This vector is copyin-copyout, rather than a direct pointer like `DMSwarmCreateGlobalVectorFromField()` 1037 1038 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyGlobalVectorFromFields()` 1039 @*/ 1040 PetscErrorCode DMSwarmCreateGlobalVectorFromFields(DM dm, PetscInt Nf, const char *fieldnames[], Vec *vec) 1041 { 1042 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 1043 1044 PetscFunctionBegin; 1045 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 1046 PetscCall(DMSwarmCreateVectorFromFields_Private(dm, Nf, fieldnames, comm, vec)); 1047 PetscFunctionReturn(PETSC_SUCCESS); 1048 } 1049 1050 /*@ 1051 DMSwarmDestroyGlobalVectorFromFields - Destroys the `Vec` object which share the array associated with a given field set 1052 1053 Collective 1054 1055 Input Parameters: 1056 + dm - a `DMSWARM` 1057 . Nf - the number of fields 1058 - fieldnames - the textual names given to the registered fields 1059 1060 Output Parameter: 1061 . vec - the vector 1062 1063 Level: beginner 1064 1065 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateGlobalVectorFromField()` 1066 @*/ 1067 PetscErrorCode DMSwarmDestroyGlobalVectorFromFields(DM dm, PetscInt Nf, const char *fieldnames[], Vec *vec) 1068 { 1069 PetscFunctionBegin; 1070 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 1071 PetscCall(DMSwarmDestroyVectorFromFields_Private(dm, Nf, fieldnames, vec)); 1072 PetscFunctionReturn(PETSC_SUCCESS); 1073 } 1074 1075 /*@ 1076 DMSwarmCreateLocalVectorFromFields - Creates a `Vec` object sharing the array associated with a given field set 1077 1078 Collective 1079 1080 Input Parameters: 1081 + dm - a `DMSWARM` 1082 . Nf - the number of fields 1083 - fieldnames - the textual names given to the registered fields 1084 1085 Output Parameter: 1086 . vec - the vector 1087 1088 Level: beginner 1089 1090 Notes: 1091 The vector must be returned using a matching call to DMSwarmDestroyLocalVectorFromField(). 1092 1093 This vector is copyin-copyout, rather than a direct pointer like `DMSwarmCreateLocalVectorFromField()` 1094 1095 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyLocalVectorFromField()` 1096 @*/ 1097 PetscErrorCode DMSwarmCreateLocalVectorFromFields(DM dm, PetscInt Nf, const char *fieldnames[], Vec *vec) 1098 { 1099 MPI_Comm comm = PETSC_COMM_SELF; 1100 1101 PetscFunctionBegin; 1102 PetscCall(DMSwarmCreateVectorFromFields_Private(dm, Nf, fieldnames, comm, vec)); 1103 PetscFunctionReturn(PETSC_SUCCESS); 1104 } 1105 1106 /*@ 1107 DMSwarmDestroyLocalVectorFromFields - Destroys the `Vec` object which share the array associated with a given field set 1108 1109 Collective 1110 1111 Input Parameters: 1112 + dm - a `DMSWARM` 1113 . Nf - the number of fields 1114 - fieldnames - the textual names given to the registered fields 1115 1116 Output Parameter: 1117 . vec - the vector 1118 1119 Level: beginner 1120 1121 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateLocalVectorFromFields()` 1122 @*/ 1123 PetscErrorCode DMSwarmDestroyLocalVectorFromFields(DM dm, PetscInt Nf, const char *fieldnames[], Vec *vec) 1124 { 1125 PetscFunctionBegin; 1126 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 1127 PetscCall(DMSwarmDestroyVectorFromFields_Private(dm, Nf, fieldnames, vec)); 1128 PetscFunctionReturn(PETSC_SUCCESS); 1129 } 1130 1131 /*@ 1132 DMSwarmInitializeFieldRegister - Initiates the registration of fields to a `DMSWARM` 1133 1134 Collective 1135 1136 Input Parameter: 1137 . dm - a `DMSWARM` 1138 1139 Level: beginner 1140 1141 Note: 1142 After all fields have been registered, you must call `DMSwarmFinalizeFieldRegister()`. 1143 1144 .seealso: `DM`, `DMSWARM`, `DMSwarmFinalizeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`, 1145 `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()` 1146 @*/ 1147 PetscErrorCode DMSwarmInitializeFieldRegister(DM dm) 1148 { 1149 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1150 1151 PetscFunctionBegin; 1152 if (!swarm->field_registration_initialized) { 1153 swarm->field_registration_initialized = PETSC_TRUE; 1154 PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_pid, 1, PETSC_INT64)); /* unique identifier */ 1155 PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_rank, 1, PETSC_INT)); /* used for communication */ 1156 } 1157 PetscFunctionReturn(PETSC_SUCCESS); 1158 } 1159 1160 /*@ 1161 DMSwarmFinalizeFieldRegister - Finalizes the registration of fields to a `DMSWARM` 1162 1163 Collective 1164 1165 Input Parameter: 1166 . dm - a `DMSWARM` 1167 1168 Level: beginner 1169 1170 Note: 1171 After `DMSwarmFinalizeFieldRegister()` has been called, no new fields can be defined on the `DMSWARM`. 1172 1173 .seealso: `DM`, `DMSWARM`, `DMSwarmInitializeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`, 1174 `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()` 1175 @*/ 1176 PetscErrorCode DMSwarmFinalizeFieldRegister(DM dm) 1177 { 1178 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1179 1180 PetscFunctionBegin; 1181 if (!swarm->field_registration_finalized) PetscCall(DMSwarmDataBucketFinalize(swarm->db)); 1182 swarm->field_registration_finalized = PETSC_TRUE; 1183 PetscFunctionReturn(PETSC_SUCCESS); 1184 } 1185 1186 /*@ 1187 DMSwarmSetLocalSizes - Sets the length of all registered fields on the `DMSWARM` 1188 1189 Not Collective 1190 1191 Input Parameters: 1192 + sw - a `DMSWARM` 1193 . nlocal - the length of each registered field 1194 - buffer - the length of the buffer used to efficient dynamic re-sizing 1195 1196 Level: beginner 1197 1198 .seealso: `DM`, `DMSWARM`, `DMSwarmGetLocalSize()` 1199 @*/ 1200 PetscErrorCode DMSwarmSetLocalSizes(DM sw, PetscInt nlocal, PetscInt buffer) 1201 { 1202 DM_Swarm *swarm = (DM_Swarm *)sw->data; 1203 PetscMPIInt rank; 1204 PetscInt *rankval; 1205 1206 PetscFunctionBegin; 1207 PetscCall(PetscLogEventBegin(DMSWARM_SetSizes, 0, 0, 0, 0)); 1208 PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, buffer)); 1209 PetscCall(PetscLogEventEnd(DMSWARM_SetSizes, 0, 0, 0, 0)); 1210 1211 // Initialize values in pid and rank placeholders 1212 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)sw), &rank)); 1213 PetscCall(DMSwarmGetField(sw, DMSwarmField_rank, NULL, NULL, (void **)&rankval)); 1214 for (PetscInt p = 0; p < nlocal; p++) rankval[p] = rank; 1215 PetscCall(DMSwarmRestoreField(sw, DMSwarmField_rank, NULL, NULL, (void **)&rankval)); 1216 /* TODO: [pid - use MPI_Scan] */ 1217 PetscFunctionReturn(PETSC_SUCCESS); 1218 } 1219 1220 /*@ 1221 DMSwarmSetCellDM - Attaches a `DM` to a `DMSWARM` 1222 1223 Collective 1224 1225 Input Parameters: 1226 + sw - a `DMSWARM` 1227 - dm - the `DM` to attach to the `DMSWARM` 1228 1229 Level: beginner 1230 1231 Note: 1232 The attached `DM` (dm) will be queried for point location and 1233 neighbor MPI-rank information if `DMSwarmMigrate()` is called. 1234 1235 .seealso: `DM`, `DMSWARM`, `DMSwarmSetType()`, `DMSwarmGetCellDM()`, `DMSwarmMigrate()` 1236 @*/ 1237 PetscErrorCode DMSwarmSetCellDM(DM sw, DM dm) 1238 { 1239 DMSwarmCellDM celldm; 1240 const char *name; 1241 char *coordName; 1242 1243 PetscFunctionBegin; 1244 PetscValidHeaderSpecific(sw, DM_CLASSID, 1); 1245 PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1246 PetscCall(PetscStrallocpy(DMSwarmPICField_coor, &coordName)); 1247 PetscCall(DMSwarmCellDMCreate(dm, 0, NULL, 1, (const char **)&coordName, &celldm)); 1248 PetscCall(PetscFree(coordName)); 1249 PetscCall(PetscObjectGetName((PetscObject)celldm, &name)); 1250 PetscCall(DMSwarmAddCellDM(sw, celldm)); 1251 PetscCall(DMSwarmCellDMDestroy(&celldm)); 1252 PetscCall(DMSwarmSetCellDMActive(sw, name)); 1253 PetscFunctionReturn(PETSC_SUCCESS); 1254 } 1255 1256 /*@ 1257 DMSwarmGetCellDM - Fetches the active cell `DM` 1258 1259 Collective 1260 1261 Input Parameter: 1262 . sw - a `DMSWARM` 1263 1264 Output Parameter: 1265 . dm - the active `DM` for the `DMSWARM` 1266 1267 Level: beginner 1268 1269 .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()` 1270 @*/ 1271 PetscErrorCode DMSwarmGetCellDM(DM sw, DM *dm) 1272 { 1273 DM_Swarm *swarm = (DM_Swarm *)sw->data; 1274 DMSwarmCellDM celldm; 1275 1276 PetscFunctionBegin; 1277 PetscValidHeaderSpecific(sw, DM_CLASSID, 1); 1278 PetscCall(PetscObjectListFind(swarm->cellDMs, swarm->activeCellDM, (PetscObject *)&celldm)); 1279 PetscCheck(celldm, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONG, "There is no cell DM named %s in this Swarm", swarm->activeCellDM); 1280 PetscCall(DMSwarmCellDMGetDM(celldm, dm)); 1281 PetscFunctionReturn(PETSC_SUCCESS); 1282 } 1283 1284 /*@C 1285 DMSwarmGetCellDMNames - Get the list of cell `DM` names 1286 1287 Not collective 1288 1289 Input Parameter: 1290 . sw - a `DMSWARM` 1291 1292 Output Parameters: 1293 + Ndm - the number of `DMSwarmCellDM` in the `DMSWARM` 1294 - celldms - the name of each `DMSwarmCellDM` 1295 1296 Level: beginner 1297 1298 .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()`, `DMSwarmGetCellDMByName()` 1299 @*/ 1300 PetscErrorCode DMSwarmGetCellDMNames(DM sw, PetscInt *Ndm, const char **celldms[]) 1301 { 1302 DM_Swarm *swarm = (DM_Swarm *)sw->data; 1303 PetscObjectList next = swarm->cellDMs; 1304 PetscInt n = 0; 1305 1306 PetscFunctionBegin; 1307 PetscValidHeaderSpecific(sw, DM_CLASSID, 1); 1308 PetscAssertPointer(Ndm, 2); 1309 PetscAssertPointer(celldms, 3); 1310 while (next) { 1311 next = next->next; 1312 ++n; 1313 } 1314 PetscCall(PetscMalloc1(n, celldms)); 1315 next = swarm->cellDMs; 1316 n = 0; 1317 while (next) { 1318 (*celldms)[n] = (const char *)next->obj->name; 1319 next = next->next; 1320 ++n; 1321 } 1322 *Ndm = n; 1323 PetscFunctionReturn(PETSC_SUCCESS); 1324 } 1325 1326 /*@ 1327 DMSwarmSetCellDMActive - Activates a cell `DM` for a `DMSWARM` 1328 1329 Collective 1330 1331 Input Parameters: 1332 + sw - a `DMSWARM` 1333 - name - name of the cell `DM` to active for the `DMSWARM` 1334 1335 Level: beginner 1336 1337 Note: 1338 The attached `DM` (dmcell) will be queried for point location and 1339 neighbor MPI-rank information if `DMSwarmMigrate()` is called. 1340 1341 .seealso: `DM`, `DMSWARM`, `DMSwarmCellDM`, `DMSwarmSetType()`, `DMSwarmAddCellDM()`, `DMSwarmSetCellDM()`, `DMSwarmMigrate()` 1342 @*/ 1343 PetscErrorCode DMSwarmSetCellDMActive(DM sw, const char name[]) 1344 { 1345 DM_Swarm *swarm = (DM_Swarm *)sw->data; 1346 DMSwarmCellDM celldm; 1347 1348 PetscFunctionBegin; 1349 PetscValidHeaderSpecific(sw, DM_CLASSID, 1); 1350 PetscCall(PetscInfo(sw, "Setting cell DM to %s\n", name)); 1351 PetscCall(PetscFree(swarm->activeCellDM)); 1352 PetscCall(PetscStrallocpy(name, (char **)&swarm->activeCellDM)); 1353 PetscCall(DMSwarmGetCellDMActive(sw, &celldm)); 1354 PetscFunctionReturn(PETSC_SUCCESS); 1355 } 1356 1357 /*@ 1358 DMSwarmGetCellDMActive - Returns the active cell `DM` for a `DMSWARM` 1359 1360 Collective 1361 1362 Input Parameter: 1363 . sw - a `DMSWARM` 1364 1365 Output Parameter: 1366 . celldm - the active `DMSwarmCellDM` 1367 1368 Level: beginner 1369 1370 .seealso: `DM`, `DMSWARM`, `DMSwarmCellDM`, `DMSwarmSetType()`, `DMSwarmAddCellDM()`, `DMSwarmSetCellDM()`, `DMSwarmMigrate()` 1371 @*/ 1372 PetscErrorCode DMSwarmGetCellDMActive(DM sw, DMSwarmCellDM *celldm) 1373 { 1374 DM_Swarm *swarm = (DM_Swarm *)sw->data; 1375 1376 PetscFunctionBegin; 1377 PetscValidHeaderSpecific(sw, DM_CLASSID, 1); 1378 PetscAssertPointer(celldm, 2); 1379 PetscCheck(swarm->activeCellDM, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONGSTATE, "Swarm has no active cell DM"); 1380 PetscCall(PetscObjectListFind(swarm->cellDMs, swarm->activeCellDM, (PetscObject *)celldm)); 1381 PetscCheck(*celldm, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONGSTATE, "Swarm has no valid cell DM for %s", swarm->activeCellDM); 1382 PetscFunctionReturn(PETSC_SUCCESS); 1383 } 1384 1385 /*@C 1386 DMSwarmGetCellDMByName - Get a `DMSwarmCellDM` from its name 1387 1388 Not collective 1389 1390 Input Parameters: 1391 + sw - a `DMSWARM` 1392 - name - the name 1393 1394 Output Parameter: 1395 . celldm - the `DMSwarmCellDM` 1396 1397 Level: beginner 1398 1399 .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()`, `DMSwarmGetCellDMNames()` 1400 @*/ 1401 PetscErrorCode DMSwarmGetCellDMByName(DM sw, const char name[], DMSwarmCellDM *celldm) 1402 { 1403 DM_Swarm *swarm = (DM_Swarm *)sw->data; 1404 1405 PetscFunctionBegin; 1406 PetscValidHeaderSpecific(sw, DM_CLASSID, 1); 1407 PetscAssertPointer(name, 2); 1408 PetscAssertPointer(celldm, 3); 1409 PetscCall(PetscObjectListFind(swarm->cellDMs, name, (PetscObject *)celldm)); 1410 PetscCheck(*celldm, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONGSTATE, "Swarm has no valid cell DM for %s", name); 1411 PetscFunctionReturn(PETSC_SUCCESS); 1412 } 1413 1414 /*@ 1415 DMSwarmAddCellDM - Adds a cell `DM` to the `DMSWARM` 1416 1417 Collective 1418 1419 Input Parameters: 1420 + sw - a `DMSWARM` 1421 - celldm - the `DMSwarmCellDM` 1422 1423 Level: beginner 1424 1425 Note: 1426 Cell DMs with the same name will share the cellid field 1427 1428 .seealso: `DM`, `DMSWARM`, `DMSwarmSetType()`, `DMSwarmPushCellDM()`, `DMSwarmSetCellDM()`, `DMSwarmMigrate()` 1429 @*/ 1430 PetscErrorCode DMSwarmAddCellDM(DM sw, DMSwarmCellDM celldm) 1431 { 1432 DM_Swarm *swarm = (DM_Swarm *)sw->data; 1433 const char *name; 1434 PetscInt dim; 1435 PetscBool flg; 1436 MPI_Comm comm; 1437 1438 PetscFunctionBegin; 1439 PetscValidHeaderSpecific(sw, DM_CLASSID, 1); 1440 PetscCall(PetscObjectGetComm((PetscObject)sw, &comm)); 1441 PetscValidHeaderSpecific(celldm, DMSWARMCELLDM_CLASSID, 2); 1442 PetscCall(PetscObjectGetName((PetscObject)celldm, &name)); 1443 PetscCall(PetscObjectListAdd(&swarm->cellDMs, name, (PetscObject)celldm)); 1444 PetscCall(DMGetDimension(sw, &dim)); 1445 for (PetscInt f = 0; f < celldm->Nfc; ++f) { 1446 PetscCall(DMSwarmDataFieldStringInList(celldm->coordFields[f], swarm->db->nfields, (const DMSwarmDataField *)swarm->db->field, &flg)); 1447 if (!flg) { 1448 PetscCall(DMSwarmRegisterPetscDatatypeField(sw, celldm->coordFields[f], dim, PETSC_DOUBLE)); 1449 } else { 1450 PetscDataType dt; 1451 PetscInt bs; 1452 1453 PetscCall(DMSwarmGetFieldInfo(sw, celldm->coordFields[f], &bs, &dt)); 1454 PetscCheck(bs == dim, comm, PETSC_ERR_ARG_WRONG, "Coordinate field %s has blocksize %" PetscInt_FMT " != %" PetscInt_FMT " spatial dimension", celldm->coordFields[f], bs, dim); 1455 PetscCheck(dt == PETSC_DOUBLE, comm, PETSC_ERR_ARG_WRONG, "Coordinate field %s has datatype %s != PETSC_DOUBLE", celldm->coordFields[f], PetscDataTypes[dt]); 1456 } 1457 } 1458 // Assume that DMs with the same name share the cellid field 1459 PetscCall(DMSwarmDataFieldStringInList(celldm->cellid, swarm->db->nfields, (const DMSwarmDataField *)swarm->db->field, &flg)); 1460 if (!flg) { 1461 PetscBool isShell, isDummy; 1462 const char *name; 1463 1464 // Allow dummy DMSHELL (I don't think we should support this mode) 1465 PetscCall(PetscObjectTypeCompare((PetscObject)celldm->dm, DMSHELL, &isShell)); 1466 PetscCall(PetscObjectGetName((PetscObject)celldm->dm, &name)); 1467 PetscCall(PetscStrcmp(name, "dummy", &isDummy)); 1468 if (!isShell || !isDummy) PetscCall(DMSwarmRegisterPetscDatatypeField(sw, celldm->cellid, 1, PETSC_INT)); 1469 } 1470 PetscCall(DMSwarmSetCellDMActive(sw, name)); 1471 PetscFunctionReturn(PETSC_SUCCESS); 1472 } 1473 1474 /*@ 1475 DMSwarmGetLocalSize - Retrieves the local length of fields registered 1476 1477 Not Collective 1478 1479 Input Parameter: 1480 . dm - a `DMSWARM` 1481 1482 Output Parameter: 1483 . nlocal - the length of each registered field 1484 1485 Level: beginner 1486 1487 .seealso: `DM`, `DMSWARM`, `DMSwarmGetSize()`, `DMSwarmSetLocalSizes()` 1488 @*/ 1489 PetscErrorCode DMSwarmGetLocalSize(DM dm, PetscInt *nlocal) 1490 { 1491 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1492 1493 PetscFunctionBegin; 1494 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, nlocal, NULL, NULL)); 1495 PetscFunctionReturn(PETSC_SUCCESS); 1496 } 1497 1498 /*@ 1499 DMSwarmGetSize - Retrieves the total length of fields registered 1500 1501 Collective 1502 1503 Input Parameter: 1504 . dm - a `DMSWARM` 1505 1506 Output Parameter: 1507 . n - the total length of each registered field 1508 1509 Level: beginner 1510 1511 Note: 1512 This calls `MPI_Allreduce()` upon each call (inefficient but safe) 1513 1514 .seealso: `DM`, `DMSWARM`, `DMSwarmGetLocalSize()`, `DMSwarmSetLocalSizes()` 1515 @*/ 1516 PetscErrorCode DMSwarmGetSize(DM dm, PetscInt *n) 1517 { 1518 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1519 PetscInt nlocal; 1520 1521 PetscFunctionBegin; 1522 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL)); 1523 PetscCallMPI(MPIU_Allreduce(&nlocal, n, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 1524 PetscFunctionReturn(PETSC_SUCCESS); 1525 } 1526 1527 /*@C 1528 DMSwarmRegisterPetscDatatypeField - Register a field to a `DMSWARM` with a native PETSc data type 1529 1530 Collective 1531 1532 Input Parameters: 1533 + dm - a `DMSWARM` 1534 . fieldname - the textual name to identify this field 1535 . blocksize - the number of each data type 1536 - type - a valid PETSc data type (`PETSC_CHAR`, `PETSC_SHORT`, `PETSC_INT`, `PETSC_FLOAT`, `PETSC_REAL`, `PETSC_LONG`) 1537 1538 Level: beginner 1539 1540 Notes: 1541 The textual name for each registered field must be unique. 1542 1543 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()` 1544 @*/ 1545 PetscErrorCode DMSwarmRegisterPetscDatatypeField(DM dm, const char fieldname[], PetscInt blocksize, PetscDataType type) 1546 { 1547 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1548 size_t size; 1549 1550 PetscFunctionBegin; 1551 PetscCheck(swarm->field_registration_initialized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmInitializeFieldRegister() first"); 1552 PetscCheck(!swarm->field_registration_finalized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Cannot register additional fields after calling DMSwarmFinalizeFieldRegister() first"); 1553 1554 PetscCheck(type != PETSC_OBJECT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}"); 1555 PetscCheck(type != PETSC_FUNCTION, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}"); 1556 PetscCheck(type != PETSC_STRING, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}"); 1557 PetscCheck(type != PETSC_STRUCT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}"); 1558 PetscCheck(type != PETSC_DATATYPE_UNKNOWN, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}"); 1559 1560 PetscCall(PetscDataTypeGetSize(type, &size)); 1561 /* Load a specific data type into data bucket, specifying textual name and its size in bytes */ 1562 PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterPetscDatatypeField", fieldname, blocksize * size, NULL)); 1563 { 1564 DMSwarmDataField gfield; 1565 1566 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield)); 1567 PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize)); 1568 } 1569 swarm->db->field[swarm->db->nfields - 1]->petsc_type = type; 1570 PetscFunctionReturn(PETSC_SUCCESS); 1571 } 1572 1573 /*@C 1574 DMSwarmRegisterUserStructField - Register a user defined struct to a `DMSWARM` 1575 1576 Collective 1577 1578 Input Parameters: 1579 + dm - a `DMSWARM` 1580 . fieldname - the textual name to identify this field 1581 - size - the size in bytes of the user struct of each data type 1582 1583 Level: beginner 1584 1585 Note: 1586 The textual name for each registered field must be unique. 1587 1588 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserDatatypeField()` 1589 @*/ 1590 PetscErrorCode DMSwarmRegisterUserStructField(DM dm, const char fieldname[], size_t size) 1591 { 1592 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1593 1594 PetscFunctionBegin; 1595 PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserStructField", fieldname, size, NULL)); 1596 swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_STRUCT; 1597 PetscFunctionReturn(PETSC_SUCCESS); 1598 } 1599 1600 /*@C 1601 DMSwarmRegisterUserDatatypeField - Register a user defined data type to a `DMSWARM` 1602 1603 Collective 1604 1605 Input Parameters: 1606 + dm - a `DMSWARM` 1607 . fieldname - the textual name to identify this field 1608 . size - the size in bytes of the user data type 1609 - blocksize - the number of each data type 1610 1611 Level: beginner 1612 1613 Note: 1614 The textual name for each registered field must be unique. 1615 1616 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserStructField()` 1617 @*/ 1618 PetscErrorCode DMSwarmRegisterUserDatatypeField(DM dm, const char fieldname[], size_t size, PetscInt blocksize) 1619 { 1620 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1621 1622 PetscFunctionBegin; 1623 PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserDatatypeField", fieldname, blocksize * size, NULL)); 1624 { 1625 DMSwarmDataField gfield; 1626 1627 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield)); 1628 PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize)); 1629 } 1630 swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_DATATYPE_UNKNOWN; 1631 PetscFunctionReturn(PETSC_SUCCESS); 1632 } 1633 1634 /*@C 1635 DMSwarmGetField - Get access to the underlying array storing all entries associated with a registered field 1636 1637 Not Collective, No Fortran Support 1638 1639 Input Parameters: 1640 + dm - a `DMSWARM` 1641 - fieldname - the textual name to identify this field 1642 1643 Output Parameters: 1644 + blocksize - the number of each data type 1645 . type - the data type 1646 - data - pointer to raw array 1647 1648 Level: beginner 1649 1650 Notes: 1651 The array must be returned using a matching call to `DMSwarmRestoreField()`. 1652 1653 Fortran Note: 1654 Only works for `type` of `PETSC_SCALAR` 1655 1656 .seealso: `DM`, `DMSWARM`, `DMSwarmRestoreField()` 1657 @*/ 1658 PetscErrorCode DMSwarmGetField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data) PeNS 1659 { 1660 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1661 DMSwarmDataField gfield; 1662 1663 PetscFunctionBegin; 1664 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 1665 if (!swarm->issetup) PetscCall(DMSetUp(dm)); 1666 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield)); 1667 PetscCall(DMSwarmDataFieldGetAccess(gfield)); 1668 PetscCall(DMSwarmDataFieldGetEntries(gfield, data)); 1669 if (blocksize) *blocksize = gfield->bs; 1670 if (type) *type = gfield->petsc_type; 1671 PetscFunctionReturn(PETSC_SUCCESS); 1672 } 1673 1674 /*@C 1675 DMSwarmRestoreField - Restore access to the underlying array storing all entries associated with a registered field 1676 1677 Not Collective 1678 1679 Input Parameters: 1680 + dm - a `DMSWARM` 1681 - fieldname - the textual name to identify this field 1682 1683 Output Parameters: 1684 + blocksize - the number of each data type 1685 . type - the data type 1686 - data - pointer to raw array 1687 1688 Level: beginner 1689 1690 Notes: 1691 The user must call `DMSwarmGetField()` prior to calling `DMSwarmRestoreField()`. 1692 1693 Fortran Note: 1694 Only works for `type` of `PETSC_SCALAR` 1695 1696 .seealso: `DM`, `DMSWARM`, `DMSwarmGetField()` 1697 @*/ 1698 PetscErrorCode DMSwarmRestoreField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data) PeNS 1699 { 1700 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1701 DMSwarmDataField gfield; 1702 1703 PetscFunctionBegin; 1704 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 1705 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield)); 1706 PetscCall(DMSwarmDataFieldRestoreAccess(gfield)); 1707 if (data) *data = NULL; 1708 PetscFunctionReturn(PETSC_SUCCESS); 1709 } 1710 1711 PetscErrorCode DMSwarmGetFieldInfo(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type) 1712 { 1713 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1714 DMSwarmDataField gfield; 1715 1716 PetscFunctionBegin; 1717 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM); 1718 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield)); 1719 if (blocksize) *blocksize = gfield->bs; 1720 if (type) *type = gfield->petsc_type; 1721 PetscFunctionReturn(PETSC_SUCCESS); 1722 } 1723 1724 /*@ 1725 DMSwarmAddPoint - Add space for one new point in the `DMSWARM` 1726 1727 Not Collective 1728 1729 Input Parameter: 1730 . dm - a `DMSWARM` 1731 1732 Level: beginner 1733 1734 Notes: 1735 The new point will have all fields initialized to zero. 1736 1737 .seealso: `DM`, `DMSWARM`, `DMSwarmAddNPoints()` 1738 @*/ 1739 PetscErrorCode DMSwarmAddPoint(DM dm) 1740 { 1741 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1742 1743 PetscFunctionBegin; 1744 if (!swarm->issetup) PetscCall(DMSetUp(dm)); 1745 PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0)); 1746 PetscCall(DMSwarmDataBucketAddPoint(swarm->db)); 1747 PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0)); 1748 PetscFunctionReturn(PETSC_SUCCESS); 1749 } 1750 1751 /*@ 1752 DMSwarmAddNPoints - Add space for a number of new points in the `DMSWARM` 1753 1754 Not Collective 1755 1756 Input Parameters: 1757 + dm - a `DMSWARM` 1758 - npoints - the number of new points to add 1759 1760 Level: beginner 1761 1762 Notes: 1763 The new point will have all fields initialized to zero. 1764 1765 .seealso: `DM`, `DMSWARM`, `DMSwarmAddPoint()` 1766 @*/ 1767 PetscErrorCode DMSwarmAddNPoints(DM dm, PetscInt npoints) 1768 { 1769 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1770 PetscInt nlocal; 1771 1772 PetscFunctionBegin; 1773 PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0)); 1774 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL)); 1775 nlocal = nlocal + npoints; 1776 PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT)); 1777 PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0)); 1778 PetscFunctionReturn(PETSC_SUCCESS); 1779 } 1780 1781 /*@ 1782 DMSwarmRemovePoint - Remove the last point from the `DMSWARM` 1783 1784 Not Collective 1785 1786 Input Parameter: 1787 . dm - a `DMSWARM` 1788 1789 Level: beginner 1790 1791 .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePointAtIndex()` 1792 @*/ 1793 PetscErrorCode DMSwarmRemovePoint(DM dm) 1794 { 1795 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1796 1797 PetscFunctionBegin; 1798 PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0)); 1799 PetscCall(DMSwarmDataBucketRemovePoint(swarm->db)); 1800 PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0)); 1801 PetscFunctionReturn(PETSC_SUCCESS); 1802 } 1803 1804 /*@ 1805 DMSwarmRemovePointAtIndex - Removes a specific point from the `DMSWARM` 1806 1807 Not Collective 1808 1809 Input Parameters: 1810 + dm - a `DMSWARM` 1811 - idx - index of point to remove 1812 1813 Level: beginner 1814 1815 .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePoint()` 1816 @*/ 1817 PetscErrorCode DMSwarmRemovePointAtIndex(DM dm, PetscInt idx) 1818 { 1819 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1820 1821 PetscFunctionBegin; 1822 PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0)); 1823 PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, idx)); 1824 PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0)); 1825 PetscFunctionReturn(PETSC_SUCCESS); 1826 } 1827 1828 /*@ 1829 DMSwarmCopyPoint - Copy point pj to point pi in the `DMSWARM` 1830 1831 Not Collective 1832 1833 Input Parameters: 1834 + dm - a `DMSWARM` 1835 . pi - the index of the point to copy 1836 - pj - the point index where the copy should be located 1837 1838 Level: beginner 1839 1840 .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePoint()` 1841 @*/ 1842 PetscErrorCode DMSwarmCopyPoint(DM dm, PetscInt pi, PetscInt pj) 1843 { 1844 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1845 1846 PetscFunctionBegin; 1847 if (!swarm->issetup) PetscCall(DMSetUp(dm)); 1848 PetscCall(DMSwarmDataBucketCopyPoint(swarm->db, pi, swarm->db, pj)); 1849 PetscFunctionReturn(PETSC_SUCCESS); 1850 } 1851 1852 static PetscErrorCode DMSwarmMigrate_Basic(DM dm, PetscBool remove_sent_points) 1853 { 1854 PetscFunctionBegin; 1855 PetscCall(DMSwarmMigrate_Push_Basic(dm, remove_sent_points)); 1856 PetscFunctionReturn(PETSC_SUCCESS); 1857 } 1858 1859 /*@ 1860 DMSwarmMigrate - Relocates points defined in the `DMSWARM` to other MPI-ranks 1861 1862 Collective 1863 1864 Input Parameters: 1865 + dm - the `DMSWARM` 1866 - remove_sent_points - flag indicating if sent points should be removed from the current MPI-rank 1867 1868 Level: advanced 1869 1870 Notes: 1871 The `DM` will be modified to accommodate received points. 1872 If `remove_sent_points` is `PETSC_TRUE`, any points that were sent will be removed from the `DM`. 1873 Different styles of migration are supported. See `DMSwarmSetMigrateType()`. 1874 1875 .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()` 1876 @*/ 1877 PetscErrorCode DMSwarmMigrate(DM dm, PetscBool remove_sent_points) 1878 { 1879 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1880 1881 PetscFunctionBegin; 1882 PetscCall(PetscLogEventBegin(DMSWARM_Migrate, 0, 0, 0, 0)); 1883 switch (swarm->migrate_type) { 1884 case DMSWARM_MIGRATE_BASIC: 1885 PetscCall(DMSwarmMigrate_Basic(dm, remove_sent_points)); 1886 break; 1887 case DMSWARM_MIGRATE_DMCELLNSCATTER: 1888 PetscCall(DMSwarmMigrate_CellDMScatter(dm, remove_sent_points)); 1889 break; 1890 case DMSWARM_MIGRATE_DMCELLEXACT: 1891 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_DMCELLEXACT not implemented"); 1892 case DMSWARM_MIGRATE_USER: 1893 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_USER not implemented"); 1894 default: 1895 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE type unknown"); 1896 } 1897 PetscCall(PetscLogEventEnd(DMSWARM_Migrate, 0, 0, 0, 0)); 1898 PetscCall(DMClearGlobalVectors(dm)); 1899 PetscFunctionReturn(PETSC_SUCCESS); 1900 } 1901 1902 PetscErrorCode DMSwarmMigrate_GlobalToLocal_Basic(DM dm, PetscInt *globalsize); 1903 1904 /* 1905 DMSwarmCollectViewCreate 1906 1907 * Applies a collection method and gathers point neighbour points into dm 1908 1909 Notes: 1910 Users should call DMSwarmCollectViewDestroy() after 1911 they have finished computations associated with the collected points 1912 */ 1913 1914 /*@ 1915 DMSwarmCollectViewCreate - Applies a collection method and gathers points 1916 in neighbour ranks into the `DMSWARM` 1917 1918 Collective 1919 1920 Input Parameter: 1921 . dm - the `DMSWARM` 1922 1923 Level: advanced 1924 1925 Notes: 1926 Users should call `DMSwarmCollectViewDestroy()` after 1927 they have finished computations associated with the collected points 1928 1929 Different collect methods are supported. See `DMSwarmSetCollectType()`. 1930 1931 Developer Note: 1932 Create and Destroy routines create new objects that can get destroyed, they do not change the state 1933 of the current object. 1934 1935 .seealso: `DM`, `DMSWARM`, `DMSwarmCollectViewDestroy()`, `DMSwarmSetCollectType()` 1936 @*/ 1937 PetscErrorCode DMSwarmCollectViewCreate(DM dm) 1938 { 1939 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1940 PetscInt ng; 1941 1942 PetscFunctionBegin; 1943 PetscCheck(!swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView currently active"); 1944 PetscCall(DMSwarmGetLocalSize(dm, &ng)); 1945 switch (swarm->collect_type) { 1946 case DMSWARM_COLLECT_BASIC: 1947 PetscCall(DMSwarmMigrate_GlobalToLocal_Basic(dm, &ng)); 1948 break; 1949 case DMSWARM_COLLECT_DMDABOUNDINGBOX: 1950 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_DMDABOUNDINGBOX not implemented"); 1951 case DMSWARM_COLLECT_GENERAL: 1952 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_GENERAL not implemented"); 1953 default: 1954 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT type unknown"); 1955 } 1956 swarm->collect_view_active = PETSC_TRUE; 1957 swarm->collect_view_reset_nlocal = ng; 1958 PetscFunctionReturn(PETSC_SUCCESS); 1959 } 1960 1961 /*@ 1962 DMSwarmCollectViewDestroy - Resets the `DMSWARM` to the size prior to calling `DMSwarmCollectViewCreate()` 1963 1964 Collective 1965 1966 Input Parameters: 1967 . dm - the `DMSWARM` 1968 1969 Notes: 1970 Users should call `DMSwarmCollectViewCreate()` before this function is called. 1971 1972 Level: advanced 1973 1974 Developer Note: 1975 Create and Destroy routines create new objects that can get destroyed, they do not change the state 1976 of the current object. 1977 1978 .seealso: `DM`, `DMSWARM`, `DMSwarmCollectViewCreate()`, `DMSwarmSetCollectType()` 1979 @*/ 1980 PetscErrorCode DMSwarmCollectViewDestroy(DM dm) 1981 { 1982 DM_Swarm *swarm = (DM_Swarm *)dm->data; 1983 1984 PetscFunctionBegin; 1985 PetscCheck(swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView is currently not active"); 1986 PetscCall(DMSwarmSetLocalSizes(dm, swarm->collect_view_reset_nlocal, -1)); 1987 swarm->collect_view_active = PETSC_FALSE; 1988 PetscFunctionReturn(PETSC_SUCCESS); 1989 } 1990 1991 static PetscErrorCode DMSwarmSetUpPIC(DM dm) 1992 { 1993 PetscInt dim; 1994 1995 PetscFunctionBegin; 1996 PetscCall(DMSwarmSetNumSpecies(dm, 1)); 1997 PetscCall(DMGetDimension(dm, &dim)); 1998 PetscCheck(dim >= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim); 1999 PetscCheck(dim <= 3, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim); 2000 PetscFunctionReturn(PETSC_SUCCESS); 2001 } 2002 2003 /*@ 2004 DMSwarmSetPointCoordinatesRandom - Sets initial coordinates for particles in each cell 2005 2006 Collective 2007 2008 Input Parameters: 2009 + dm - the `DMSWARM` 2010 - Npc - The number of particles per cell in the cell `DM` 2011 2012 Level: intermediate 2013 2014 Notes: 2015 The user must use `DMSwarmSetCellDM()` to set the cell `DM` first. The particles are placed randomly inside each cell. If only 2016 one particle is in each cell, it is placed at the centroid. 2017 2018 .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()` 2019 @*/ 2020 PetscErrorCode DMSwarmSetPointCoordinatesRandom(DM dm, PetscInt Npc) 2021 { 2022 DM cdm; 2023 DMSwarmCellDM celldm; 2024 PetscRandom rnd; 2025 DMPolytopeType ct; 2026 PetscBool simplex; 2027 PetscReal *centroid, *coords, *xi0, *v0, *J, *invJ, detJ; 2028 PetscInt dim, d, cStart, cEnd, c, p, Nfc; 2029 const char **coordFields; 2030 2031 PetscFunctionBeginUser; 2032 PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)dm), &rnd)); 2033 PetscCall(PetscRandomSetInterval(rnd, -1.0, 1.0)); 2034 PetscCall(PetscRandomSetType(rnd, PETSCRAND48)); 2035 2036 PetscCall(DMSwarmGetCellDMActive(dm, &celldm)); 2037 PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields)); 2038 PetscCheck(Nfc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "We only support a single coordinate field right now, not %" PetscInt_FMT, Nfc); 2039 PetscCall(DMSwarmGetCellDM(dm, &cdm)); 2040 PetscCall(DMGetDimension(cdm, &dim)); 2041 PetscCall(DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd)); 2042 PetscCall(DMPlexGetCellType(cdm, cStart, &ct)); 2043 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 2044 2045 PetscCall(PetscMalloc5(dim, ¢roid, dim, &xi0, dim, &v0, dim * dim, &J, dim * dim, &invJ)); 2046 for (d = 0; d < dim; ++d) xi0[d] = -1.0; 2047 PetscCall(DMSwarmGetField(dm, coordFields[0], NULL, NULL, (void **)&coords)); 2048 for (c = cStart; c < cEnd; ++c) { 2049 if (Npc == 1) { 2050 PetscCall(DMPlexComputeCellGeometryFVM(cdm, c, NULL, centroid, NULL)); 2051 for (d = 0; d < dim; ++d) coords[c * dim + d] = centroid[d]; 2052 } else { 2053 PetscCall(DMPlexComputeCellGeometryFEM(cdm, c, NULL, v0, J, invJ, &detJ)); /* affine */ 2054 for (p = 0; p < Npc; ++p) { 2055 const PetscInt n = c * Npc + p; 2056 PetscReal sum = 0.0, refcoords[3]; 2057 2058 for (d = 0; d < dim; ++d) { 2059 PetscCall(PetscRandomGetValueReal(rnd, &refcoords[d])); 2060 sum += refcoords[d]; 2061 } 2062 if (simplex && sum > 0.0) 2063 for (d = 0; d < dim; ++d) refcoords[d] -= PetscSqrtReal(dim) * sum; 2064 CoordinatesRefToReal(dim, dim, xi0, v0, J, refcoords, &coords[n * dim]); 2065 } 2066 } 2067 } 2068 PetscCall(DMSwarmRestoreField(dm, coordFields[0], NULL, NULL, (void **)&coords)); 2069 PetscCall(PetscFree5(centroid, xi0, v0, J, invJ)); 2070 PetscCall(PetscRandomDestroy(&rnd)); 2071 PetscFunctionReturn(PETSC_SUCCESS); 2072 } 2073 2074 /*@ 2075 DMSwarmGetType - Get particular flavor of `DMSWARM` 2076 2077 Collective 2078 2079 Input Parameter: 2080 . sw - the `DMSWARM` 2081 2082 Output Parameter: 2083 . stype - the `DMSWARM` type (e.g. `DMSWARM_PIC`) 2084 2085 Level: advanced 2086 2087 .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()`, `DMSwarmSetCollectType()`, `DMSwarmType`, `DMSWARM_PIC`, `DMSWARM_BASIC` 2088 @*/ 2089 PetscErrorCode DMSwarmGetType(DM sw, DMSwarmType *stype) 2090 { 2091 DM_Swarm *swarm = (DM_Swarm *)sw->data; 2092 2093 PetscFunctionBegin; 2094 PetscValidHeaderSpecific(sw, DM_CLASSID, 1); 2095 PetscAssertPointer(stype, 2); 2096 *stype = swarm->swarm_type; 2097 PetscFunctionReturn(PETSC_SUCCESS); 2098 } 2099 2100 /*@ 2101 DMSwarmSetType - Set particular flavor of `DMSWARM` 2102 2103 Collective 2104 2105 Input Parameters: 2106 + sw - the `DMSWARM` 2107 - stype - the `DMSWARM` type (e.g. `DMSWARM_PIC`) 2108 2109 Level: advanced 2110 2111 .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()`, `DMSwarmSetCollectType()`, `DMSwarmType`, `DMSWARM_PIC`, `DMSWARM_BASIC` 2112 @*/ 2113 PetscErrorCode DMSwarmSetType(DM sw, DMSwarmType stype) 2114 { 2115 DM_Swarm *swarm = (DM_Swarm *)sw->data; 2116 2117 PetscFunctionBegin; 2118 PetscValidHeaderSpecific(sw, DM_CLASSID, 1); 2119 swarm->swarm_type = stype; 2120 if (swarm->swarm_type == DMSWARM_PIC) PetscCall(DMSwarmSetUpPIC(sw)); 2121 PetscFunctionReturn(PETSC_SUCCESS); 2122 } 2123 2124 static PetscErrorCode DMSwarmCreateRemapDM_Private(DM sw, DM *rdm) 2125 { 2126 PetscFE fe; 2127 DMPolytopeType ct; 2128 PetscInt dim, cStart; 2129 const char *prefix = "remap_"; 2130 2131 PetscFunctionBegin; 2132 PetscCall(DMCreate(PetscObjectComm((PetscObject)sw), rdm)); 2133 PetscCall(DMSetType(*rdm, DMPLEX)); 2134 PetscCall(DMPlexSetOptionsPrefix(*rdm, prefix)); 2135 PetscCall(DMSetFromOptions(*rdm)); 2136 PetscCall(PetscObjectSetName((PetscObject)*rdm, "remap")); 2137 PetscCall(DMViewFromOptions(*rdm, NULL, "-dm_view")); 2138 2139 PetscCall(DMGetDimension(*rdm, &dim)); 2140 PetscCall(DMPlexGetHeightStratum(*rdm, 0, &cStart, NULL)); 2141 PetscCall(DMPlexGetCellType(*rdm, cStart, &ct)); 2142 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, prefix, PETSC_DETERMINE, &fe)); 2143 PetscCall(PetscObjectSetName((PetscObject)fe, "distribution")); 2144 PetscCall(DMSetField(*rdm, 0, NULL, (PetscObject)fe)); 2145 PetscCall(DMCreateDS(*rdm)); 2146 PetscCall(PetscFEDestroy(&fe)); 2147 PetscFunctionReturn(PETSC_SUCCESS); 2148 } 2149 2150 static PetscErrorCode DMSetup_Swarm(DM sw) 2151 { 2152 DM_Swarm *swarm = (DM_Swarm *)sw->data; 2153 2154 PetscFunctionBegin; 2155 if (swarm->issetup) PetscFunctionReturn(PETSC_SUCCESS); 2156 swarm->issetup = PETSC_TRUE; 2157 2158 if (swarm->remap_type != DMSWARM_REMAP_NONE) { 2159 DMSwarmCellDM celldm; 2160 DM rdm; 2161 const char *fieldnames[2] = {DMSwarmPICField_coor, "velocity"}; 2162 const char *vfieldnames[1] = {"w_q"}; 2163 2164 PetscCall(DMSwarmCreateRemapDM_Private(sw, &rdm)); 2165 PetscCall(DMSwarmCellDMCreate(rdm, 1, vfieldnames, 2, fieldnames, &celldm)); 2166 PetscCall(DMSwarmAddCellDM(sw, celldm)); 2167 PetscCall(DMSwarmCellDMDestroy(&celldm)); 2168 PetscCall(DMDestroy(&rdm)); 2169 } 2170 2171 if (swarm->swarm_type == DMSWARM_PIC) { 2172 DMSwarmCellDM celldm; 2173 2174 PetscCall(DMSwarmGetCellDMActive(sw, &celldm)); 2175 PetscCheck(celldm, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "No active cell DM. DMSWARM_PIC requires you call DMSwarmSetCellDM() or DMSwarmAddCellDM()"); 2176 if (celldm->dm->ops->locatepointssubdomain) { 2177 /* check methods exists for exact ownership identificiation */ 2178 PetscCall(PetscInfo(sw, "DMSWARM_PIC: Using method CellDM->ops->LocatePointsSubdomain\n")); 2179 swarm->migrate_type = DMSWARM_MIGRATE_DMCELLEXACT; 2180 } else { 2181 /* check methods exist for point location AND rank neighbor identification */ 2182 if (celldm->dm->ops->locatepoints) { 2183 PetscCall(PetscInfo(sw, "DMSWARM_PIC: Using method CellDM->LocatePoints\n")); 2184 } else SETERRQ(PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->locatepoints be defined"); 2185 2186 if (celldm->dm->ops->getneighbors) { 2187 PetscCall(PetscInfo(sw, "DMSWARM_PIC: Using method CellDM->GetNeigbors\n")); 2188 } else SETERRQ(PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->getneighbors be defined"); 2189 2190 swarm->migrate_type = DMSWARM_MIGRATE_DMCELLNSCATTER; 2191 } 2192 } 2193 2194 PetscCall(DMSwarmFinalizeFieldRegister(sw)); 2195 2196 /* check some fields were registered */ 2197 PetscCheck(swarm->db->nfields > 2, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "At least one field user must be registered via DMSwarmRegisterXXX()"); 2198 PetscFunctionReturn(PETSC_SUCCESS); 2199 } 2200 2201 static PetscErrorCode DMDestroy_Swarm(DM dm) 2202 { 2203 DM_Swarm *swarm = (DM_Swarm *)dm->data; 2204 2205 PetscFunctionBegin; 2206 if (--swarm->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2207 PetscCall(PetscObjectListDestroy(&swarm->cellDMs)); 2208 PetscCall(PetscFree(swarm->activeCellDM)); 2209 PetscCall(DMSwarmDataBucketDestroy(&swarm->db)); 2210 PetscCall(PetscFree(swarm)); 2211 PetscFunctionReturn(PETSC_SUCCESS); 2212 } 2213 2214 static PetscErrorCode DMSwarmView_Draw(DM dm, PetscViewer viewer) 2215 { 2216 DM cdm; 2217 DMSwarmCellDM celldm; 2218 PetscDraw draw; 2219 PetscReal *coords, oldPause, radius = 0.01; 2220 PetscInt Np, p, bs, Nfc; 2221 const char **coordFields; 2222 2223 PetscFunctionBegin; 2224 PetscCall(PetscOptionsGetReal(NULL, ((PetscObject)dm)->prefix, "-dm_view_swarm_radius", &radius, NULL)); 2225 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 2226 PetscCall(DMSwarmGetCellDM(dm, &cdm)); 2227 PetscCall(PetscDrawGetPause(draw, &oldPause)); 2228 PetscCall(PetscDrawSetPause(draw, 0.0)); 2229 PetscCall(DMView(cdm, viewer)); 2230 PetscCall(PetscDrawSetPause(draw, oldPause)); 2231 2232 PetscCall(DMSwarmGetCellDMActive(dm, &celldm)); 2233 PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields)); 2234 PetscCheck(Nfc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "We only support a single coordinate field right now, not %" PetscInt_FMT, Nfc); 2235 PetscCall(DMSwarmGetLocalSize(dm, &Np)); 2236 PetscCall(DMSwarmGetField(dm, coordFields[0], &bs, NULL, (void **)&coords)); 2237 for (p = 0; p < Np; ++p) { 2238 const PetscInt i = p * bs; 2239 2240 PetscCall(PetscDrawEllipse(draw, coords[i], coords[i + 1], radius, radius, PETSC_DRAW_BLUE)); 2241 } 2242 PetscCall(DMSwarmRestoreField(dm, coordFields[0], &bs, NULL, (void **)&coords)); 2243 PetscCall(PetscDrawFlush(draw)); 2244 PetscCall(PetscDrawPause(draw)); 2245 PetscCall(PetscDrawSave(draw)); 2246 PetscFunctionReturn(PETSC_SUCCESS); 2247 } 2248 2249 static PetscErrorCode DMView_Swarm_Ascii(DM dm, PetscViewer viewer) 2250 { 2251 PetscViewerFormat format; 2252 PetscInt *sizes; 2253 PetscInt dim, Np, maxSize = 17; 2254 MPI_Comm comm; 2255 PetscMPIInt rank, size, p; 2256 const char *name, *cellid; 2257 2258 PetscFunctionBegin; 2259 PetscCall(PetscViewerGetFormat(viewer, &format)); 2260 PetscCall(DMGetDimension(dm, &dim)); 2261 PetscCall(DMSwarmGetLocalSize(dm, &Np)); 2262 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 2263 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 2264 PetscCallMPI(MPI_Comm_size(comm, &size)); 2265 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 2266 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 2267 else PetscCall(PetscViewerASCIIPrintf(viewer, "Swarm in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 2268 if (size < maxSize) PetscCall(PetscCalloc1(size, &sizes)); 2269 else PetscCall(PetscCalloc1(3, &sizes)); 2270 if (size < maxSize) { 2271 PetscCallMPI(MPI_Gather(&Np, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 2272 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of particles per rank:")); 2273 for (p = 0; p < size; ++p) { 2274 if (rank == 0) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p])); 2275 } 2276 } else { 2277 PetscInt locMinMax[2] = {Np, Np}; 2278 2279 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 2280 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of particles per rank: %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 2281 } 2282 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 2283 PetscCall(PetscFree(sizes)); 2284 if (format == PETSC_VIEWER_ASCII_INFO) { 2285 DMSwarmCellDM celldm; 2286 PetscInt *cell; 2287 2288 PetscCall(PetscViewerASCIIPrintf(viewer, " Cells containing each particle:\n")); 2289 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 2290 PetscCall(DMSwarmGetCellDMActive(dm, &celldm)); 2291 PetscCall(DMSwarmCellDMGetCellID(celldm, &cellid)); 2292 PetscCall(DMSwarmGetField(dm, cellid, NULL, NULL, (void **)&cell)); 2293 for (p = 0; p < Np; ++p) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " p%d: %" PetscInt_FMT "\n", p, cell[p])); 2294 PetscCall(PetscViewerFlush(viewer)); 2295 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 2296 PetscCall(DMSwarmRestoreField(dm, cellid, NULL, NULL, (void **)&cell)); 2297 } 2298 PetscFunctionReturn(PETSC_SUCCESS); 2299 } 2300 2301 static PetscErrorCode DMView_Swarm(DM dm, PetscViewer viewer) 2302 { 2303 DM_Swarm *swarm = (DM_Swarm *)dm->data; 2304 PetscBool iascii, ibinary, isvtk, isdraw, ispython; 2305 #if defined(PETSC_HAVE_HDF5) 2306 PetscBool ishdf5; 2307 #endif 2308 2309 PetscFunctionBegin; 2310 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2311 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2312 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 2313 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &ibinary)); 2314 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 2315 #if defined(PETSC_HAVE_HDF5) 2316 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2317 #endif 2318 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 2319 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 2320 if (iascii) { 2321 PetscViewerFormat format; 2322 2323 PetscCall(PetscViewerGetFormat(viewer, &format)); 2324 switch (format) { 2325 case PETSC_VIEWER_ASCII_INFO_DETAIL: 2326 PetscCall(DMSwarmDataBucketView(PetscObjectComm((PetscObject)dm), swarm->db, NULL, DATABUCKET_VIEW_STDOUT)); 2327 break; 2328 default: 2329 PetscCall(DMView_Swarm_Ascii(dm, viewer)); 2330 } 2331 } else { 2332 #if defined(PETSC_HAVE_HDF5) 2333 if (ishdf5) PetscCall(DMSwarmView_HDF5(dm, viewer)); 2334 #endif 2335 if (isdraw) PetscCall(DMSwarmView_Draw(dm, viewer)); 2336 if (ispython) PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm)); 2337 } 2338 PetscFunctionReturn(PETSC_SUCCESS); 2339 } 2340 2341 /*@ 2342 DMSwarmGetCellSwarm - Extracts a single cell from the `DMSWARM` object, returns it as a single cell `DMSWARM`. 2343 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. 2344 2345 Noncollective 2346 2347 Input Parameters: 2348 + sw - the `DMSWARM` 2349 . cellID - the integer id of the cell to be extracted and filtered 2350 - cellswarm - The `DMSWARM` to receive the cell 2351 2352 Level: beginner 2353 2354 Notes: 2355 This presently only supports `DMSWARM_PIC` type 2356 2357 Should be restored with `DMSwarmRestoreCellSwarm()` 2358 2359 Changes to this cell of the swarm will be lost if they are made prior to restoring this cell. 2360 2361 .seealso: `DM`, `DMSWARM`, `DMSwarmRestoreCellSwarm()` 2362 @*/ 2363 PetscErrorCode DMSwarmGetCellSwarm(DM sw, PetscInt cellID, DM cellswarm) 2364 { 2365 DM_Swarm *original = (DM_Swarm *)sw->data; 2366 DMLabel label; 2367 DM dmc, subdmc; 2368 PetscInt *pids, particles, dim; 2369 const char *name; 2370 2371 PetscFunctionBegin; 2372 /* Configure new swarm */ 2373 PetscCall(DMSetType(cellswarm, DMSWARM)); 2374 PetscCall(DMGetDimension(sw, &dim)); 2375 PetscCall(DMSetDimension(cellswarm, dim)); 2376 PetscCall(DMSwarmSetType(cellswarm, DMSWARM_PIC)); 2377 /* Destroy the unused, unconfigured data bucket to prevent stragglers in memory */ 2378 PetscCall(DMSwarmDataBucketDestroy(&((DM_Swarm *)cellswarm->data)->db)); 2379 PetscCall(DMSwarmSortGetAccess(sw)); 2380 PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, cellID, &particles)); 2381 PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids)); 2382 PetscCall(DMSwarmDataBucketCreateFromSubset(original->db, particles, pids, &((DM_Swarm *)cellswarm->data)->db)); 2383 PetscCall(DMSwarmSortRestoreAccess(sw)); 2384 PetscCall(DMSwarmSortRestorePointsPerCell(sw, cellID, &particles, &pids)); 2385 PetscCall(DMSwarmGetCellDM(sw, &dmc)); 2386 PetscCall(DMLabelCreate(PetscObjectComm((PetscObject)sw), "singlecell", &label)); 2387 PetscCall(DMAddLabel(dmc, label)); 2388 PetscCall(DMLabelSetValue(label, cellID, 1)); 2389 PetscCall(DMPlexFilter(dmc, label, 1, PETSC_FALSE, PETSC_FALSE, NULL, &subdmc)); 2390 PetscCall(PetscObjectGetName((PetscObject)dmc, &name)); 2391 PetscCall(PetscObjectSetName((PetscObject)subdmc, name)); 2392 PetscCall(DMSwarmSetCellDM(cellswarm, subdmc)); 2393 PetscCall(DMLabelDestroy(&label)); 2394 PetscFunctionReturn(PETSC_SUCCESS); 2395 } 2396 2397 /*@ 2398 DMSwarmRestoreCellSwarm - Restores a `DMSWARM` object obtained with `DMSwarmGetCellSwarm()`. All fields are copied back into the parent swarm. 2399 2400 Noncollective 2401 2402 Input Parameters: 2403 + sw - the parent `DMSWARM` 2404 . cellID - the integer id of the cell to be copied back into the parent swarm 2405 - cellswarm - the cell swarm object 2406 2407 Level: beginner 2408 2409 Note: 2410 This only supports `DMSWARM_PIC` types of `DMSWARM`s 2411 2412 .seealso: `DM`, `DMSWARM`, `DMSwarmGetCellSwarm()` 2413 @*/ 2414 PetscErrorCode DMSwarmRestoreCellSwarm(DM sw, PetscInt cellID, DM cellswarm) 2415 { 2416 DM dmc; 2417 PetscInt *pids, particles, p; 2418 2419 PetscFunctionBegin; 2420 PetscCall(DMSwarmSortGetAccess(sw)); 2421 PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids)); 2422 PetscCall(DMSwarmSortRestoreAccess(sw)); 2423 /* Pointwise copy of each particle based on pid. The parent swarm may not be altered during this process. */ 2424 for (p = 0; p < particles; ++p) PetscCall(DMSwarmDataBucketCopyPoint(((DM_Swarm *)cellswarm->data)->db, pids[p], ((DM_Swarm *)sw->data)->db, pids[p])); 2425 /* Free memory, destroy cell dm */ 2426 PetscCall(DMSwarmGetCellDM(cellswarm, &dmc)); 2427 PetscCall(DMDestroy(&dmc)); 2428 PetscCall(DMSwarmSortRestorePointsPerCell(sw, cellID, &particles, &pids)); 2429 PetscFunctionReturn(PETSC_SUCCESS); 2430 } 2431 2432 /*@ 2433 DMSwarmComputeMoments - Compute the first three particle moments for a given field 2434 2435 Noncollective 2436 2437 Input Parameters: 2438 + sw - the `DMSWARM` 2439 . coordinate - the coordinate field name 2440 - weight - the weight field name 2441 2442 Output Parameter: 2443 . moments - the field moments 2444 2445 Level: intermediate 2446 2447 Notes: 2448 The `moments` array should be of length bs + 2, where bs is the block size of the coordinate field. 2449 2450 The weight field must be a scalar, having blocksize 1. 2451 2452 .seealso: `DM`, `DMSWARM`, `DMPlexComputeMoments()` 2453 @*/ 2454 PetscErrorCode DMSwarmComputeMoments(DM sw, const char coordinate[], const char weight[], PetscReal moments[]) 2455 { 2456 const PetscReal *coords; 2457 const PetscReal *w; 2458 PetscReal *mom; 2459 PetscDataType dtc, dtw; 2460 PetscInt bsc, bsw, Np; 2461 MPI_Comm comm; 2462 2463 PetscFunctionBegin; 2464 PetscValidHeaderSpecific(sw, DM_CLASSID, 1); 2465 PetscAssertPointer(coordinate, 2); 2466 PetscAssertPointer(weight, 3); 2467 PetscAssertPointer(moments, 4); 2468 PetscCall(PetscObjectGetComm((PetscObject)sw, &comm)); 2469 PetscCall(DMSwarmGetField(sw, coordinate, &bsc, &dtc, (void **)&coords)); 2470 PetscCall(DMSwarmGetField(sw, weight, &bsw, &dtw, (void **)&w)); 2471 PetscCheck(dtc == PETSC_REAL, comm, PETSC_ERR_ARG_WRONG, "Coordinate field %s must be real, not %s", coordinate, PetscDataTypes[dtc]); 2472 PetscCheck(dtw == PETSC_REAL, comm, PETSC_ERR_ARG_WRONG, "Weight field %s must be real, not %s", weight, PetscDataTypes[dtw]); 2473 PetscCheck(bsw == 1, comm, PETSC_ERR_ARG_WRONG, "Weight field %s must be a scalar, not blocksize %" PetscInt_FMT, weight, bsw); 2474 PetscCall(DMSwarmGetLocalSize(sw, &Np)); 2475 PetscCall(DMGetWorkArray(sw, bsc + 2, MPIU_REAL, &mom)); 2476 PetscCall(PetscArrayzero(mom, bsc + 2)); 2477 for (PetscInt p = 0; p < Np; ++p) { 2478 const PetscReal *c = &coords[p * bsc]; 2479 const PetscReal wp = w[p]; 2480 2481 mom[0] += wp; 2482 for (PetscInt d = 0; d < bsc; ++d) { 2483 mom[d + 1] += wp * c[d]; 2484 mom[d + bsc + 1] += wp * PetscSqr(c[d]); 2485 } 2486 } 2487 PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&coords)); 2488 PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w)); 2489 PetscCallMPI(MPIU_Allreduce(mom, moments, bsc + 2, MPIU_REAL, MPI_SUM, PetscObjectComm((PetscObject)sw))); 2490 PetscCall(DMRestoreWorkArray(sw, bsc + 2, MPIU_REAL, &mom)); 2491 PetscFunctionReturn(PETSC_SUCCESS); 2492 } 2493 2494 static PetscErrorCode DMSetFromOptions_Swarm(DM dm, PetscOptionItems PetscOptionsObject) 2495 { 2496 DM_Swarm *swarm = (DM_Swarm *)dm->data; 2497 2498 PetscFunctionBegin; 2499 PetscOptionsHeadBegin(PetscOptionsObject, "DMSwarm Options"); 2500 PetscCall(PetscOptionsEnum("-dm_swarm_remap_type", "Remap algorithm", "DMSwarmSetRemapType", DMSwarmRemapTypeNames, (PetscEnum)swarm->remap_type, (PetscEnum *)&swarm->remap_type, NULL)); 2501 PetscOptionsHeadEnd(); 2502 PetscFunctionReturn(PETSC_SUCCESS); 2503 } 2504 2505 PETSC_INTERN PetscErrorCode DMClone_Swarm(DM, DM *); 2506 2507 static PetscErrorCode DMInitialize_Swarm(DM sw) 2508 { 2509 PetscFunctionBegin; 2510 sw->ops->view = DMView_Swarm; 2511 sw->ops->load = NULL; 2512 sw->ops->setfromoptions = DMSetFromOptions_Swarm; 2513 sw->ops->clone = DMClone_Swarm; 2514 sw->ops->setup = DMSetup_Swarm; 2515 sw->ops->createlocalsection = NULL; 2516 sw->ops->createsectionpermutation = NULL; 2517 sw->ops->createdefaultconstraints = NULL; 2518 sw->ops->createglobalvector = DMCreateGlobalVector_Swarm; 2519 sw->ops->createlocalvector = DMCreateLocalVector_Swarm; 2520 sw->ops->getlocaltoglobalmapping = NULL; 2521 sw->ops->createfieldis = NULL; 2522 sw->ops->createcoordinatedm = NULL; 2523 sw->ops->getcoloring = NULL; 2524 sw->ops->creatematrix = DMCreateMatrix_Swarm; 2525 sw->ops->createinterpolation = NULL; 2526 sw->ops->createinjection = NULL; 2527 sw->ops->createmassmatrix = DMCreateMassMatrix_Swarm; 2528 sw->ops->refine = NULL; 2529 sw->ops->coarsen = NULL; 2530 sw->ops->refinehierarchy = NULL; 2531 sw->ops->coarsenhierarchy = NULL; 2532 sw->ops->globaltolocalbegin = NULL; 2533 sw->ops->globaltolocalend = NULL; 2534 sw->ops->localtoglobalbegin = NULL; 2535 sw->ops->localtoglobalend = NULL; 2536 sw->ops->destroy = DMDestroy_Swarm; 2537 sw->ops->createsubdm = NULL; 2538 sw->ops->getdimpoints = NULL; 2539 sw->ops->locatepoints = NULL; 2540 PetscFunctionReturn(PETSC_SUCCESS); 2541 } 2542 2543 PETSC_INTERN PetscErrorCode DMClone_Swarm(DM dm, DM *newdm) 2544 { 2545 DM_Swarm *swarm = (DM_Swarm *)dm->data; 2546 2547 PetscFunctionBegin; 2548 swarm->refct++; 2549 (*newdm)->data = swarm; 2550 PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMSWARM)); 2551 PetscCall(DMInitialize_Swarm(*newdm)); 2552 (*newdm)->dim = dm->dim; 2553 PetscFunctionReturn(PETSC_SUCCESS); 2554 } 2555 2556 /*MC 2557 DMSWARM = "swarm" - A `DM` object for particle methods, such as particle-in-cell (PIC), in which the underlying 2558 data is both (i) dynamic in length, (ii) and of arbitrary data type. 2559 2560 Level: intermediate 2561 2562 Notes: 2563 User data can be represented by `DMSWARM` through a registering "fields" which are to be stored on particles. 2564 To register a field, the user must provide; 2565 (a) a unique name; 2566 (b) the data type (or size in bytes); 2567 (c) the block size of the data. 2568 2569 For example, suppose the application requires a unique id, energy, momentum and density to be stored 2570 on a set of particles. Then the following code could be used 2571 .vb 2572 DMSwarmInitializeFieldRegister(dm) 2573 DMSwarmRegisterPetscDatatypeField(dm,"uid",1,PETSC_LONG); 2574 DMSwarmRegisterPetscDatatypeField(dm,"energy",1,PETSC_REAL); 2575 DMSwarmRegisterPetscDatatypeField(dm,"momentum",3,PETSC_REAL); 2576 DMSwarmRegisterPetscDatatypeField(dm,"density",1,PETSC_FLOAT); 2577 DMSwarmFinalizeFieldRegister(dm) 2578 .ve 2579 2580 The fields represented by `DMSWARM` are dynamic and can be re-sized at any time. 2581 The only restriction imposed by `DMSWARM` is that all fields contain the same number of particles. 2582 2583 To support particle methods, "migration" techniques are provided. These methods migrate data 2584 between ranks. 2585 2586 `DMSWARM` supports the methods `DMCreateGlobalVector()` and `DMCreateLocalVector()`. 2587 As a `DMSWARM` may internally define and store values of different data types, 2588 before calling `DMCreateGlobalVector()` or `DMCreateLocalVector()`, the user must inform `DMSWARM` which 2589 fields should be used to define a `Vec` object via `DMSwarmVectorDefineField()` 2590 The specified field can be changed at any time - thereby permitting vectors 2591 compatible with different fields to be created. 2592 2593 A dual representation of fields in the `DMSWARM` and a Vec object is permitted via `DMSwarmCreateGlobalVectorFromField()` 2594 Here the data defining the field in the `DMSWARM` is shared with a `Vec`. 2595 This is inherently unsafe if you alter the size of the field at any time between 2596 calls to `DMSwarmCreateGlobalVectorFromField()` and `DMSwarmDestroyGlobalVectorFromField()`. 2597 If the local size of the `DMSWARM` does not match the local size of the global vector 2598 when `DMSwarmDestroyGlobalVectorFromField()` is called, an error is thrown. 2599 2600 Additional high-level support is provided for Particle-In-Cell methods. Refer to `DMSwarmSetType()`. 2601 2602 .seealso: `DM`, `DMSWARM`, `DMType`, `DMCreate()`, `DMSetType()`, `DMSwarmSetType()`, `DMSwarmType`, `DMSwarmCreateGlobalVectorFromField()`, 2603 `DMCreateGlobalVector()`, `DMCreateLocalVector()` 2604 M*/ 2605 2606 PETSC_EXTERN PetscErrorCode DMCreate_Swarm(DM dm) 2607 { 2608 DM_Swarm *swarm; 2609 2610 PetscFunctionBegin; 2611 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2612 PetscCall(PetscNew(&swarm)); 2613 dm->data = swarm; 2614 PetscCall(DMSwarmDataBucketCreate(&swarm->db)); 2615 PetscCall(DMSwarmInitializeFieldRegister(dm)); 2616 dm->dim = 0; 2617 swarm->refct = 1; 2618 swarm->issetup = PETSC_FALSE; 2619 swarm->swarm_type = DMSWARM_BASIC; 2620 swarm->migrate_type = DMSWARM_MIGRATE_BASIC; 2621 swarm->collect_type = DMSWARM_COLLECT_BASIC; 2622 swarm->migrate_error_on_missing_point = PETSC_FALSE; 2623 swarm->collect_view_active = PETSC_FALSE; 2624 swarm->collect_view_reset_nlocal = -1; 2625 PetscCall(DMInitialize_Swarm(dm)); 2626 if (SwarmDataFieldId == -1) PetscCall(PetscObjectComposedDataRegister(&SwarmDataFieldId)); 2627 PetscFunctionReturn(PETSC_SUCCESS); 2628 } 2629 2630 /* Replace dm with the contents of ndm, and then destroy ndm 2631 - Share the DM_Swarm structure 2632 */ 2633 PetscErrorCode DMSwarmReplace(DM dm, DM *ndm) 2634 { 2635 DM dmNew = *ndm; 2636 const PetscReal *maxCell, *Lstart, *L; 2637 PetscInt dim; 2638 2639 PetscFunctionBegin; 2640 if (dm == dmNew) { 2641 PetscCall(DMDestroy(ndm)); 2642 PetscFunctionReturn(PETSC_SUCCESS); 2643 } 2644 dm->setupcalled = dmNew->setupcalled; 2645 if (!dm->hdr.name) { 2646 const char *name; 2647 2648 PetscCall(PetscObjectGetName((PetscObject)*ndm, &name)); 2649 PetscCall(PetscObjectSetName((PetscObject)dm, name)); 2650 } 2651 PetscCall(DMGetDimension(dmNew, &dim)); 2652 PetscCall(DMSetDimension(dm, dim)); 2653 PetscCall(DMGetPeriodicity(dmNew, &maxCell, &Lstart, &L)); 2654 PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L)); 2655 PetscCall(DMDestroy_Swarm(dm)); 2656 PetscCall(DMInitialize_Swarm(dm)); 2657 dm->data = dmNew->data; 2658 ((DM_Swarm *)dmNew->data)->refct++; 2659 PetscCall(DMDestroy(ndm)); 2660 PetscFunctionReturn(PETSC_SUCCESS); 2661 } 2662 2663 /*@ 2664 DMSwarmDuplicate - Creates a new `DMSWARM` with the same fields and cell `DM`s but no particles 2665 2666 Collective 2667 2668 Input Parameter: 2669 . sw - the `DMSWARM` 2670 2671 Output Parameter: 2672 . nsw - the new `DMSWARM` 2673 2674 Level: beginner 2675 2676 .seealso: `DM`, `DMSWARM`, `DMSwarmCreate()`, `DMClone()` 2677 @*/ 2678 PetscErrorCode DMSwarmDuplicate(DM sw, DM *nsw) 2679 { 2680 DM_Swarm *swarm = (DM_Swarm *)sw->data; 2681 DMSwarmDataField *fields; 2682 DMSwarmCellDM celldm, ncelldm; 2683 DMSwarmType stype; 2684 const char *name, **celldmnames; 2685 void *ctx; 2686 PetscInt dim, Nf, Ndm; 2687 PetscBool flg; 2688 2689 PetscFunctionBegin; 2690 PetscCall(DMCreate(PetscObjectComm((PetscObject)sw), nsw)); 2691 PetscCall(DMSetType(*nsw, DMSWARM)); 2692 PetscCall(PetscObjectGetName((PetscObject)sw, &name)); 2693 PetscCall(PetscObjectSetName((PetscObject)*nsw, name)); 2694 PetscCall(DMGetDimension(sw, &dim)); 2695 PetscCall(DMSetDimension(*nsw, dim)); 2696 PetscCall(DMSwarmGetType(sw, &stype)); 2697 PetscCall(DMSwarmSetType(*nsw, stype)); 2698 PetscCall(DMGetApplicationContext(sw, &ctx)); 2699 PetscCall(DMSetApplicationContext(*nsw, ctx)); 2700 2701 PetscCall(DMSwarmDataBucketGetDMSwarmDataFields(swarm->db, &Nf, &fields)); 2702 for (PetscInt f = 0; f < Nf; ++f) { 2703 PetscCall(DMSwarmDataFieldStringInList(fields[f]->name, ((DM_Swarm *)(*nsw)->data)->db->nfields, (const DMSwarmDataField *)((DM_Swarm *)(*nsw)->data)->db->field, &flg)); 2704 if (!flg) PetscCall(DMSwarmRegisterPetscDatatypeField(*nsw, fields[f]->name, fields[f]->bs, fields[f]->petsc_type)); 2705 } 2706 2707 PetscCall(DMSwarmGetCellDMNames(sw, &Ndm, &celldmnames)); 2708 for (PetscInt c = 0; c < Ndm; ++c) { 2709 DM dm; 2710 PetscInt Ncf; 2711 const char **coordfields, **fields; 2712 2713 PetscCall(DMSwarmGetCellDMByName(sw, celldmnames[c], &celldm)); 2714 PetscCall(DMSwarmCellDMGetDM(celldm, &dm)); 2715 PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Ncf, &coordfields)); 2716 PetscCall(DMSwarmCellDMGetFields(celldm, &Nf, &fields)); 2717 PetscCall(DMSwarmCellDMCreate(dm, Nf, fields, Ncf, coordfields, &ncelldm)); 2718 PetscCall(DMSwarmAddCellDM(*nsw, ncelldm)); 2719 PetscCall(DMSwarmCellDMDestroy(&ncelldm)); 2720 } 2721 PetscCall(PetscFree(celldmnames)); 2722 2723 PetscCall(DMSetFromOptions(*nsw)); 2724 PetscCall(DMSetUp(*nsw)); 2725 PetscCall(DMSwarmGetCellDMActive(sw, &celldm)); 2726 PetscCall(PetscObjectGetName((PetscObject)celldm, &name)); 2727 PetscCall(DMSwarmSetCellDMActive(*nsw, name)); 2728 PetscFunctionReturn(PETSC_SUCCESS); 2729 } 2730