/* This function computes the local velocity dispersion * of each particle (among particles of the same type) */ void veldisp(void) { double vsum[3], v2sum[3]; double h, hinv, hinv3; double rho, wk; double dx, dy, dz, r, r2, u; int i,j,k,ii,n,count; float *r2list; int *ngblist; /* only active particles */ for(i=IndFirstUpdate,count=0; count<NumForceUpdate; i=P[i].ForceFlag, count++) { if(P[i].Type>0) { rho= vsum[0] = vsum[1] = vsum[2] = v2sum[0] = v2sum[1] = v2sum[2] = 0; P[i].HsmlVelDisp= sqrt(ngb_treefind(P[i].PosPred, All.DesNumNgb, 1.1*P[i].HsmlVelDisp, P[i].Type, &ngblist, &r2list)); h = P[i].HsmlVelDisp; hinv = 1.0/h; hinv3 = hinv*hinv*hinv; for(n=0; n<All.DesNumNgb; n++) { j = ngblist[n]+1; dx = P[i].PosPred[0] - P[j].PosPred[0]; dy = P[i].PosPred[1] - P[j].PosPred[1]; dz = P[i].PosPred[2] - P[j].PosPred[2]; #ifdef PERIODIC dx= periodic(dx); dy= periodic(dy); dz= periodic(dz); #endif r2 = dx*dx + dy*dy + dz*dz; r = sqrt(r2); if(r<h) { u = r*hinv; ii = (int)(u*KERNEL_TABLE); wk =hinv3*( Kernel[ii] + (Kernel[ii+1]-Kernel[ii])*(u-KernelRad[ii])*KERNEL_TABLE); rho += P[j].Mass * wk; } for(k=0; k<3; k++) { vsum[k] += P[j].VelPred[k]; v2sum[k] += P[j].VelPred[k]*P[j].VelPred[k]; } } P[i].DensVelDisp = rho; P[i].VelDisp = 0; for(k=0; k<3; k++) { vsum[k] /= All.DesNumNgb; v2sum[k]/= All.DesNumNgb; P[i].VelDisp += v2sum[k] - vsum[k]*vsum[k]; } if(P[i].VelDisp > 0) P[i].VelDisp= sqrt(P[i].VelDisp); else P[i].VelDisp= 0; } } }
/* the function below detects particles that have a number of neighbours * outside the allowed tolerance range. For these, particles the smoothing * length is adjusted accordingly. Note that the smoothing length is */ void sidm_ensure_neighbours(int mode) { #define MAXITER 30 int i, ntot, last=0; float *r2list; int *ngblist, count, candidates; int iter=0; double save; /* int IndFirstUpdateBackup, NumForceUpdateBackup; IndFirstUpdateBackup= IndFirstUpdate; NumForceUpdateBackup= NumForceUpdate; for(i=IndFirstUpdate, count=0; count<NumForceUpdate; i=P[i].ForceFlag, count++){ P[i].ForceFlagBackup= P[i].ForceFlag; } */ for(i=IndFirstUpdate, count=0, candidates=0; count<NumForceUpdate; i=P[i].ForceFlag, count++) { if(P[i].Type>0) { if(P[i].NgbVelDisp < (All.DesNumNgb-All.MaxNumNgbDeviation) || (P[i].NgbVelDisp > (All.DesNumNgb+All.MaxNumNgbDeviation))) candidates++; } } MPI_Reduce(&candidates, &ntot, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); MPI_Bcast(&ntot, 1, MPI_INT, 0, MPI_COMM_WORLD); if(ntot > 0) { //#ifdef FINDNBRLOG // if(ThisTask==0) //{ //printf("\n%d particles have too few/too many neighbours in sidm calculation!\n", ntot); // printf("Now fixing that...\n"); // } //#endif for(i=IndFirstUpdate, count=0; count<NumForceUpdate; i=P[i].ForceFlag, count++) P[i].Left= P[i].Right= 0; do { for(i=1+N_gas, NumForceUpdate= 0, NumSphUpdate=0; i<=NumPart; i++) { if( P[i].NgbVelDisp < (All.DesNumNgb-All.MaxNumNgbDeviation) || P[i].NgbVelDisp > (All.DesNumNgb+All.MaxNumNgbDeviation)) { if(P[i].Left>0 && P[i].Right>0) if((P[i].Right-P[i].Left) < 1.0e-3 * P[i].Left) continue; if(NumForceUpdate==0) IndFirstUpdate= i; else P[last].ForceFlag= i; NumForceUpdate++; last=i; if(P[i].NgbVelDisp < (All.DesNumNgb-All.MaxNumNgbDeviation)) P[i].Left= dmax(P[i].HsmlVelDisp, P[i].Left); else if(P[i].Right!=0) { if(P[i].HsmlVelDisp<P[i].Right) P[i].Right= P[i].HsmlVelDisp; } else P[i].Right= P[i].HsmlVelDisp; } } MPI_Allreduce(&NumForceUpdate, &ntot, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); if(ntot > 0) { //#ifdef FINDNBRLOG // if(ThisTask==0) //printf("ngb iteration %d. still %d particles\n", iter, ntot); //#endif for(i=IndFirstUpdate, count=0; count<NumForceUpdate; i=P[i].ForceFlag, count++) { if(iter >= 20) { printf("i=%d ID=%d Hsml=%g Left=%g Right=%g Ngbs=%d Right-Left=%g\n pos=(%g|%g|%g)\n", i, P[i].ID, P[i].HsmlVelDisp, P[i].Left, P[i].Right, P[i].NgbVelDisp, P[i].Right-P[i].Left, P[i].PosPred[0], P[i].PosPred[1], P[i].PosPred[2]); } if(iter == MAXITER) { printf("ThisTask=%d Mi=(%g|%g|%g) Ma=(%g|%g|%g)\n", ThisTask, DomainMin[P[i].Type][0], DomainMin[P[i].Type][1], DomainMin[P[i].Type][2], DomainMax[P[i].Type][0], DomainMax[P[i].Type][1], DomainMax[P[i].Type][2]); printf("i=%d ID=%d coord=(%g|%g|%g)\n", i, P[i].ID, P[i].PosPred[0], P[i].PosPred[1], P[i].PosPred[2]); printf("ngb_treefind= %g\n", sqrt(ngb_treefind(P[i].PosPred , All.DesNumNgb, 0, P[i].Type, &ngblist, &r2list))); } if(P[i].Left==0 || P[i].Right==0) { if(P[i].Right==0 && P[i].NgbVelDisp<15 && NtypeLocal[P[i].Type]>All.DesNumNgb) { P[i].HsmlVelDisp= sqrt(ngb_treefind(P[i].PosPred, All.DesNumNgb, 0, P[i].Type, &ngblist, &r2list)); } else { P[i].HsmlVelDisp= P[i].HsmlVelDisp*( 0.5 + 0.5*pow(P[i].NgbVelDisp/((double)All.DesNumNgb), -1.0/3)); } } else { P[i].HsmlVelDisp= 0.5*(P[i].Left + P[i].Right); } } sidm(); iter++; if(iter > MAXITER) { fprintf(stdout, "failed to converge in function ensure_neighbours()\n"); endrun(1155); } } } while(ntot > 0); if(mode == 0) { /* restore timeline to active particles */ /* IndFirstUpdate= IndFirstUpdateBackup; NumForceUpdate= NumForceUpdateBackup; for(i=IndFirstUpdateBackup, count=0; count<NumForceUpdateBackup; i=P[i].ForceFlagBackup, count++){ P[i].ForceFlag= P[i].ForceFlagBackup; } */ save= All.TimeStep; find_next_time(); All.TimeStep= save; } else { /* make all particles active again */ for(i=1; i<=NumPart; i++) P[i].ForceFlag=i+1; P[NumPart].ForceFlag=1; IndFirstUpdate=1; NumForceUpdate=NumPart; NumSphUpdate=N_gas; } } #undef MAXITER }