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