#define PETSCDM_DLL #include /*I "petscdmswarm.h" I*/ #include #include #include #include "data_bucket.h" /* Error chceking macto to ensure the swarm type is correct and that a cell DM has been set */ #define DMSWARMPICVALID(dm) \ { \ DM_Swarm *_swarm = (DM_Swarm*)(dm)->data; \ if (_swarm->swarm_type != DMSWARM_PIC) SETERRQ(PetscObjectComm((PetscObject)(dm)),PETSC_ERR_SUP,"Only valid for DMSwarm-PIC. You must call DMSwarmSetType(dm,DMSWARM_PIC)"); \ else \ if (!_swarm->dmcell) SETERRQ(PetscObjectComm((PetscObject)(dm)),PETSC_ERR_SUP,"Only valid for DMSwarmPIC if the cell DM is set. You must call DMSwarmSetCellDM(dm,celldm)"); \ } /* Coordinate insertition/addition API */ /*@C DMSwarmSetPointsUniformCoordinates - Set point coordinates in a DMSwarm on a regular (ijk) grid Collective on DM Input parameters: + dm - the DMSwarm . min - minimum coordinate values in the x, y, z directions (array of length dim) . max - maximum coordinate values in the x, y, z directions (array of length dim) . npoints - number of points in each spatial direction (array of length dim) - mode - indicates whether to append points to the swarm (ADD_VALUES), or over-ride existing points (INSERT_VALUES) Level: beginner Notes: When using mode = INSERT_VALUES, this method will reset the number of particles in the DMSwarm to be npoints[0]*npoints[1] (2D) or npoints[0]*npoints[1]*npoints[2] (3D). When using mode = ADD_VALUES, new points will be appended to any already existing in the DMSwarm .seealso: DMSwarmSetType(), DMSwarmSetCellDM(), DMSwarmType @*/ PETSC_EXTERN PetscErrorCode DMSwarmSetPointsUniformCoordinates(DM dm,PetscReal min[],PetscReal max[],PetscInt npoints[],InsertMode mode) { PetscErrorCode ierr; PetscReal gmin[] = {PETSC_MAX_REAL ,PETSC_MAX_REAL, PETSC_MAX_REAL}; PetscReal gmax[] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; PetscInt i,j,k,N,bs,b,n_estimate,n_curr,n_new_est,p,n_found; Vec coorlocal; const PetscScalar *_coor; DM celldm; PetscReal dx[3]; PetscInt _npoints[] = { 0, 0, 1 }; Vec pos; PetscScalar *_pos; PetscReal *swarm_coor; PetscInt *swarm_cellid; PetscSF sfcell = NULL; const PetscSFNode *LA_sfcell; PetscFunctionBegin; DMSWARMPICVALID(dm); ierr = DMSwarmGetCellDM(dm,&celldm);CHKERRQ(ierr); ierr = DMGetCoordinatesLocal(celldm,&coorlocal);CHKERRQ(ierr); ierr = VecGetSize(coorlocal,&N);CHKERRQ(ierr); ierr = VecGetBlockSize(coorlocal,&bs);CHKERRQ(ierr); N = N / bs; ierr = VecGetArrayRead(coorlocal,&_coor);CHKERRQ(ierr); for (i=0; i 1) { dx[b] = (max[b] - min[b])/((PetscReal)(npoints[b]-1)); } else { dx[b] = 0.0; } _npoints[b] = npoints[b]; } /* determine number of points living in the bounding box */ n_estimate = 0; for (k=0; k<_npoints[2]; k++) { for (j=0; j<_npoints[1]; j++) { for (i=0; i<_npoints[0]; i++) { PetscReal xp[] = {0.0,0.0,0.0}; PetscInt ijk[3]; PetscBool point_inside = PETSC_TRUE; ijk[0] = i; ijk[1] = j; ijk[2] = k; for (b=0; b gmax[b]) { point_inside = PETSC_FALSE; } } if (point_inside) { n_estimate++; } } } } /* create candidate list */ ierr = VecCreate(PETSC_COMM_SELF,&pos);CHKERRQ(ierr); ierr = VecSetSizes(pos,bs*n_estimate,PETSC_DECIDE);CHKERRQ(ierr); ierr = VecSetBlockSize(pos,bs);CHKERRQ(ierr); ierr = VecSetFromOptions(pos);CHKERRQ(ierr); ierr = VecGetArray(pos,&_pos);CHKERRQ(ierr); n_estimate = 0; for (k=0; k<_npoints[2]; k++) { for (j=0; j<_npoints[1]; j++) { for (i=0; i<_npoints[0]; i++) { PetscReal xp[] = {0.0,0.0,0.0}; PetscInt ijk[3]; PetscBool point_inside = PETSC_TRUE; ijk[0] = i; ijk[1] = j; ijk[2] = k; for (b=0; b gmax[b]) { point_inside = PETSC_FALSE; } } if (point_inside) { for (b=0; b 0) { /* allocate space */ ierr = PetscMalloc1(bs*my_npoints,&my_coor);CHKERRQ(ierr); } else { my_coor = coor; } ierr = MPI_Bcast(my_coor,bs*my_npoints,MPIU_REAL,0,comm);CHKERRQ(ierr); } else { my_npoints = npoints; my_coor = coor; } /* determine the number of points living in the bounding box */ n_estimate = 0; for (i=0; i gmax[b]) { point_inside = PETSC_FALSE; } } if (point_inside) { n_estimate++; } } /* create candidate list */ ierr = VecCreate(PETSC_COMM_SELF,&pos);CHKERRQ(ierr); ierr = VecSetSizes(pos,bs*n_estimate,PETSC_DECIDE);CHKERRQ(ierr); ierr = VecSetBlockSize(pos,bs);CHKERRQ(ierr); ierr = VecSetFromOptions(pos);CHKERRQ(ierr); ierr = VecGetArray(pos,&_pos);CHKERRQ(ierr); n_estimate = 0; for (i=0; i gmax[b]) { point_inside = PETSC_FALSE; } } if (point_inside) { for (b=0; b 0) { ierr = PetscFree(my_coor);CHKERRQ(ierr); } } ierr = PetscSFDestroy(&sfcell);CHKERRQ(ierr); ierr = VecDestroy(&pos);CHKERRQ(ierr); PetscFunctionReturn(0); } extern PetscErrorCode private_DMSwarmInsertPointsUsingCellDM_DA(DM,DM,DMSwarmPICLayoutType,PetscInt); extern PetscErrorCode private_DMSwarmInsertPointsUsingCellDM_PLEX(DM,DM,DMSwarmPICLayoutType,PetscInt); /*@C DMSwarmInsertPointsUsingCellDM - Insert point coordinates within each cell Not collective Input parameters: + dm - the DMSwarm . layout_type - method used to fill each cell with the cell DM - fill_param - parameter controlling how many points per cell are added (the meaning of this parameter is dependent on the layout type) Level: beginner Notes: The insert method will reset any previous defined points within the DMSwarm. When using a DMDA both 2D and 3D are supported for all layout types provided you are using DMDA_ELEMENT_Q1. When using a DMPLEX the following case are supported: (i ) DMSWARMPIC_LAYOUT_REGULAR: 2D (triangle), (ii ) DMSWARMPIC_LAYOUT_GAUSS: 2D and 3D provided the cell is a tri/tet or a quad/hex, (iii) DMSWARMPIC_LAYOUT_SUBDIVISION: 2D and 3D for quad/hex and 2D tri. .seealso: DMSwarmPICLayoutType, DMSwarmSetType(), DMSwarmSetCellDM(), DMSwarmType @*/ PETSC_EXTERN PetscErrorCode DMSwarmInsertPointsUsingCellDM(DM dm,DMSwarmPICLayoutType layout_type,PetscInt fill_param) { PetscErrorCode ierr; DM celldm; PetscBool isDA,isPLEX; PetscFunctionBegin; DMSWARMPICVALID(dm); ierr = DMSwarmGetCellDM(dm,&celldm);CHKERRQ(ierr); ierr = PetscObjectTypeCompare((PetscObject)celldm,DMDA,&isDA);CHKERRQ(ierr); ierr = PetscObjectTypeCompare((PetscObject)celldm,DMPLEX,&isPLEX);CHKERRQ(ierr); if (isDA) { ierr = private_DMSwarmInsertPointsUsingCellDM_DA(dm,celldm,layout_type,fill_param);CHKERRQ(ierr); } else if (isPLEX) { ierr = private_DMSwarmInsertPointsUsingCellDM_PLEX(dm,celldm,layout_type,fill_param);CHKERRQ(ierr); } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Only supported for cell DMs of type DMDA and DMPLEX"); PetscFunctionReturn(0); } extern PetscErrorCode private_DMSwarmSetPointCoordinatesCellwise_PLEX(DM,DM,PetscInt,PetscReal*); /*@C DMSwarmSetPointCoordinatesCellwise - Insert point coordinates (defined over the reference cell) within each cell Not collective Input parameters: + dm - the DMSwarm . celldm - the cell DM . npoints - the number of points to insert in each cell - xi - the coordinates (defined in the local coordinate system for each cell) to insert Level: beginner Notes: The method will reset any previous defined points within the DMSwarm. Only supported for DMPLEX. If you are using a DMDA it is recommended to either use DMSwarmInsertPointsUsingCellDM(), or extract and set the coordinates yourself the following code $ PetscReal *coor; $ DMSwarmGetField(dm,DMSwarmPICField_coor,NULL,NULL,(void**)&coor); $ // user code to define the coordinates here $ DMSwarmRestoreField(dm,DMSwarmPICField_coor,NULL,NULL,(void**)&coor); .seealso: DMSwarmSetCellDM(), DMSwarmInsertPointsUsingCellDM() @*/ PETSC_EXTERN PetscErrorCode DMSwarmSetPointCoordinatesCellwise(DM dm,PetscInt npoints,PetscReal xi[]) { PetscErrorCode ierr; DM celldm; PetscBool isDA,isPLEX; PetscFunctionBegin; DMSWARMPICVALID(dm); ierr = DMSwarmGetCellDM(dm,&celldm);CHKERRQ(ierr); ierr = PetscObjectTypeCompare((PetscObject)celldm,DMDA,&isDA);CHKERRQ(ierr); ierr = PetscObjectTypeCompare((PetscObject)celldm,DMPLEX,&isPLEX);CHKERRQ(ierr); if (isDA) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Only supported for cell DMs of type DMPLEX. Recommended you use DMSwarmInsertPointsUsingCellDM()"); else if (isPLEX) { ierr = private_DMSwarmSetPointCoordinatesCellwise_PLEX(dm,celldm,npoints,xi);CHKERRQ(ierr); } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Only supported for cell DMs of type DMDA and DMPLEX"); PetscFunctionReturn(0); } /* Field projection API */ extern PetscErrorCode private_DMSwarmProjectFields_DA(DM swarm,DM celldm,PetscInt project_type,PetscInt nfields,DataField dfield[],Vec vecs[]); extern PetscErrorCode private_DMSwarmProjectFields_PLEX(DM swarm,DM celldm,PetscInt project_type,PetscInt nfields,DataField dfield[],Vec vecs[]); /*@C DMSwarmProjectFields - Project a set of swarm fields onto the cell DM Collective on Vec Input parameters: + dm - the DMSwarm . nfields - the number of swarm fields to project . fieldnames - the textual names of the swarm fields to project . fields - an array of Vec's of length nfields - reuse - flag indicating whether the array and contents of fields should be re-used or internally allocated Currently, the only available projection method consists of phi_i = \sum_{p=0}^{np} N_i(x_p) phi_p dJ / \sum_{p=0}^{np} N_i(x_p) dJ where phi_p is the swarm field at point p, N_i() is the cell DM basis function at vertex i, dJ is the determinant of the cell Jacobian and phi_i is the projected vertex value of the field phi. Level: beginner Notes: If reuse = PETSC_FALSE, this function will allocate the array of Vec's, and each individual Vec. The user is responsible for destroying both the array and the individual Vec objects. Only swarm fields registered with data type = PETSC_REAL can be projected onto the cell DM. Only swarm fields of block size = 1 can currently be projected. The only projection methods currently only support the DA (2D) and PLEX (triangles 2D). .seealso: DMSwarmSetType(), DMSwarmSetCellDM(), DMSwarmType @*/ PETSC_EXTERN PetscErrorCode DMSwarmProjectFields(DM dm,PetscInt nfields,const char *fieldnames[],Vec **fields,PetscBool reuse) { DM_Swarm *swarm = (DM_Swarm*)dm->data; DataField *gfield; DM celldm; PetscBool isDA,isPLEX; Vec *vecs; PetscInt f,nvecs; PetscInt project_type = 0; PetscErrorCode ierr; PetscFunctionBegin; DMSWARMPICVALID(dm); ierr = DMSwarmGetCellDM(dm,&celldm);CHKERRQ(ierr); ierr = PetscMalloc1(nfields,&gfield);CHKERRQ(ierr); nvecs = 0; for (f=0; fdb,fieldnames[f],&gfield[f]);CHKERRQ(ierr); if (gfield[f]->petsc_type != PETSC_REAL) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Projection only valid for fields using a data type = PETSC_REAL"); if (gfield[f]->bs != 1) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Projection only valid for fields with block size = 1"); nvecs += gfield[f]->bs; } if (!reuse) { ierr = PetscMalloc1(nvecs,&vecs);CHKERRQ(ierr); for (f=0; fname);CHKERRQ(ierr); } } else { vecs = *fields; } ierr = PetscObjectTypeCompare((PetscObject)celldm,DMDA,&isDA);CHKERRQ(ierr); ierr = PetscObjectTypeCompare((PetscObject)celldm,DMPLEX,&isPLEX);CHKERRQ(ierr); if (isDA) { ierr = private_DMSwarmProjectFields_DA(dm,celldm,project_type,nfields,gfield,vecs);CHKERRQ(ierr); } else if (isPLEX) { ierr = private_DMSwarmProjectFields_PLEX(dm,celldm,project_type,nfields,gfield,vecs);CHKERRQ(ierr); } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Only supported for cell DMs of type DMDA and DMPLEX"); ierr = PetscFree(gfield);CHKERRQ(ierr); if (!reuse) { *fields = vecs; } PetscFunctionReturn(0); } /*@C DMSwarmCreatePointPerCellCount - Count the number of points within all cells in the cell DM Not collective Input parameter: . dm - the DMSwarm Output parameters: + ncells - the number of cells in the cell DM (optional argument, pass NULL to ignore) - count - array of length ncells containing the number of points per cell Level: beginner Notes: The array count is allocated internally and must be free'd by the user. .seealso: DMSwarmSetType(), DMSwarmSetCellDM(), DMSwarmType @*/ PETSC_EXTERN PetscErrorCode DMSwarmCreatePointPerCellCount(DM dm,PetscInt *ncells,PetscInt **count) { PetscErrorCode ierr; PetscBool isvalid; PetscInt nel; PetscInt *sum; PetscFunctionBegin; ierr = DMSwarmSortGetIsValid(dm,&isvalid);CHKERRQ(ierr); nel = 0; if (isvalid) { PetscInt e; ierr = DMSwarmSortGetSizes(dm,&nel,NULL);CHKERRQ(ierr); ierr = PetscMalloc1(nel,&sum);CHKERRQ(ierr); for (e=0; e