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