static char help[] = "Example program demonstrating projection between particle and finite element spaces using OpenMP in 2D cylindrical coordinates\n"; #include "petscdmplex.h" #include "petscds.h" #include "petscdmswarm.h" #include "petscksp.h" #include #if defined(PETSC_HAVE_OPENMP) && defined(PETSC_HAVE_THREADSAFETY) #include #endif typedef struct { Mat MpTrans; Mat Mp; Vec ff; Vec uu; } MatShellCtx; PetscErrorCode MatMultMtM_SeqAIJ(Mat MtM,Vec xx,Vec yy) { MatShellCtx *matshellctx; PetscFunctionBeginUser; CHKERRQ(MatShellGetContext(MtM,&matshellctx)); PetscCheck(matshellctx,PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "No context"); CHKERRQ(MatMult(matshellctx->Mp, xx, matshellctx->ff)); CHKERRQ(MatMult(matshellctx->MpTrans, matshellctx->ff, yy)); PetscFunctionReturn(0); } PetscErrorCode MatMultAddMtM_SeqAIJ(Mat MtM,Vec xx, Vec yy, Vec zz) { MatShellCtx *matshellctx; PetscFunctionBeginUser; CHKERRQ(MatShellGetContext(MtM,&matshellctx)); PetscCheck(matshellctx,PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "No context"); CHKERRQ(MatMult(matshellctx->Mp, xx, matshellctx->ff)); CHKERRQ(MatMultAdd(matshellctx->MpTrans, matshellctx->ff, yy, zz)); PetscFunctionReturn(0); } PetscErrorCode createSwarm(const DM dm, DM *sw) { PetscInt Nc = 1, dim = 2; PetscFunctionBeginUser; CHKERRQ(DMCreate(PETSC_COMM_SELF, sw)); CHKERRQ(DMSetType(*sw, DMSWARM)); CHKERRQ(DMSetDimension(*sw, dim)); CHKERRQ(DMSwarmSetType(*sw, DMSWARM_PIC)); CHKERRQ(DMSwarmSetCellDM(*sw, dm)); CHKERRQ(DMSwarmRegisterPetscDatatypeField(*sw, "w_q", Nc, PETSC_SCALAR)); CHKERRQ(DMSwarmFinalizeFieldRegister(*sw)); CHKERRQ(DMSetFromOptions(*sw)); PetscFunctionReturn(0); } PetscErrorCode gridToParticles(const DM dm, DM sw, PetscReal *moments, Vec rhs, Mat M_p) { PetscBool is_lsqr; KSP ksp; Mat PM_p=NULL,MtM,D; Vec ff; PetscInt Np, timestep = 0, bs, N, M, nzl; PetscReal time = 0.0; PetscDataType dtype; MatShellCtx *matshellctx; PetscFunctionBeginUser; CHKERRQ(KSPCreate(PETSC_COMM_SELF, &ksp)); CHKERRQ(KSPSetOptionsPrefix(ksp, "ftop_")); CHKERRQ(KSPSetFromOptions(ksp)); CHKERRQ(PetscObjectTypeCompare((PetscObject)ksp,KSPLSQR,&is_lsqr)); if (!is_lsqr) { CHKERRQ(MatGetLocalSize(M_p, &M, &N)); if (N>M) { PC pc; CHKERRQ(PetscInfo(ksp, " M (%D) < M (%D) -- skip revert to lsqr\n",M,N)); is_lsqr = PETSC_TRUE; CHKERRQ(KSPSetType(ksp,KSPLSQR)); CHKERRQ(KSPGetPC(ksp,&pc)); CHKERRQ(PCSetType(pc,PCNONE)); // could put in better solver -ftop_pc_type bjacobi -ftop_sub_pc_type lu -ftop_sub_pc_factor_shift_type nonzero } else { CHKERRQ(PetscNew(&matshellctx)); CHKERRQ(MatCreateShell(PetscObjectComm((PetscObject)dm),N,N,PETSC_DECIDE,PETSC_DECIDE,matshellctx,&MtM)); CHKERRQ(MatTranspose(M_p,MAT_INITIAL_MATRIX,&matshellctx->MpTrans)); matshellctx->Mp = M_p; CHKERRQ(MatShellSetOperation(MtM, MATOP_MULT, (void (*)(void))MatMultMtM_SeqAIJ)); CHKERRQ(MatShellSetOperation(MtM, MATOP_MULT_ADD, (void (*)(void))MatMultAddMtM_SeqAIJ)); CHKERRQ(MatCreateVecs(M_p,&matshellctx->uu,&matshellctx->ff)); CHKERRQ(MatCreateSeqAIJ(PETSC_COMM_SELF,N,N,1,NULL,&D)); for (int i=0 ; iMpTrans,i,&nzl,&cols,&vals)); for (int ii=0 ; iiMpTrans,NULL,"-ftop2_MpTranspose_mat_view")); } } if (is_lsqr) { PC pc; PetscBool is_bjac; CHKERRQ(KSPGetPC(ksp,&pc)); CHKERRQ(PetscObjectTypeCompare((PetscObject)pc,PCBJACOBI,&is_bjac)); if (is_bjac) { CHKERRQ(DMSwarmCreateMassMatrixSquare(sw, dm, &PM_p)); CHKERRQ(KSPSetOperators(ksp, M_p, PM_p)); } else { CHKERRQ(KSPSetOperators(ksp, M_p, M_p)); } } CHKERRQ(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &ff)); // this grabs access !!!!! if (!is_lsqr) { CHKERRQ(KSPSolve(ksp, rhs, matshellctx->uu)); CHKERRQ(MatMult(M_p, matshellctx->uu, ff)); CHKERRQ(MatDestroy(&matshellctx->MpTrans)); CHKERRQ(VecDestroy(&matshellctx->ff)); CHKERRQ(VecDestroy(&matshellctx->uu)); CHKERRQ(MatDestroy(&D)); CHKERRQ(MatDestroy(&MtM)); CHKERRQ(PetscFree(matshellctx)); } else { CHKERRQ(KSPSolveTranspose(ksp, rhs, ff)); } CHKERRQ(KSPDestroy(&ksp)); /* Visualize particle field */ CHKERRQ(DMSetOutputSequenceNumber(sw, timestep, time)); CHKERRQ(VecViewFromOptions(ff, NULL, "-weights_view")); CHKERRQ(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &ff)); /* compute energy */ if (moments) { PetscReal *wq, *coords; CHKERRQ(DMSwarmGetLocalSize(sw,&Np)); CHKERRQ(DMSwarmGetField(sw, "w_q", &bs, &dtype, (void**)&wq)); CHKERRQ(DMSwarmGetField(sw, "DMSwarmPIC_coor", &bs, &dtype, (void**)&coords)); moments[0] = moments[1] = moments[2] = 0; for (int p=0;pMAX_NUM_THRDS,PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Too many threads %D > %D", numthreads, MAX_NUM_THRDS); PetscCheckFalse(numthreads<=0,PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "No threads %D > %D ", numthreads, MAX_NUM_THRDS); #endif if (target >= numthreads) target = numthreads-1; CHKERRQ(PetscLogEventRegister("Create Swarm", DM_CLASSID, &swarm_create_ev)); CHKERRQ(PetscLogEventRegister("Single solve", DM_CLASSID, &solve_ev)); CHKERRQ(PetscLogEventRegister("Solve loop", DM_CLASSID, &solve_loop_ev)); CHKERRQ(PetscLogStageRegister("Solve", &stage)); i = dim; CHKERRQ(PetscOptionsGetIntArray(NULL, NULL, "-dm_plex_box_faces", faces, &i, NULL)); i = dim; CHKERRQ(PetscOptionsGetIntArray(NULL, NULL, "-np", Np, &i, NULL)); /* Create thread meshes */ for (int tid=0; tid