/* derive series expansion from random numbers. called every timestep, updating the seed */ void SCF_calc_from_random(long *seed) { int n, l, m; for (l=0; l<=SCF_LMAX; l++) for (m=0; m<=l; m++) for (n=0; n<=SCF_NMAX; n++) { sinsum[nlm(n,l,m)]=SCF_Hnml_rand(n,l,m,seed); cossum[nlm(n,l,m)]=SCF_Gnml_rand(n,l,m,seed); } }
/* set the expansion factors back to zero */ void SCF_reset(void) { int n, l, m; for (l=0; l<=SCF_LMAX; l++) for (m=0; m<=l; m++) for (n=0; n<=SCF_NMAX; n++) { sinsum[nlm(n,l,m)]=0.0; cossum[nlm(n,l,m)]=0.0; } }
/* write out coefficients and check potential + accelerations (note the scaling!) */ void SCF_collect_update(void) { int n, l, m; for (n=0; n<=SCF_NMAX; n++) { for (l=0; l<=SCF_LMAX; l++) { for (m=0; m<=l; m++) { sinsum[nlm(n,l,m)]=sinsum_all[nlm(n,l,m)]; cossum[nlm(n,l,m)]=cossum_all[nlm(n,l,m)]; } } } }
bool YlmRnlSet<GT>::add(int n, int l, int m, int s, value_type occ) { if(Restriction == "spin+space") { NLIndex nl(n,l); NL_Map_t::iterator it = NL.find(nl); ///if the orbital is new add it to the end of the list if(it == NL.end()) { ///assign the orbital a new id ID.push_back(NumUniqueOrb); ///the id counter is set to 1 IDcount.push_back(1); ///add a new element to the map NL[nl] = NumUniqueOrb; ///increment the number of unique orbitals NumUniqueOrb++; ///now add the radial grid orbital psi.push_back(RadialOrbital_t(m_grid)); ///add the quantum numbers to the list N.push_back(n); L.push_back(l); M.push_back(m); S.push_back(s); Occ.push_back(occ); } else { ///if an orbital of the same restriction type has already ///been added, add the orbital such that all the ///orbitals with the same restriction type are grouped ///together ///increment the id counter IDcount[(*it).second]++; ///locate the position in the array where the orbital ///will be added // IDmap.resize(IDcount.size()); vector<int> IDmap(IDcount.size()); IDmap[0] = 0; int sum = 0; for(int i=1; i < IDmap.size(); i++) { sum += IDcount[i-1]; IDmap[i] = sum; } ID.insert(ID.begin()+IDmap[(*it).second],(*it).second); psi.insert(psi.begin()+IDmap[(*it).second],RadialOrbital_t(m_grid)); N.insert(N.begin()+IDmap[(*it).second],n); L.insert(L.begin()+IDmap[(*it).second],l); M.insert(M.begin()+IDmap[(*it).second],m); S.insert(S.begin()+IDmap[(*it).second],s); Occ.insert(Occ.begin()+IDmap[(*it).second],occ); IDmap.clear(); } } if(Restriction == "spin") { NLMIndex nlm(n,l,m); NLM_Map_t::iterator it = NLM.find(nlm); if(it == NLM.end()) { ID.push_back(NumUniqueOrb); IDcount.push_back(1); NLM[nlm] = NumUniqueOrb; NumUniqueOrb++; psi.push_back(RadialOrbital_t(m_grid)); N.push_back(n); L.push_back(l); M.push_back(m); S.push_back(s); Occ.push_back(occ); } else { IDcount[(*it).second]++; vector<int> IDmap(IDcount.size()); // IDmap.resize(IDcount.size()); IDmap[0] = 0; int sum = 0; for(int i=1; i < IDmap.size(); i++) { sum += IDcount[i-1]; IDmap[i] = sum; } ID.insert(ID.begin()+IDmap[(*it).second],(*it).second); psi.insert(psi.begin()+IDmap[(*it).second],RadialOrbital_t(m_grid)); N.insert(N.begin()+IDmap[(*it).second],n); L.insert(L.begin()+IDmap[(*it).second],l); M.insert(M.begin()+IDmap[(*it).second],m); S.insert(S.begin()+IDmap[(*it).second],s); Occ.insert(Occ.begin()+IDmap[(*it).second],occ); IDmap.clear(); } } if(Restriction == "none") { ///add the orbital at the end of the list ID.push_back(NumUniqueOrb); IDcount.push_back(1); NumUniqueOrb++; psi.push_back(RadialOrbital_t(m_grid)); N.push_back(n); L.push_back(l); M.push_back(m); S.push_back(s); Occ.push_back(occ); } return true; }
/* write out coefficients and check potential + accelerations (note the scaling!) */ void SCF_write(int task) { int n, l, m; /* print selected task */ if (ThisTask == task) { for (n=0; n<=SCF_NMAX; n++) { for (l=0; l<=SCF_LMAX; l++) { for (m=0; m<=l; m++) { #ifdef SCF_SCALEFAC fprintf(FdSCF, "Step %d: Task: %d H[%d,%d,%d] = %g %g\n", All.NumCurrentTiStep, ThisTask, n, l, m, sinsum[nlm(n,l,m)], sinsum[nlm(n,l,m)]*scalefac_nlm[nlm(n,l,m)]); fprintf(FdSCF, "Step %d: Task: %d G[%d,%d,%d] = %g %g\n", All.NumCurrentTiStep, ThisTask, n, l, m, cossum[nlm(n,l,m)], cossum[nlm(n,l,m)]*scalefac_nlm[nlm(n,l,m)]); #else fprintf(FdSCF, "Step %d: Task: %d H[%d,%d,%d] = %g\n", All.NumCurrentTiStep, ThisTask, n, l, m, sinsum[nlm(n,l,m)]); fprintf(FdSCF, "Step %d: Task: %d G[%d,%d,%d] = %g\n", All.NumCurrentTiStep, ThisTask, n, l, m, cossum[nlm(n,l,m)]); #endif fflush(FdSCF); } } } } /* print all tasks */ if (-1 == task) { for (n=0; n<=SCF_NMAX; n++) { for (l=0; l<=SCF_LMAX; l++) { for (m=0; m<=l; m++) { #ifdef SCF_SCALEFAC fprintf(FdSCF, "Step %d: Task: %d H[%d,%d,%d] = %g %g\n", All.NumCurrentTiStep, ThisTask, n, l, m, sinsum[nlm(n,l,m)], sinsum[nlm(n,l,m)]*scalefac_nlm[nlm(n,l,m)]); fprintf(FdSCF, "Step %d: Task: %d G[%d,%d,%d] = %g %g\n", All.NumCurrentTiStep, ThisTask, n, l, m, cossum[nlm(n,l,m)], cossum[nlm(n,l,m)]*scalefac_nlm[nlm(n,l,m)]); #else fprintf(FdSCF, "Step %d: Task: %d H[%d,%d,%d] = %g\n", All.NumCurrentTiStep, ThisTask, n, l, m, sinsum[nlm(n,l,m)]); fprintf(FdSCF, "Step %d: Task: %d G[%d,%d,%d] = %g\n", All.NumCurrentTiStep, ThisTask, n, l, m, cossum[nlm(n,l,m)]); #endif fflush(FdSCF); } } } } }
/* SCF init routine */ void SCF_init(void) { int l, n, m; MyDouble K_nl, deltam0; Anltilde=(MyDouble*)mymalloc("Anltilde",(SCF_NMAX+1)*(SCF_LMAX+1)*sizeof(MyDouble)); coeflm=(MyDouble*)mymalloc("coeflm",(SCF_LMAX+1)*(SCF_LMAX+1)*sizeof(MyDouble)); cosmphi=(MyDouble*)mymalloc("cosmphi",(SCF_LMAX+1)*sizeof(MyDouble)); sinmphi=(MyDouble*)mymalloc("sinmphi",(SCF_LMAX+1)*sizeof(MyDouble)); ultrasp=(MyDouble*)mymalloc("ultrasp",(SCF_NMAX+1)*(SCF_LMAX+1)*sizeof(MyDouble)); ultraspt=(MyDouble*)mymalloc("ultraspt",(SCF_NMAX+1)*(SCF_LMAX+1)*sizeof(MyDouble)); ultrasp1=(MyDouble*)mymalloc("ultrasp1",(SCF_NMAX+1)*(SCF_LMAX+1)*sizeof(MyDouble)); plm=(MyDouble*)mymalloc("plm",(SCF_LMAX+1)*(SCF_LMAX+1)*sizeof(MyDouble)); dplm=(MyDouble*)mymalloc("dplm",(SCF_LMAX+1)*(SCF_LMAX+1)*sizeof(MyDouble)); dblfact=(MyDouble*)mymalloc("dblfact",(SCF_LMAX+1)*sizeof(MyDouble)); sinsum=(MyDouble*)mymalloc("sinsum",(SCF_NMAX+1)*(SCF_LMAX+1)*(SCF_LMAX+1)*sizeof(MyDouble)); cossum=(MyDouble*)mymalloc("cossum",(SCF_NMAX+1)*(SCF_LMAX+1)*(SCF_LMAX+1)*sizeof(MyDouble)); #ifdef SCF_HYBRID sinsum_all=(MyDouble*)mymalloc("sinsum_all",(SCF_NMAX+1)*(SCF_LMAX+1)*(SCF_LMAX+1)*sizeof(MyDouble)); cossum_all=(MyDouble*)mymalloc("cossum_all", (SCF_NMAX+1)*(SCF_LMAX+1)*(SCF_LMAX+1)*sizeof(MyDouble)); int i; /* store masses in backup field */ for (i = 0; i < NumPart; i++) P[i].MassBackup = P[i].Mass; #endif #ifdef SCF_SCALEFAC scalefac_nlm=(float*)mymalloc("sinsum_all",(SCF_NMAX+1)*(SCF_LMAX+1)*(SCF_LMAX+1)*sizeof(MyDouble)); FILE *fd; if(!(fd = fopen("scf_scalefac.dat", "r"))) { printf("Cannot read SCF scaling file `scf_scalefac.dat'\n"); endrun(10121); } for (n=0; n<=SCF_NMAX; n++) for (l=0; l<=SCF_LMAX; l++) for (m=0; m<=l; m++) fscanf(fd, "%g", (float*)&scalefac_nlm[nlm(n,l,m)]); fclose(fd); #ifdef DEBUG if (ThisTask == 0) for (n=0; n<=SCF_NMAX; n++) for (l=0; l<=SCF_LMAX; l++) for (m=0; m<=l; m++) printf("(%d,%d,%d) = %g\n", n,l,m,scalefac_nlm[nlm(n,l,m)]); #endif #endif Anltilde[0]=0.0; coeflm[0]=0.0; cosmphi[0]=0.0; sinmphi[0]=0.0; ultrasp[0]=0.0; ultraspt[0]=0.0; plm[0]=0.0; ultrasp1[0]=0.0; dplm[0]=0.0; dblfact[1]=1.; /* set initial random number seed (global variable, so that all processors generate the same potential */ scf_seed=42; for (l=2; l<=SCF_LMAX; l++) dblfact[l]=dblfact[l-1]*(2.*l-1.); for (n=0; n<=SCF_NMAX; n++) for (l=0; l<=SCF_LMAX; l++) Anltilde[nl(n,l)]=0.0; for (l=0; l<=SCF_LMAX; l++) for (m=0; m<=l; m++) coeflm[lm(l,m)]=0.0; for (n=0; n<=SCF_NMAX; n++) for (l=0; l<=SCF_LMAX; l++) { K_nl = 0.5*n*(n+4.*l+3.)+(l+1.)*(2.*l+1.); /* eq.(2.23) */ Anltilde[nl(n,l)]=-pow(2.,8.*l+6.)*factrl(n)*(n+2.*l+1.5)*tgamma(2.*l+1.5)*tgamma(2.*l+1.5)/(4.*M_PI*K_nl*factrl(n+4*l+2)); } for (l=0; l<=SCF_LMAX; l++) { for (m=0; m<=l; ++m) { deltam0=2.; if (m==0) deltam0=1.; coeflm[lm(l,m)]=(2.*l+1.)*deltam0*factrl(l-m)/factrl(l+m); /* N_lm eq. (3.15) */ } } }
/* Calculate SCF coefficients based on particle distribution */ void SCF_calc_from_particles(void) { double r, un, unm1, costh, sinth, phi, xi; double plm1m,plm2m,temp1,temp2,temp3; int n,l,m; int i; double x, y, z, mass; for(i = 0; i < NumPart; i++) { /* consider only DM particles of SCF coefficients */ if (P[i].Type != 1) continue; /* scale to unit hernquist sphere */ to_unit(P[i].Pos[0], P[i].Pos[1], P[i].Pos[2], &x, &y, &z); mass = P[i].Mass /SCF_HQ_MASS; /* OR: not */ //x = P[i].Pos[0]; y = P[i].Pos[1]; z = P[i].Pos[2]; //mass = P[i].Mass; /* particle coordinate transformation */ r = sqrt(x * x + y * y + z * z); costh=z/r; phi=atan2(y,x); xi=(r-1.)/(r+1.); sinth=sqrt(1.-costh*costh); for (m=0; m<=SCF_LMAX; m++) { cosmphi[m]=cos(m*phi); sinmphi[m]=sin(m*phi); } /* Ultraspherical polynomials */ for (l=0; l<=SCF_LMAX; l++) { ultrasp[nl(0,l)]=1.0; if (SCF_NMAX>0) { ultrasp[nl(1,l)]=(2.0*(2.*l+1.5))*xi; un=ultrasp[nl(1,l)]; unm1=1.0; /* recursion */ for(n=1; n<=SCF_NMAX-1; n++) { ultrasp[nl(n+1,l)]=((2.0*n+(2.0*(2.*l+1.5)))*xi*un-(1.0*n-1.0+(2.0*(2.*l+1.5)))*unm1)*1.0/(n+1.0); unm1=un; un=ultrasp[nl(n+1,l)]; } } for (n=0; n<=SCF_NMAX; n++) { ultraspt[nl(n,l)]=ultrasp[nl(n,l)]*Anltilde[nl(n,l)]; } } /* Legendre polynomials */ for (m=0; m<=SCF_LMAX; m++) { plm[lm(m,m)]=1.0; if (m>0) plm[lm(m,m)]=-pow(1,m)*dblfact[m]*pow(sinth,m); plm1m=plm[lm(m,m)]; plm2m=0.0; /* recursion */ for (l=m+1; l<=SCF_LMAX; l++) { plm[lm(l,m)]=(costh*(2.*l-1.)*plm1m-(l+m-1.)*plm2m)/(l-m); plm2m=plm1m; plm1m=plm[lm(l,m)]; } } for (l=0; l<=SCF_LMAX; l++) { temp1=pow(r,l)/pow(1.+r,2*l+1)*mass; for (m=0; m<=l; m++) { temp2=temp1*plm[lm(l,m)]*coeflm[lm(l,m)]*sinmphi[m]; temp3=temp1*plm[lm(l,m)]*coeflm[lm(l,m)]*cosmphi[m]; for (n=0; n<=SCF_NMAX; n++) { sinsum[nlm(n,l,m)]+=temp2*ultraspt[nl(n,l)]; cossum[nlm(n,l,m)]+=temp3*ultraspt[nl(n,l)]; } } } } }
/* get force and potential based on SCF expansion of (unit!) sphere */ void SCF_evaluate(MyDouble x, MyDouble y, MyDouble z, MyDouble *potential, MyDouble *ax, MyDouble *ay, MyDouble *az) { int n,l,m; MyDouble r,rl, costh,sinth,phi,xi; MyDouble ar,ath,aphi,poten; MyDouble un,unm1,unplusr,phinltil; MyDouble plm1m,plm2m; MyDouble temp1,temp2,temp3,temp4; MyDouble Clm,Dlm,Elm,Flm; /* particle coordinate transformation */ r = sqrt(x * x + y * y + z * z); costh=z/r; phi=atan2(y,x); xi=(r-1.)/(r+1.); sinth=sqrt(1.-costh*costh); for (m=0; m<=SCF_LMAX; m++) { cosmphi[m]=cos(m*phi); sinmphi[m]=sin(m*phi); } ar=0.0; ath=0.0; aphi=0.0; poten=0.0; /* Ultraspherical polynomials */ for (l=0; l<=SCF_LMAX; l++) { ultrasp[nl(0,l)]=1.0; ultrasp1[nl(0,l)]=0.0; if (SCF_NMAX>0) { ultrasp[nl(1,l)]=(2.0*(2.*l+1.5))*xi; ultrasp1[nl(1,l)]=1.0; un=ultrasp[nl(1,l)]; unm1=1.0; /* recursion */ for(n=1; n<=SCF_NMAX-1; n++) { ultrasp[nl(n+1,l)]=((2.0*n+(2.0*(2.*l+1.5)))*xi*un-(1.0*n-1.0+(2.0*(2.*l+1.5)))*unm1)*1.0/(n+1.0); unm1=un; un=ultrasp[nl(n+1,l)]; ultrasp1[nl(n+1,l)]=(((2.0*(2.*l+1.5))+(n+1)-1.)*unm1-(n+1)*xi*ultrasp[nl(n+1,l)])/((2.0*(2.*l+1.5))*(1.-xi*xi)); } } } /* Legendre polynomials */ for (m=0; m<=SCF_LMAX; m++) { plm[lm(m,m)]=1.0; if(m>0) plm[lm(m,m)]=pow(-1,m)*dblfact[m]*pow(sinth,m); plm1m=plm[lm(m,m)]; plm2m=0.0; /* recursion */ for(l=m+1; l<=SCF_LMAX; l++) { plm[lm(l,m)]=(costh*(2.*l-1.)*plm1m-(l+m-1.)*plm2m)/(l-m); plm2m=plm1m; plm1m=plm[lm(l,m)]; } } /* derivatives of Legendre polynomials */ dplm[0]=0.0; for(l=1; l<=SCF_LMAX; l++) { for(m=0; m<=l; m++) { if(l==m) dplm[lm(l,m)]=l*costh*plm[lm(l,m)]/(costh*costh-1.0); else dplm[lm(l,m)]=(l*costh*plm[lm(l,m)]-(l+m)*plm[lm(l-1,m)])/(costh*costh-1.0); } } for (l=0; l<=SCF_LMAX; l++) { temp1=0.0; temp2=0.0; temp3=0.0; temp4=0.0; for(m=0; m<=l; m++) { Clm=0.0; Dlm=0.0; Elm=0.0; Flm=0.0; for(n=0; n<=SCF_NMAX; n++) { #ifdef SCF_SCALEFAC Clm += ultrasp[nl(n,l)]*cossum[nlm(n,l,m)] * scalefac_nlm[nlm(n,l,m)]; Dlm += ultrasp[nl(n,l)]*sinsum[nlm(n,l,m)] * scalefac_nlm[nlm(n,l,m)]; Elm += ultrasp1[nl(n,l)]*cossum[nlm(n,l,m)] * scalefac_nlm[nlm(n,l,m)]; Flm += ultrasp1[nl(n,l)]*sinsum[nlm(n,l,m)] * scalefac_nlm[nlm(n,l,m)]; #else Clm += ultrasp[nl(n,l)]*cossum[nlm(n,l,m)]; Dlm += ultrasp[nl(n,l)]*sinsum[nlm(n,l,m)]; Elm += ultrasp1[nl(n,l)]*cossum[nlm(n,l,m)]; Flm += ultrasp1[nl(n,l)]*sinsum[nlm(n,l,m)]; #endif } temp1 += plm[lm(l,m)]*(Clm*cosmphi[m]+Dlm*sinmphi[m]); temp2 += -plm[lm(l,m)]*(Elm*cosmphi[m]+Flm*sinmphi[m]); temp3 += -dplm[lm(l,m)]*(Clm*cosmphi[m]+Dlm*sinmphi[m]); temp4 += -m*plm[lm(l,m)]*(Dlm*cosmphi[m]-Clm*sinmphi[m]); } rl=pow(r,l); unplusr=pow(1.+r,2*l+1); phinltil=rl/unplusr; /* add contributions to potential */ poten += temp1*phinltil; /* add contributions to accelerations in spherical coordinates */ ar += phinltil*(-temp1*(l/r-(2.*l+1.)/(1.+r))+temp2*4.*(2.*l+1.5)/(pow(1.+r,2))); ath += temp3*phinltil; aphi += temp4*phinltil; } /* convert to cartesian coordinates */ *ax=(sinth*cos(phi)*ar+costh*cos(phi)*ath-sin(phi)*aphi); *ay=(sinth*sin(phi)*ar+costh*sin(phi)*ath+cos(phi)*aphi); *az=(costh*ar-sinth*ath); *potential = poten; }