Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

forcetree.c

Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <string.h>
00004 #include <math.h>
00005 #include <time.h>
00006 #include <mpi.h>
00007 
00008 #include "allvars.h"
00009 #include "proto.h"
00010 
00011 
00026 static int last;
00027 
00028 
00029 
00031 #define NTAB 1000
00032 
00033 static float tabfac, shortrange_table[NTAB], shortrange_table_potential[NTAB];
00034 
00036 static int first_flag = 0;
00037 
00038 
00039 
00040 
00041 #ifdef PERIODIC
00042 
00043 #define NEAREST(x) (((x)>boxhalf)?((x)-boxsize):(((x)<-boxhalf)?((x)+boxsize):(x)))
00044 
00045 #define EN  64
00046 
00049 static FLOAT fcorrx[EN + 1][EN + 1][EN + 1];
00050 static FLOAT fcorry[EN + 1][EN + 1][EN + 1];
00051 static FLOAT fcorrz[EN + 1][EN + 1][EN + 1];
00052 static FLOAT potcorr[EN + 1][EN + 1][EN + 1];
00053 static double fac_intp;
00054 #endif
00055 
00056 
00057 
00061 int force_treebuild(int npart)
00062 {
00063   Numnodestree = force_treebuild_single(npart);
00064 
00065   force_update_pseudoparticles();
00066 
00067   force_flag_localnodes();
00068 
00069   TimeOfLastTreeConstruction = All.Time;
00070 
00071   return Numnodestree;
00072 }
00073 
00074 
00075 
00093 int force_treebuild_single(int npart)
00094 {
00095   int i, j, subnode = 0, parent, numnodes;
00096   int nfree, th, nn, no;
00097   struct NODE *nfreep;
00098   double lenhalf, epsilon;
00099   peanokey key;
00100 
00101 
00102   /* create an empty root node  */
00103   nfree = All.MaxPart;          /* index of first free node */
00104   nfreep = &Nodes[nfree];       /* select first node */
00105 
00106   nfreep->len = DomainLen;
00107   for(j = 0; j < 3; j++)
00108     nfreep->center[j] = DomainCenter[j];
00109   for(j = 0; j < 8; j++)
00110     nfreep->u.suns[j] = -1;
00111 
00112 
00113   numnodes = 1;
00114   nfreep++;
00115   nfree++;
00116 
00117   /* create a set of empty nodes corresponding to the top-level domain
00118    * grid. We need to generate these nodes first to make sure that we have a
00119    * complete top-level tree which allows the easy insertion of the
00120    * pseudo-particles at the right place 
00121    */
00122 
00123   force_create_empty_nodes(All.MaxPart, 0, 1, 0, 0, 0, &numnodes, &nfree);
00124 
00125 
00126   /* if a high-resolution region in a global tree is used, we need to generate
00127    * an additional set empty nodes to make sure that we have a complete
00128    * top-level tree for the high-resolution inset
00129    */
00130 
00131   nfreep = &Nodes[nfree];
00132   parent = -1;                  /* note: will not be used below before it is changed */
00133 
00134 
00135   /* now we insert all particles */
00136   for(i = 0; i < npart; i++)
00137     {
00138 
00139       /* the softening is only used to check whether particles are so close
00140        * that the tree needs not to be refined further
00141        */
00142       epsilon = All.ForceSoftening[P[i].Type];
00143 
00144       key = peano_hilbert_key((P[i].Pos[0] - DomainCorner[0]) * DomainFac,
00145                               (P[i].Pos[1] - DomainCorner[1]) * DomainFac,
00146                               (P[i].Pos[2] - DomainCorner[2]) * DomainFac, BITS_PER_DIMENSION);
00147 
00148       no = 0;
00149       while(TopNodes[no].Daughter >= 0)
00150         no = TopNodes[no].Daughter + (key - TopNodes[no].StartKey) / (TopNodes[no].Size / 8);
00151 
00152       no = TopNodes[no].Leaf;
00153       th = DomainNodeIndex[no];
00154 
00155       while(1)
00156         {
00157           if(th >= All.MaxPart) /* we are dealing with an internal node */
00158             {
00159               subnode = 0;
00160               if(P[i].Pos[0] > Nodes[th].center[0])
00161                 subnode += 1;
00162               if(P[i].Pos[1] > Nodes[th].center[1])
00163                 subnode += 2;
00164               if(P[i].Pos[2] > Nodes[th].center[2])
00165                 subnode += 4;
00166 
00167               nn = Nodes[th].u.suns[subnode];
00168 
00169               if(nn >= 0)       /* ok, something is in the daughter slot already, need to continue */
00170                 {
00171                   parent = th;
00172                   th = nn;
00173                 }
00174               else
00175                 {
00176                   /* here we have found an empty slot where we can attach
00177                    * the new particle as a leaf.
00178                    */
00179                   Nodes[th].u.suns[subnode] = i;
00180                   break;        /* done for this particle */
00181                 }
00182             }
00183           else
00184             {
00185               /* We try to insert into a leaf with a single particle.  Need
00186                * to generate a new internal node at this point.
00187                */
00188               Nodes[parent].u.suns[subnode] = nfree;
00189 
00190               nfreep->len = 0.5 * Nodes[parent].len;
00191               lenhalf = 0.25 * Nodes[parent].len;
00192 
00193               if(subnode & 1)
00194                 nfreep->center[0] = Nodes[parent].center[0] + lenhalf;
00195               else
00196                 nfreep->center[0] = Nodes[parent].center[0] - lenhalf;
00197 
00198               if(subnode & 2)
00199                 nfreep->center[1] = Nodes[parent].center[1] + lenhalf;
00200               else
00201                 nfreep->center[1] = Nodes[parent].center[1] - lenhalf;
00202 
00203               if(subnode & 4)
00204                 nfreep->center[2] = Nodes[parent].center[2] + lenhalf;
00205               else
00206                 nfreep->center[2] = Nodes[parent].center[2] - lenhalf;
00207 
00208               nfreep->u.suns[0] = -1;
00209               nfreep->u.suns[1] = -1;
00210               nfreep->u.suns[2] = -1;
00211               nfreep->u.suns[3] = -1;
00212               nfreep->u.suns[4] = -1;
00213               nfreep->u.suns[5] = -1;
00214               nfreep->u.suns[6] = -1;
00215               nfreep->u.suns[7] = -1;
00216 
00217 
00218               subnode = 0;
00219               if(P[th].Pos[0] > nfreep->center[0])
00220                 subnode += 1;
00221               if(P[th].Pos[1] > nfreep->center[1])
00222                 subnode += 2;
00223               if(P[th].Pos[2] > nfreep->center[2])
00224                 subnode += 4;
00225 #ifndef NOTREERND
00226               if(nfreep->len < 1.0e-3 * epsilon)
00227                 {
00228                   /* seems like we're dealing with particles at identical (or extremely close)
00229                    * locations. Randomize subnode index to allow tree construction. Note: Multipole moments
00230                    * of tree are still correct, but this will only happen well below gravitational softening
00231                    * length-scale anyway.
00232                    */
00233                   subnode = (int) (8.0 * get_random_number((0xffff & P[i].ID) + P[i].GravCost));
00234                   P[i].GravCost += 1;
00235                   if(subnode >= 8)
00236                     subnode = 7;
00237                 }
00238 #endif
00239               nfreep->u.suns[subnode] = th;
00240 
00241               th = nfree;       /* resume trying to insert the new particle at
00242                                  * the newly created internal node
00243                                  */
00244 
00245               numnodes++;
00246               nfree++;
00247               nfreep++;
00248 
00249               if((numnodes) >= MaxNodes)
00250                 {
00251                   printf("task %d: maximum number %d of tree-nodes reached.\n", ThisTask, MaxNodes);
00252                   printf("for particle %d\n", i);
00253                   dump_particles();
00254                   endrun(1);
00255                 }
00256             }
00257         }
00258     }
00259 
00260 
00261   /* insert the pseudo particles that represent the mass distribution of other domains */
00262   force_insert_pseudo_particles();
00263 
00264 
00265   /* now compute the multipole moments recursively */
00266   last = -1;
00267 
00268   force_update_node_recursive(All.MaxPart, -1, -1);
00269 
00270   if(last >= All.MaxPart)
00271     {
00272       if(last >= All.MaxPart + MaxNodes)        /* a pseudo-particle */
00273         Nextnode[last - MaxNodes] = -1;
00274       else
00275         Nodes[last].u.d.nextnode = -1;
00276     }
00277   else
00278     Nextnode[last] = -1;
00279 
00280   return numnodes;
00281 }
00282 
00283 
00284 
00292 void force_create_empty_nodes(int no, int topnode, int bits, int x, int y, int z, int *nodecount,
00293                               int *nextfree)
00294 {
00295   int i, j, k, n, sub, count;
00296 
00297   if(TopNodes[topnode].Daughter >= 0)
00298     {
00299       for(i = 0; i < 2; i++)
00300         for(j = 0; j < 2; j++)
00301           for(k = 0; k < 2; k++)
00302             {
00303               sub = 7 & peano_hilbert_key((x << 1) + i, (y << 1) + j, (z << 1) + k, bits);
00304 
00305               count = i + 2 * j + 4 * k;
00306 
00307               Nodes[no].u.suns[count] = *nextfree;
00308 
00309 
00310               Nodes[*nextfree].len = 0.5 * Nodes[no].len;
00311               Nodes[*nextfree].center[0] = Nodes[no].center[0] + (2 * i - 1) * 0.25 * Nodes[no].len;
00312               Nodes[*nextfree].center[1] = Nodes[no].center[1] + (2 * j - 1) * 0.25 * Nodes[no].len;
00313               Nodes[*nextfree].center[2] = Nodes[no].center[2] + (2 * k - 1) * 0.25 * Nodes[no].len;
00314 
00315               for(n = 0; n < 8; n++)
00316                 Nodes[*nextfree].u.suns[n] = -1;
00317 
00318               if(TopNodes[TopNodes[topnode].Daughter + sub].Daughter == -1)
00319                 DomainNodeIndex[TopNodes[TopNodes[topnode].Daughter + sub].Leaf] = *nextfree;
00320 
00321               *nextfree = *nextfree + 1;
00322               *nodecount = *nodecount + 1;
00323 
00324               if((*nodecount) >= MaxNodes)
00325                 {
00326                   printf("task %d: maximum number %d of tree-nodes reached.\n", ThisTask, MaxNodes);
00327                   printf("in create empty nodes\n");
00328                   dump_particles();
00329                   endrun(11);
00330                 }
00331 
00332               force_create_empty_nodes(*nextfree - 1, TopNodes[topnode].Daughter + sub,
00333                                        bits + 1, 2 * x + i, 2 * y + j, 2 * z + k, nodecount, nextfree);
00334             }
00335     }
00336 }
00337 
00338 
00339 
00346 void force_insert_pseudo_particles(void)
00347 {
00348   int i, index, subnode, nn, th;
00349 
00350   for(i = 0; i < NTopleaves; i++)
00351     {
00352       index = DomainNodeIndex[i];
00353 
00354       DomainMoment[i].mass = 0;
00355       DomainMoment[i].s[0] = Nodes[index].center[0];
00356       DomainMoment[i].s[1] = Nodes[index].center[1];
00357       DomainMoment[i].s[2] = Nodes[index].center[2];
00358     }
00359 
00360   for(i = 0; i < NTopleaves; i++)
00361     {
00362 
00363       if(i < DomainMyStart || i > DomainMyLast)
00364         {
00365           th = All.MaxPart;     /* select index of first node in tree */
00366 
00367           while(1)
00368             {
00369               if(th >= All.MaxPart)     /* we are dealing with an internal node */
00370                 {
00371                   if(th >= All.MaxPart + MaxNodes)
00372                     endrun(888);        /* this can't be */
00373 
00374                   subnode = 0;
00375                   if(DomainMoment[i].s[0] > Nodes[th].center[0])
00376                     subnode += 1;
00377                   if(DomainMoment[i].s[1] > Nodes[th].center[1])
00378                     subnode += 2;
00379                   if(DomainMoment[i].s[2] > Nodes[th].center[2])
00380                     subnode += 4;
00381 
00382                   nn = Nodes[th].u.suns[subnode];
00383 
00384                   if(nn >= 0)   /* ok, something is in the daughter slot already, need to continue */
00385                     {
00386                       th = nn;
00387                     }
00388                   else
00389                     {
00390                       /* here we have found an empty slot where we can 
00391                        * attach the pseudo particle as a leaf 
00392                        */
00393                       Nodes[th].u.suns[subnode] = All.MaxPart + MaxNodes + i;
00394 
00395                       break;    /* done for this pseudo particle */
00396                     }
00397                 }
00398               else
00399                 {
00400                   endrun(889);  /* this can't be */
00401                 }
00402             }
00403         }
00404     }
00405 }
00406 
00407 
00423 void force_update_node_recursive(int no, int sib, int father)
00424 {
00425   int j, jj, p, pp, nextsib, suns[8];
00426   FLOAT hmax;
00427 
00428 #ifdef UNEQUALSOFTENINGS
00429 #ifndef ADAPTIVE_GRAVSOFT_FORGAS
00430   int maxsofttype, diffsoftflag;
00431 #else
00432   double maxsoft;
00433 #endif
00434 #endif
00435   struct particle_data *pa;
00436   double s[3], vs[3], mass;
00437 
00438   if(no >= All.MaxPart && no < All.MaxPart + MaxNodes)  /* internal node */
00439     {
00440       for(j = 0; j < 8; j++)
00441         suns[j] = Nodes[no].u.suns[j];  /* this "backup" is necessary because the nextnode entry will
00442                                            overwrite one element (union!) */
00443       if(last >= 0)
00444         {
00445           if(last >= All.MaxPart)
00446             {
00447               if(last >= All.MaxPart + MaxNodes)        /* a pseudo-particle */
00448                 Nextnode[last - MaxNodes] = no;
00449               else
00450                 Nodes[last].u.d.nextnode = no;
00451             }
00452           else
00453             Nextnode[last] = no;
00454         }
00455 
00456       last = no;
00457 
00458       mass = 0;
00459       s[0] = 0;
00460       s[1] = 0;
00461       s[2] = 0;
00462       vs[0] = 0;
00463       vs[1] = 0;
00464       vs[2] = 0;
00465       hmax = 0;
00466 #ifdef UNEQUALSOFTENINGS
00467 #ifndef ADAPTIVE_GRAVSOFT_FORGAS
00468       maxsofttype = 7;
00469       diffsoftflag = 0;
00470 #else
00471       maxsoft = 0;
00472 #endif
00473 #endif
00474 
00475       for(j = 0; j < 8; j++)
00476         {
00477           if((p = suns[j]) >= 0)
00478             {
00479               /* check if we have a sibling on the same level */
00480               for(jj = j + 1; jj < 8; jj++)
00481                 if((pp = suns[jj]) >= 0)
00482                   break;
00483 
00484               if(jj < 8)        /* yes, we do */
00485                 nextsib = pp;
00486               else
00487                 nextsib = sib;
00488 
00489               force_update_node_recursive(p, nextsib, no);
00490 
00491 
00492               if(p >= All.MaxPart)      /* an internal node or pseudo particle */
00493                 {
00494                   if(p >= All.MaxPart + MaxNodes)       /* a pseudo particle */
00495                     {
00496                       /* nothing to be done here because the mass of the
00497                        * pseudo-particle is still zero. This will be changed
00498                        * later.
00499                        */
00500                     }
00501                   else
00502                     {
00503                       mass += Nodes[p].u.d.mass;
00504                       s[0] += Nodes[p].u.d.mass * Nodes[p].u.d.s[0];
00505                       s[1] += Nodes[p].u.d.mass * Nodes[p].u.d.s[1];
00506                       s[2] += Nodes[p].u.d.mass * Nodes[p].u.d.s[2];
00507                       vs[0] += Nodes[p].u.d.mass * Extnodes[p].vs[0];
00508                       vs[1] += Nodes[p].u.d.mass * Extnodes[p].vs[1];
00509                       vs[2] += Nodes[p].u.d.mass * Extnodes[p].vs[2];
00510 
00511                       if(Extnodes[p].hmax > hmax)
00512                         hmax = Extnodes[p].hmax;
00513 
00514 #ifdef UNEQUALSOFTENINGS
00515 #ifndef ADAPTIVE_GRAVSOFT_FORGAS
00516                       diffsoftflag |= (Nodes[p].u.d.bitflags >> 5) & 1;
00517 
00518                       if(maxsofttype == 7)
00519                         {
00520                           maxsofttype = (Nodes[p].u.d.bitflags >> 2) & 7;
00521                         }
00522                       else
00523                         {
00524                           if(((Nodes[p].u.d.bitflags >> 2) & 7) != 7)
00525                             {
00526                               if(All.ForceSoftening[((Nodes[p].u.d.bitflags >> 2) & 7)] >
00527                                  All.ForceSoftening[maxsofttype])
00528                                 {
00529                                   maxsofttype = ((Nodes[p].u.d.bitflags >> 2) & 7);
00530                                   diffsoftflag = 1;
00531                                 }
00532                               else
00533                                 {
00534                                   if(All.ForceSoftening[((Nodes[p].u.d.bitflags >> 2) & 7)] <
00535                                      All.ForceSoftening[maxsofttype])
00536                                     diffsoftflag = 1;
00537                                 }
00538                             }
00539                         }
00540 #else
00541                       if(Nodes[p].maxsoft > maxsoft)
00542                         maxsoft = Nodes[p].maxsoft;
00543 #endif
00544 #endif
00545                     }
00546                 }
00547               else              /* a particle */
00548                 {
00549                   pa = &P[p];
00550 
00551                   mass += pa->Mass;
00552                   s[0] += pa->Mass * pa->Pos[0];
00553                   s[1] += pa->Mass * pa->Pos[1];
00554                   s[2] += pa->Mass * pa->Pos[2];
00555                   vs[0] += pa->Mass * pa->Vel[0];
00556                   vs[1] += pa->Mass * pa->Vel[1];
00557                   vs[2] += pa->Mass * pa->Vel[2];
00558 
00559 #ifdef UNEQUALSOFTENINGS
00560 #ifndef ADAPTIVE_GRAVSOFT_FORGAS
00561                   if(maxsofttype == 7)
00562                     {
00563                       maxsofttype = pa->Type;
00564                     }
00565                   else
00566                     {
00567                       if(All.ForceSoftening[pa->Type] > All.ForceSoftening[maxsofttype])
00568                         {
00569                           maxsofttype = pa->Type;
00570                           diffsoftflag = 1;
00571                         }
00572                       else
00573                         {
00574                           if(All.ForceSoftening[pa->Type] < All.ForceSoftening[maxsofttype])
00575                             diffsoftflag = 1;
00576                         }
00577                     }
00578 #else
00579                   if(pa->Type == 0)
00580                     {
00581                       if(SphP[p].Hsml > maxsoft)
00582                         maxsoft = SphP[p].Hsml;
00583                     }
00584                   else
00585                     {
00586                       if(All.ForceSoftening[pa->Type] > maxsoft)
00587                         maxsoft = All.ForceSoftening[pa->Type];
00588                     }
00589 #endif
00590 #endif
00591                   if(pa->Type == 0)
00592                     if(SphP[p].Hsml > hmax)
00593                       hmax = SphP[p].Hsml;
00594                 }
00595             }
00596         }
00597 
00598 
00599       if(mass)
00600         {
00601           s[0] /= mass;
00602           s[1] /= mass;
00603           s[2] /= mass;
00604           vs[0] /= mass;
00605           vs[1] /= mass;
00606           vs[2] /= mass;
00607         }
00608       else
00609         {
00610           s[0] = Nodes[no].center[0];
00611           s[1] = Nodes[no].center[1];
00612           s[2] = Nodes[no].center[2];
00613         }
00614 
00615       Nodes[no].u.d.s[0] = s[0];
00616       Nodes[no].u.d.s[1] = s[1];
00617       Nodes[no].u.d.s[2] = s[2];
00618       Nodes[no].u.d.mass = mass;
00619 
00620 
00621 #ifdef UNEQUALSOFTENINGS
00622 #ifndef ADAPTIVE_GRAVSOFT_FORGAS
00623       Nodes[no].u.d.bitflags = 4 * maxsofttype + 32 * diffsoftflag;
00624 #else
00625       Nodes[no].u.d.bitflags = 0;
00626       Nodes[no].maxsoft = maxsoft;
00627 #endif
00628 #else
00629       Nodes[no].u.d.bitflags = 0;
00630 #endif
00631 
00632 
00633       Extnodes[no].vs[0] = vs[0];
00634       Extnodes[no].vs[1] = vs[1];
00635       Extnodes[no].vs[2] = vs[2];
00636       Extnodes[no].hmax = hmax;
00637 
00638       Nodes[no].u.d.sibling = sib;
00639       Nodes[no].u.d.father = father;
00640     }
00641   else                          /* single particle or pseudo particle */
00642     {
00643       if(last >= 0)
00644         {
00645           if(last >= All.MaxPart)
00646             {
00647               if(last >= All.MaxPart + MaxNodes)        /* a pseudo-particle */
00648                 Nextnode[last - MaxNodes] = no;
00649               else
00650                 Nodes[last].u.d.nextnode = no;
00651             }
00652           else
00653             Nextnode[last] = no;
00654         }
00655 
00656       last = no;
00657 
00658       if(no < All.MaxPart)      /* only set it for single particles */
00659         Father[no] = father;
00660     }
00661 
00662 }
00663 
00664 
00665 
00672 void force_update_pseudoparticles(void)
00673 {
00674   force_exchange_pseudodata();
00675 
00676   force_treeupdate_pseudos();
00677 }
00678 
00679 
00680 
00685 void force_exchange_pseudodata(void)
00686 {
00687   int i, no;
00688   MPI_Status status;
00689   int level, sendTask, recvTask;
00690 
00691   for(i = DomainMyStart; i <= DomainMyLast; i++)
00692     {
00693       no = DomainNodeIndex[i];
00694 
00695       /* read out the multipole moments from the local base cells */
00696       DomainMoment[i].s[0] = Nodes[no].u.d.s[0];
00697       DomainMoment[i].s[1] = Nodes[no].u.d.s[1];
00698       DomainMoment[i].s[2] = Nodes[no].u.d.s[2];
00699       DomainMoment[i].vs[0] = Extnodes[no].vs[0];
00700       DomainMoment[i].vs[1] = Extnodes[no].vs[1];
00701       DomainMoment[i].vs[2] = Extnodes[no].vs[2];
00702       DomainMoment[i].mass = Nodes[no].u.d.mass;
00703 #ifdef UNEQUALSOFTENINGS
00704       DomainMoment[i].bitflags = Nodes[no].u.d.bitflags;
00705 #endif
00706     }
00707 
00708   /* share the pseudo-particle data accross CPUs */
00709 
00710   for(level = 1; level < (1 << PTask); level++)
00711     {
00712       sendTask = ThisTask;
00713       recvTask = ThisTask ^ level;
00714 
00715       if(recvTask < NTask)
00716         MPI_Sendrecv(&DomainMoment[DomainStartList[sendTask]],
00717                      (DomainEndList[sendTask] - DomainStartList[sendTask] + 1) * sizeof(struct DomainNODE),
00718                      MPI_BYTE, recvTask, TAG_DMOM,
00719                      &DomainMoment[DomainStartList[recvTask]],
00720                      (DomainEndList[recvTask] - DomainStartList[recvTask] + 1) * sizeof(struct DomainNODE),
00721                      MPI_BYTE, recvTask, TAG_DMOM, MPI_COMM_WORLD, &status);
00722     }
00723 
00724 }
00725 
00729 void force_treeupdate_pseudos(void)
00730 {
00731   int i, k, no;
00732   FLOAT sold[3], vsold[3], snew[3], vsnew[3], massold, massnew, mm;
00733 
00734 #ifdef UNEQUALSOFTENINGS
00735   int maxsofttype, diffsoftflag;
00736 #endif
00737 
00738   for(i = 0; i < NTopleaves; i++)
00739     if(i < DomainMyStart || i > DomainMyLast)
00740       {
00741         no = DomainNodeIndex[i];
00742 
00743         for(k = 0; k < 3; k++)
00744           {
00745             sold[k] = Nodes[no].u.d.s[k];
00746             vsold[k] = Extnodes[no].vs[k];
00747           }
00748         massold = Nodes[no].u.d.mass;
00749 
00750         for(k = 0; k < 3; k++)
00751           {
00752             snew[k] = DomainMoment[i].s[k];
00753             vsnew[k] = DomainMoment[i].vs[k];
00754           }
00755         massnew = DomainMoment[i].mass;
00756 
00757 
00758 #ifdef UNEQUALSOFTENINGS
00759         maxsofttype = (Nodes[no].u.d.bitflags >> 2) & 7;
00760         diffsoftflag = (Nodes[no].u.d.bitflags >> 5) & 1;
00761 #endif
00762         do
00763           {
00764             mm = Nodes[no].u.d.mass + massnew - massold;
00765             for(k = 0; k < 3; k++)
00766               {
00767                 if(mm > 0)
00768                   {
00769                     Nodes[no].u.d.s[k] =
00770                       (Nodes[no].u.d.mass * Nodes[no].u.d.s[k] + massnew * snew[k] - massold * sold[k]) / mm;
00771                     Extnodes[no].vs[k] =
00772                       (Nodes[no].u.d.mass * Extnodes[no].vs[k] + massnew * vsnew[k] -
00773                        massold * vsold[k]) / mm;
00774                   }
00775               }
00776             Nodes[no].u.d.mass = mm;
00777 
00778 
00779 #ifdef UNEQUALSOFTENINGS
00780             diffsoftflag |= (Nodes[no].u.d.bitflags >> 5) & 1;
00781 
00782             if(maxsofttype == 7)
00783               maxsofttype = (Nodes[no].u.d.bitflags >> 2) & 7;
00784             else
00785               {
00786                 if(((Nodes[no].u.d.bitflags >> 2) & 7) != 7)
00787                   {
00788                     if(All.ForceSoftening[((Nodes[no].u.d.bitflags >> 2) & 7)] >
00789                        All.ForceSoftening[maxsofttype])
00790                       {
00791                         maxsofttype = ((Nodes[no].u.d.bitflags >> 2) & 7);
00792                         diffsoftflag = 1;
00793                       }
00794                     else
00795                       {
00796                         if(All.ForceSoftening[((Nodes[no].u.d.bitflags >> 2) & 7)] <
00797                            All.ForceSoftening[maxsofttype])
00798                           diffsoftflag = 1;
00799                       }
00800                   }
00801               }
00802 
00803             Nodes[no].u.d.bitflags = (Nodes[no].u.d.bitflags & 3) + 4 * maxsofttype + 32 * diffsoftflag;
00804 #endif
00805             no = Nodes[no].u.d.father;
00806 
00807           }
00808         while(no >= 0);
00809       }
00810 }
00811 
00812 
00813 
00817 void force_flag_localnodes(void)
00818 {
00819   int no, i;
00820 
00821   /* mark all top-level nodes */
00822 
00823   for(i = 0; i < NTopleaves; i++)
00824     {
00825       no = DomainNodeIndex[i];
00826 
00827       while(no >= 0)
00828         {
00829           if((Nodes[no].u.d.bitflags & 1))
00830             break;
00831 
00832           Nodes[no].u.d.bitflags |= 1;
00833 
00834           no = Nodes[no].u.d.father;
00835         }
00836     }
00837 
00838   /* mark top-level nodes that contain local particles */
00839 
00840   for(i = DomainMyStart; i <= DomainMyLast; i++)
00841     {
00842       /*
00843          if(DomainMoment[i].mass > 0)
00844        */
00845       {
00846         no = DomainNodeIndex[i];
00847 
00848         while(no >= 0)
00849           {
00850             if((Nodes[no].u.d.bitflags & 2))
00851               break;
00852 
00853             Nodes[no].u.d.bitflags |= 2;
00854 
00855             no = Nodes[no].u.d.father;
00856           }
00857       }
00858     }
00859 }
00860 
00861 
00862 
00868 void force_update_len(void)
00869 {
00870   int i, no;
00871   MPI_Status status;
00872   int level, sendTask, recvTask;
00873 
00874   force_update_node_len_local();
00875 
00876   /* first update the side-lengths of all local nodes */
00877   for(i = DomainMyStart; i <= DomainMyLast; i++)
00878     {
00879       no = DomainNodeIndex[i];
00880 
00881       DomainTreeNodeLen[i] = Nodes[no].len;
00882     }
00883 
00884   for(level = 1; level < (1 << PTask); level++)
00885     {
00886       sendTask = ThisTask;
00887       recvTask = ThisTask ^ level;
00888 
00889       if(recvTask < NTask)
00890         MPI_Sendrecv(&DomainTreeNodeLen[DomainStartList[sendTask]],
00891                      (DomainEndList[sendTask] - DomainStartList[sendTask] + 1) * sizeof(FLOAT),
00892                      MPI_BYTE, recvTask, TAG_NODELEN,
00893                      &DomainTreeNodeLen[DomainStartList[recvTask]],
00894                      (DomainEndList[recvTask] - DomainStartList[recvTask] + 1) * sizeof(FLOAT),
00895                      MPI_BYTE, recvTask, TAG_NODELEN, MPI_COMM_WORLD, &status);
00896     }
00897 
00898   /* Finally, we update the top-level tree. */
00899   force_update_node_len_toptree();
00900 }
00901 
00902 
00906 void force_update_node_len_local(void)
00907 {
00908   int i, p, k, no;
00909   FLOAT dist, distmax;
00910 
00911   for(i = 0; i < NumPart; i++)
00912     {
00913       no = Father[i];
00914 
00915       for(k = 0, distmax = 0; k < 3; k++)
00916         {
00917           dist = P[i].Pos[k] - Nodes[no].center[k];
00918           if(dist < 0)
00919             dist = -dist;
00920           if(dist > distmax)
00921             distmax = dist;
00922         }
00923 
00924       if(distmax + distmax > Nodes[no].len)
00925         {
00926           Nodes[no].len = distmax + distmax;
00927           p = Nodes[no].u.d.father;
00928 
00929           while(p >= 0)
00930             {
00931               distmax = Nodes[p].center[0] - Nodes[no].center[0];
00932               if(distmax < 0)
00933                 distmax = -distmax;
00934               distmax = distmax + distmax + Nodes[no].len;
00935 
00936               if(0.999999 * distmax > Nodes[p].len)
00937                 {
00938                   Nodes[p].len = distmax;
00939                   no = p;
00940                   p = Nodes[p].u.d.father;
00941                 }
00942               else
00943                 break;
00944             }
00945         }
00946     }
00947 }
00948 
00949 
00953 void force_update_node_len_toptree(void)
00954 {
00955   int i, no, p;
00956   FLOAT distmax;
00957 
00958   for(i = 0; i < NTopleaves; i++)
00959     if(i < DomainMyStart || i > DomainMyLast)
00960       {
00961         no = DomainNodeIndex[i];
00962 
00963         if(Nodes[no].len < DomainTreeNodeLen[i])
00964           Nodes[no].len = DomainTreeNodeLen[i];
00965 
00966         p = Nodes[no].u.d.father;
00967 
00968         while(p >= 0)
00969           {
00970             distmax = Nodes[p].center[0] - Nodes[no].center[0];
00971             if(distmax < 0)
00972               distmax = -distmax;
00973             distmax = distmax + distmax + Nodes[no].len;
00974 
00975             if(0.999999 * distmax > Nodes[p].len)
00976               {
00977                 Nodes[p].len = distmax;
00978                 no = p;
00979                 p = Nodes[p].u.d.father;
00980               }
00981             else
00982               break;
00983           }
00984       }
00985 }
00986 
00987 
00988 
00989 
00997 void force_update_hmax(void)
00998 {
00999   int i, no;
01000   MPI_Status status;
01001   int level, sendTask, recvTask;
01002 
01003   force_update_node_hmax_local();
01004 
01005   for(i = DomainMyStart; i <= DomainMyLast; i++)
01006     {
01007       no = DomainNodeIndex[i];
01008 
01009       DomainHmax[i] = Extnodes[no].hmax;
01010     }
01011 
01012   /* share the hmax-data of the pseudo-particles accross CPUs */
01013 
01014   for(level = 1; level < (1 << PTask); level++)
01015     {
01016       sendTask = ThisTask;
01017       recvTask = ThisTask ^ level;
01018 
01019       if(recvTask < NTask)
01020         MPI_Sendrecv(&DomainHmax[DomainStartList[sendTask]],
01021                      (DomainEndList[sendTask] - DomainStartList[sendTask] + 1) * sizeof(FLOAT),
01022                      MPI_BYTE, recvTask, TAG_HMAX,
01023                      &DomainHmax[DomainStartList[recvTask]],
01024                      (DomainEndList[recvTask] - DomainStartList[recvTask] + 1) * sizeof(FLOAT),
01025                      MPI_BYTE, recvTask, TAG_HMAX, MPI_COMM_WORLD, &status);
01026     }
01027 
01028 
01029   force_update_node_hmax_toptree();
01030 }
01031 
01034 void force_update_node_hmax_local(void)
01035 {
01036   int i, p, no;
01037 
01038   for(i = 0; i < N_gas; i++)
01039     {
01040 
01041       no = Father[i];
01042 
01043       if(SphP[i].Hsml > Extnodes[no].hmax)
01044         {
01045 
01046           Extnodes[no].hmax = SphP[i].Hsml;
01047           p = Nodes[no].u.d.father;
01048 
01049           while(p >= 0)
01050             {
01051               if(Extnodes[no].hmax > Extnodes[p].hmax)
01052                 {
01053                   Extnodes[p].hmax = Extnodes[no].hmax;
01054                   no = p;
01055                   p = Nodes[p].u.d.father;
01056                 }
01057               else
01058                 break;
01059             }
01060         }
01061 
01062     }
01063 }
01064 
01065 
01066 
01067 
01070 void force_update_node_hmax_toptree(void)
01071 {
01072 
01073   int i, no, p;
01074 
01075 
01076   for(i = 0; i < NTopleaves; i++)
01077     if(i < DomainMyStart || i > DomainMyLast)
01078       {
01079         no = DomainNodeIndex[i];
01080 
01081         if(Extnodes[no].hmax < DomainHmax[i])
01082           Extnodes[no].hmax = DomainHmax[i];
01083 
01084         p = Nodes[no].u.d.father;
01085 
01086         while(p >= 0)
01087           {
01088             if(Extnodes[no].hmax > Extnodes[p].hmax)
01089               {
01090                 Extnodes[p].hmax = Extnodes[no].hmax;
01091                 no = p;
01092                 p = Nodes[p].u.d.father;
01093               }
01094             else
01095               break;
01096           }
01097       }
01098 }
01099 
01100 
01101 
01102 
01103 
01109 int force_treeevaluate(int target, int mode, double *ewaldcountsum)
01110 {
01111   struct NODE *nop = 0;
01112   int no, ninteractions, ptype;
01113   double r2, dx, dy, dz, mass, r, fac, u, h, h_inv, h3_inv;
01114   double acc_x, acc_y, acc_z, pos_x, pos_y, pos_z, aold;
01115 
01116 #ifdef ADAPTIVE_GRAVSOFT_FORGAS
01117   double soft = 0;
01118 #endif
01119 #ifdef PERIODIC
01120   double boxsize, boxhalf;
01121 
01122   boxsize = All.BoxSize;
01123   boxhalf = 0.5 * All.BoxSize;
01124 #endif
01125 
01126   acc_x = 0;
01127   acc_y = 0;
01128   acc_z = 0;
01129   ninteractions = 0;
01130 
01131   if(mode == 0)
01132     {
01133       pos_x = P[target].Pos[0];
01134       pos_y = P[target].Pos[1];
01135       pos_z = P[target].Pos[2];
01136       ptype = P[target].Type;
01137       aold = All.ErrTolForceAcc * P[target].OldAcc;
01138 #ifdef ADAPTIVE_GRAVSOFT_FORGAS
01139       if(ptype == 0)
01140         soft = SphP[target].Hsml;
01141 #endif
01142     }
01143   else
01144     {
01145       pos_x = GravDataGet[target].u.Pos[0];
01146       pos_y = GravDataGet[target].u.Pos[1];
01147       pos_z = GravDataGet[target].u.Pos[2];
01148 #ifdef UNEQUALSOFTENINGS
01149       ptype = GravDataGet[target].Type;
01150 #else
01151       ptype = P[0].Type;
01152 #endif
01153       aold = All.ErrTolForceAcc * GravDataGet[target].w.OldAcc;
01154 #ifdef ADAPTIVE_GRAVSOFT_FORGAS
01155       if(ptype == 0)
01156         soft = GravDataGet[target].Soft;
01157 #endif
01158     }
01159 
01160 
01161 
01162 #ifndef UNEQUALSOFTENINGS
01163   h = All.ForceSoftening[ptype];
01164   h_inv = 1.0 / h;
01165   h3_inv = h_inv * h_inv * h_inv;
01166 #endif
01167   no = All.MaxPart;             /* root node */
01168 
01169   while(no >= 0)
01170     {
01171       if(no < All.MaxPart)      /* single particle */
01172         {
01173           /* the index of the node is the index of the particle */
01174           /* observe the sign */
01175 
01176           dx = P[no].Pos[0] - pos_x;
01177           dy = P[no].Pos[1] - pos_y;
01178           dz = P[no].Pos[2] - pos_z;
01179 
01180           mass = P[no].Mass;
01181         }
01182       else
01183         {
01184           if(no >= All.MaxPart + MaxNodes)      /* pseudo particle */
01185             {
01186               if(mode == 0)
01187                 {
01188                   Exportflag[DomainTask[no - (All.MaxPart + MaxNodes)]] = 1;
01189                 }
01190               no = Nextnode[no - MaxNodes];
01191               continue;
01192             }
01193           nop = &Nodes[no];
01194           dx = nop->u.d.s[0] - pos_x;
01195           dy = nop->u.d.s[1] - pos_y;
01196           dz = nop->u.d.s[2] - pos_z;
01197 
01198           mass = nop->u.d.mass;
01199         }
01200 #ifdef PERIODIC
01201       dx = NEAREST(dx);
01202       dy = NEAREST(dy);
01203       dz = NEAREST(dz);
01204 #endif
01205       r2 = dx * dx + dy * dy + dz * dz;
01206 
01207       if(no < All.MaxPart)
01208         {
01209 #ifdef UNEQUALSOFTENINGS
01210 #ifdef ADAPTIVE_GRAVSOFT_FORGAS
01211           if(ptype == 0)
01212             h = soft;
01213           else
01214             h = All.ForceSoftening[ptype];
01215 
01216           if(P[no].Type == 0)
01217             {
01218               if(h < SphP[no].Hsml)
01219                 h = SphP[no].Hsml;
01220             }
01221           else
01222             {
01223               if(h < All.ForceSoftening[P[no].Type])
01224                 h = All.ForceSoftening[P[no].Type];
01225             }
01226 #else
01227           h = All.ForceSoftening[ptype];
01228           if(h < All.ForceSoftening[P[no].Type])
01229             h = All.ForceSoftening[P[no].Type];
01230 #endif
01231 #endif
01232           no = Nextnode[no];
01233         }
01234       else                      /* we have an  internal node. Need to check opening criterion */
01235         {
01236           if(mode == 1)
01237             {
01238               if((nop->u.d.bitflags & 3) == 1)  /* if it's a top-level node
01239                                                  * which does not contain
01240                                                  * local particles we can
01241                                                  * continue to do a short-cut */
01242                 {
01243                   no = nop->u.d.sibling;
01244                   continue;
01245                 }
01246             }
01247 
01248 
01249           if(All.ErrTolTheta)   /* check Barnes-Hut opening criterion */
01250             {
01251               if(nop->len * nop->len > r2 * All.ErrTolTheta * All.ErrTolTheta)
01252                 {
01253                   /* open cell */
01254                   no = nop->u.d.nextnode;
01255                   continue;
01256                 }
01257             }
01258           else                  /* check relative opening criterion */
01259             {
01260               if(mass * nop->len * nop->len > r2 * r2 * aold)
01261                 {
01262                   /* open cell */
01263                   no = nop->u.d.nextnode;
01264                   continue;
01265                 }
01266 
01267               /* check in addition whether we lie inside the cell */
01268 
01269               if(fabs(nop->center[0] - pos_x) < 0.60 * nop->len)
01270                 {
01271                   if(fabs(nop->center[1] - pos_y) < 0.60 * nop->len)
01272                     {
01273                       if(fabs(nop->center[2] - pos_z) < 0.60 * nop->len)
01274                         {
01275                           no = nop->u.d.nextnode;
01276                           continue;
01277                         }
01278                     }
01279                 }
01280             }
01281 
01282 
01283 #ifdef UNEQUALSOFTENINGS
01284 #ifndef ADAPTIVE_GRAVSOFT_FORGAS
01285           h = All.ForceSoftening[ptype];
01286           if(h < All.ForceSoftening[(nop->u.d.bitflags >> 2) & 7])
01287             {
01288               h = All.ForceSoftening[(nop->u.d.bitflags >> 2) & 7];
01289               if(r2 < h * h)
01290                 {
01291                   if(((nop->u.d.bitflags >> 5) & 1))    /* bit-5 signals that there are particles of different softening in the node */
01292                     {
01293                       no = nop->u.d.nextnode;
01294                       continue;
01295                     }
01296                 }
01297             }
01298 #else
01299           if(ptype == 0)
01300             h = soft;
01301           else
01302             h = All.ForceSoftening[ptype];
01303 
01304           if(h < nop->maxsoft)
01305             {
01306               h = nop->maxsoft;
01307               if(r2 < h * h)
01308                 {
01309                   no = nop->u.d.nextnode;
01310                   continue;
01311                 }
01312             }
01313 #endif
01314 #endif
01315 
01316           no = nop->u.d.sibling;        /* ok, node can be used */
01317 
01318           if(mode == 1)
01319             {
01320               if(((nop->u.d.bitflags) & 1))     /* Bit 0 signals that this node belongs to top-level tree */
01321                 continue;
01322             }
01323         }
01324 
01325       r = sqrt(r2);
01326 
01327       if(r >= h)
01328         fac = mass / (r2 * r);
01329       else
01330         {
01331 #ifdef UNEQUALSOFTENINGS
01332           h_inv = 1.0 / h;
01333           h3_inv = h_inv * h_inv * h_inv;
01334 #endif
01335           u = r * h_inv;
01336           if(u < 0.5)
01337             fac = mass * h3_inv * (10.666666666667 + u * u * (32.0 * u - 38.4));
01338           else
01339             fac =
01340               mass * h3_inv * (21.333333333333 - 48.0 * u +
01341                                38.4 * u * u - 10.666666666667 * u * u * u - 0.066666666667 / (u * u * u));
01342         }
01343 
01344       acc_x += dx * fac;
01345       acc_y += dy * fac;
01346       acc_z += dz * fac;
01347 
01348       ninteractions++;
01349     }
01350 
01351 
01352   /* store result at the proper place */
01353   if(mode == 0)
01354     {
01355       P[target].GravAccel[0] = acc_x;
01356       P[target].GravAccel[1] = acc_y;
01357       P[target].GravAccel[2] = acc_z;
01358       P[target].GravCost = ninteractions;
01359     }
01360   else
01361     {
01362       GravDataResult[target].u.Acc[0] = acc_x;
01363       GravDataResult[target].u.Acc[1] = acc_y;
01364       GravDataResult[target].u.Acc[2] = acc_z;
01365       GravDataResult[target].w.Ninteractions = ninteractions;
01366     }
01367 
01368 #ifdef PERIODIC
01369   *ewaldcountsum += force_treeevaluate_ewald_correction(target, mode, pos_x, pos_y, pos_z, aold);
01370 #endif
01371 
01372   return ninteractions;
01373 }
01374 
01375 
01376 
01377 
01378 
01379 
01380 #ifdef PMGRID
01381 
01391 int force_treeevaluate_shortrange(int target, int mode)
01392 {
01393   struct NODE *nop = 0;
01394   int no, ptype, ninteractions, tabindex;
01395   double r2, dx, dy, dz, mass, r, fac, u, h, h_inv, h3_inv;
01396   double acc_x, acc_y, acc_z, pos_x, pos_y, pos_z, aold;
01397   double eff_dist;
01398   double rcut, asmth, asmthfac, rcut2, dist;
01399 #ifdef ADAPTIVE_GRAVSOFT_FORGAS
01400   double soft = 0;
01401 #endif
01402 #ifdef PERIODIC
01403   double boxsize, boxhalf;
01404 
01405   boxsize = All.BoxSize;
01406   boxhalf = 0.5 * All.BoxSize;
01407 #endif
01408 
01409 
01410   acc_x = 0;
01411   acc_y = 0;
01412   acc_z = 0;
01413   ninteractions = 0;
01414 
01415   if(mode == 0)
01416     {
01417       pos_x = P[target].Pos[0];
01418       pos_y = P[target].Pos[1];
01419       pos_z = P[target].Pos[2];
01420       ptype = P[target].Type;
01421       aold = All.ErrTolForceAcc * P[target].OldAcc;
01422 #ifdef ADAPTIVE_GRAVSOFT_FORGAS
01423       if(ptype == 0)
01424         soft = SphP[target].Hsml;
01425 #endif
01426     }
01427   else
01428     {
01429       pos_x = GravDataGet[target].u.Pos[0];
01430       pos_y = GravDataGet[target].u.Pos[1];
01431       pos_z = GravDataGet[target].u.Pos[2];
01432 #ifdef UNEQUALSOFTENINGS
01433       ptype = GravDataGet[target].Type;
01434 #else
01435       ptype = P[0].Type;
01436 #endif
01437       aold = All.ErrTolForceAcc * GravDataGet[target].w.OldAcc;
01438 #ifdef ADAPTIVE_GRAVSOFT_FORGAS
01439       if(ptype == 0)
01440         soft = GravDataGet[target].Soft;
01441 #endif
01442     }
01443 
01444   rcut = All.Rcut[0];
01445   asmth = All.Asmth[0];
01446 #ifdef PLACEHIGHRESREGION
01447   if(((1 << ptype) & (PLACEHIGHRESREGION)))
01448     {
01449       rcut = All.Rcut[1];
01450       asmth = All.Asmth[1];
01451     }
01452 #endif
01453   rcut2 = rcut * rcut;
01454 
01455   asmthfac = 0.5 / asmth * (NTAB / 3.0);
01456 
01457 #ifndef UNEQUALSOFTENINGS
01458   h = All.ForceSoftening[ptype];
01459   h_inv = 1.0 / h;
01460   h3_inv = h_inv * h_inv * h_inv;
01461 #endif
01462   no = All.MaxPart;             /* root node */
01463 
01464   while(no >= 0)
01465     {
01466       if(no < All.MaxPart)
01467         {
01468           /* the index of the node is the index of the particle */
01469           dx = P[no].Pos[0] - pos_x;
01470           dy = P[no].Pos[1] - pos_y;
01471           dz = P[no].Pos[2] - pos_z;
01472 #ifdef PERIODIC
01473           dx = NEAREST(dx);
01474           dy = NEAREST(dy);
01475           dz = NEAREST(dz);
01476 #endif
01477           r2 = dx * dx + dy * dy + dz * dz;
01478 
01479           mass = P[no].Mass;
01480 #ifdef UNEQUALSOFTENINGS
01481 #ifdef ADAPTIVE_GRAVSOFT_FORGAS
01482           if(ptype == 0)
01483             h = soft;
01484           else
01485             h = All.ForceSoftening[ptype];
01486 
01487           if(P[no].Type == 0)
01488             {
01489               if(h < SphP[no].Hsml)
01490                 h = SphP[no].Hsml;
01491             }
01492           else
01493             {
01494               if(h < All.ForceSoftening[P[no].Type])
01495                 h = All.ForceSoftening[P[no].Type];
01496             }
01497 #else
01498           h = All.ForceSoftening[ptype];
01499           if(h < All.ForceSoftening[P[no].Type])
01500             h = All.ForceSoftening[P[no].Type];
01501 #endif
01502 #endif
01503           no = Nextnode[no];
01504         }
01505       else                      /* we have an  internal node */
01506         {
01507           if(no >= All.MaxPart + MaxNodes)      /* pseudo particle */
01508             {
01509               if(mode == 0)
01510                 {
01511                   Exportflag[DomainTask[no - (All.MaxPart + MaxNodes)]] = 1;
01512                 }
01513               no = Nextnode[no - MaxNodes];
01514               continue;
01515             }
01516 
01517           nop = &Nodes[no];
01518 
01519           if(mode == 1)
01520             {
01521               if((nop->u.d.bitflags & 3) == 1)  /* if it's a top-level node
01522                                                  * which does not contain
01523                                                  * local particles we can
01524                                                  * continue at this point
01525                                                  */
01526                 {
01527                   no = nop->u.d.sibling;
01528                   continue;
01529                 }
01530             }
01531 
01532           mass = nop->u.d.mass;
01533 
01534           dx = nop->u.d.s[0] - pos_x;
01535           dy = nop->u.d.s[1] - pos_y;
01536           dz = nop->u.d.s[2] - pos_z;
01537 #ifdef PERIODIC
01538           dx = NEAREST(dx);
01539           dy = NEAREST(dy);
01540           dz = NEAREST(dz);
01541 #endif
01542           r2 = dx * dx + dy * dy + dz * dz;
01543 
01544           if(r2 > rcut2)
01545             {
01546               /* check whether we can stop walking along this branch */
01547               eff_dist = rcut + 0.5 * nop->len;
01548 #ifdef PERIODIC
01549               dist = NEAREST(nop->center[0] - pos_x);
01550 #else
01551               dist = nop->center[0] - pos_x;
01552 #endif
01553               if(dist < -eff_dist || dist > eff_dist)
01554                 {
01555                   no = nop->u.d.sibling;
01556                   continue;
01557                 }
01558 #ifdef PERIODIC
01559               dist = NEAREST(nop->center[1] - pos_y);
01560 #else
01561               dist = nop->center[1] - pos_y;
01562 #endif
01563               if(dist < -eff_dist || dist > eff_dist)
01564                 {
01565                   no = nop->u.d.sibling;
01566                   continue;
01567                 }
01568 #ifdef PERIODIC
01569               dist = NEAREST(nop->center[2] - pos_z);
01570 #else
01571               dist = nop->center[2] - pos_z;
01572 #endif
01573               if(dist < -eff_dist || dist > eff_dist)
01574                 {
01575                   no = nop->u.d.sibling;
01576                   continue;
01577                 }
01578             }
01579 
01580 
01581           if(All.ErrTolTheta)   /* check Barnes-Hut opening criterion */
01582             {
01583               if(nop->len * nop->len > r2 * All.ErrTolTheta * All.ErrTolTheta)
01584                 {
01585                   /* open cell */
01586                   no = nop->u.d.nextnode;
01587                   continue;
01588                 }
01589             }
01590           else                  /* check relative opening criterion */
01591             {
01592               if(mass * nop->len * nop->len > r2 * r2 * aold)
01593                 {
01594                   /* open cell */
01595                   no = nop->u.d.nextnode;
01596                   continue;
01597                 }
01598 
01599               /* check in addition whether we lie inside the cell */
01600 
01601               if(fabs(nop->center[0] - pos_x) < 0.60 * nop->len)
01602                 {
01603                   if(fabs(nop->center[1] - pos_y) < 0.60 * nop->len)
01604                     {
01605                       if(fabs(nop->center[2] - pos_z) < 0.60 * nop->len)
01606                         {
01607                           no = nop->u.d.nextnode;
01608                           continue;
01609                         }
01610                     }
01611                 }
01612             }
01613 
01614 #ifdef UNEQUALSOFTENINGS
01615 #ifndef ADAPTIVE_GRAVSOFT_FORGAS
01616           h = All.ForceSoftening[ptype];
01617           if(h < All.ForceSoftening[(nop->u.d.bitflags >> 2) & 7])
01618             {
01619               h = All.ForceSoftening[(nop->u.d.bitflags >> 2) & 7];
01620               if(r2 < h * h)
01621                 {
01622                   if(((nop->u.d.bitflags >> 5) & 1))    /* bit-5 signals that there are particles of different softening in the node */
01623                     {
01624                       no = nop->u.d.nextnode;
01625 
01626                       continue;
01627                     }
01628                 }
01629             }
01630 #else
01631           if(ptype == 0)
01632             h = soft;
01633           else
01634             h = All.ForceSoftening[ptype];
01635 
01636           if(h < nop->maxsoft)
01637             {
01638               h = nop->maxsoft;
01639               if(r2 < h * h)
01640                 {
01641                   no = nop->u.d.nextnode;
01642                   continue;
01643                 }
01644             }
01645 #endif
01646 #endif
01647           no = nop->u.d.sibling;        /* ok, node can be used */
01648 
01649           if(mode == 1)
01650             {
01651               if(((nop->u.d.bitflags) & 1))     /* Bit 0 signals that this node belongs to top-level tree */
01652                 continue;
01653             }
01654         }
01655 
01656       r = sqrt(r2);
01657 
01658       if(r >= h)
01659         fac = mass / (r2 * r);
01660       else
01661         {
01662 #ifdef UNEQUALSOFTENINGS
01663           h_inv = 1.0 / h;
01664           h3_inv = h_inv * h_inv * h_inv;
01665 #endif
01666           u = r * h_inv;
01667           if(u < 0.5)
01668             fac = mass * h3_inv * (10.666666666667 + u * u * (32.0 * u - 38.4));
01669           else
01670             fac =
01671               mass * h3_inv * (21.333333333333 - 48.0 * u +
01672                                38.4 * u * u - 10.666666666667 * u * u * u - 0.066666666667 / (u * u * u));
01673         }
01674 
01675       tabindex = (int) (asmthfac * r);
01676 
01677       if(tabindex < NTAB)
01678         {
01679           fac *= shortrange_table[tabindex];
01680 
01681           acc_x += dx * fac;
01682           acc_y += dy * fac;
01683           acc_z += dz * fac;
01684 
01685           ninteractions++;
01686         }
01687     }
01688 
01689 
01690   /* store result at the proper place */
01691   if(mode == 0)
01692     {
01693       P[target].GravAccel[0] = acc_x;
01694       P[target].GravAccel[1] = acc_y;
01695       P[target].GravAccel[2] = acc_z;
01696       P[target].GravCost = ninteractions;
01697     }
01698   else
01699     {
01700       GravDataResult[target].u.Acc[0] = acc_x;
01701       GravDataResult[target].u.Acc[1] = acc_y;
01702       GravDataResult[target].u.Acc[2] = acc_z;
01703       GravDataResult[target].w.Ninteractions = ninteractions;
01704     }
01705 
01706   return ninteractions;
01707 }
01708 
01709 #endif
01710 
01711 
01712 
01713 #ifdef PERIODIC
01714 
01732 int force_treeevaluate_ewald_correction(int target, int mode, double pos_x, double pos_y, double pos_z,
01733                                         double aold)
01734 {
01735   struct NODE *nop = 0;
01736   int no, cost;
01737   double dx, dy, dz, mass, r2;
01738   int signx, signy, signz;
01739   int i, j, k, openflag;
01740   double u, v, w;
01741   double f1, f2, f3, f4, f5, f6, f7, f8;
01742   double acc_x, acc_y, acc_z;
01743   double boxsize, boxhalf;
01744 
01745   boxsize = All.BoxSize;
01746   boxhalf = 0.5 * All.BoxSize;
01747 
01748   acc_x = 0;
01749   acc_y = 0;
01750   acc_z = 0;
01751   cost = 0;
01752 
01753   no = All.MaxPart;
01754 
01755   while(no >= 0)
01756     {
01757       if(no < All.MaxPart)      /* single particle */
01758         {
01759           /* the index of the node is the index of the particle */
01760           /* observe the sign */
01761 
01762           dx = P[no].Pos[0] - pos_x;
01763           dy = P[no].Pos[1] - pos_y;
01764           dz = P[no].Pos[2] - pos_z;
01765           mass = P[no].Mass;
01766         }
01767       else
01768         {
01769           if(no >= All.MaxPart + MaxNodes)      /* pseudo particle */
01770             {
01771               if(mode == 0)
01772                 {
01773                   Exportflag[DomainTask[no - (All.MaxPart + MaxNodes)]] = 1;
01774                 }
01775 
01776               no = Nextnode[no - MaxNodes];
01777               continue;
01778             }
01779 
01780           nop = &Nodes[no];
01781           dx = nop->u.d.s[0] - pos_x;
01782           dy = nop->u.d.s[1] - pos_y;
01783           dz = nop->u.d.s[2] - pos_z;
01784           mass = nop->u.d.mass;
01785         }
01786 
01787       dx = NEAREST(dx);
01788       dy = NEAREST(dy);
01789       dz = NEAREST(dz);
01790 
01791       if(no < All.MaxPart)
01792         no = Nextnode[no];
01793       else                      /* we have an  internal node. Need to check opening criterion */
01794         {
01795           openflag = 0;
01796 
01797           r2 = dx * dx + dy * dy + dz * dz;
01798 
01799           if(All.ErrTolTheta)   /* check Barnes-Hut opening criterion */
01800             {
01801               if(nop->len * nop->len > r2 * All.ErrTolTheta * All.ErrTolTheta)
01802                 {
01803                   openflag = 1;
01804                 }
01805             }
01806           else                  /* check relative opening criterion */
01807             {
01808               if(mass * nop->len * nop->len > r2 * r2 * aold)
01809                 {
01810                   openflag = 1;
01811                 }
01812               else
01813                 {
01814                   if(fabs(nop->center[0] - pos_x) < 0.60 * nop->len)
01815                     {
01816                       if(fabs(nop->center[1] - pos_y) < 0.60 * nop->len)
01817                         {
01818                           if(fabs(nop->center[2] - pos_z) < 0.60 * nop->len)
01819                             {
01820                               openflag = 1;
01821                             }
01822                         }
01823                     }
01824                 }
01825             }
01826 
01827           if(openflag)
01828             {
01829               /* now we check if we can avoid opening the cell */
01830 
01831               u = nop->center[0] - pos_x;
01832               if(u > boxhalf)
01833                 u -= boxsize;
01834               if(u < -boxhalf)
01835                 u += boxsize;
01836 
01837               if(fabs(u) > 0.5 * (boxsize - nop->len))
01838                 {
01839                   no = nop->u.d.nextnode;
01840                   continue;
01841                 }
01842 
01843               u = nop->center[1] - pos_y;
01844               if(u > boxhalf)
01845                 u -= boxsize;
01846               if(u < -boxhalf)
01847                 u += boxsize;
01848 
01849               if(fabs(u) > 0.5 * (boxsize - nop->len))
01850                 {
01851                   no = nop->u.d.nextnode;
01852                   continue;
01853                 }
01854 
01855               u = nop->center[2] - pos_z;
01856               if(u > boxhalf)
01857                 u -= boxsize;
01858               if(u < -boxhalf)
01859                 u += boxsize;
01860 
01861               if(fabs(u) > 0.5 * (boxsize - nop->len))
01862                 {
01863                   no = nop->u.d.nextnode;
01864                   continue;
01865                 }
01866 
01867               /* if the cell is too large, we need to refine
01868                * it further 
01869                */
01870               if(nop->len > 0.20 * boxsize)
01871                 {
01872                   /* cell is too large */
01873                   no = nop->u.d.nextnode;
01874                   continue;
01875                 }
01876             }
01877 
01878           no = nop->u.d.sibling;        /* ok, node can be used */
01879 
01880           if(mode == 1)
01881             {
01882               if((nop->u.d.bitflags & 1))       /* Bit 0 signals that this node belongs to top-level tree */
01883                 continue;
01884             }
01885         }
01886 
01887       /* compute the Ewald correction force */
01888 
01889       if(dx < 0)
01890         {
01891           dx = -dx;
01892           signx = +1;
01893         }
01894       else
01895         signx = -1;
01896 
01897       if(dy < 0)
01898         {
01899           dy = -dy;
01900           signy = +1;
01901         }
01902       else
01903         signy = -1;
01904 
01905       if(dz < 0)
01906         {
01907           dz = -dz;
01908           signz = +1;
01909         }
01910       else
01911         signz = -1;
01912 
01913       u = dx * fac_intp;
01914       i = (int) u;
01915       if(i >= EN)
01916         i = EN - 1;
01917       u -= i;
01918       v = dy * fac_intp;
01919       j = (int) v;
01920       if(j >= EN)
01921         j = EN - 1;
01922       v -= j;
01923       w = dz * fac_intp;
01924       k = (int) w;
01925       if(k >= EN)
01926         k = EN - 1;
01927       w -= k;
01928 
01929       /* compute factors for trilinear interpolation */
01930 
01931       f1 = (1 - u) * (1 - v) * (1 - w);
01932       f2 = (1 - u) * (1 - v) * (w);
01933       f3 = (1 - u) * (v) * (1 - w);
01934       f4 = (1 - u) * (v) * (w);
01935       f5 = (u) * (1 - v) * (1 - w);
01936       f6 = (u) * (1 - v) * (w);
01937       f7 = (u) * (v) * (1 - w);
01938       f8 = (u) * (v) * (w);
01939 
01940       acc_x += mass * signx * (fcorrx[i][j][k] * f1 +
01941                                fcorrx[i][j][k + 1] * f2 +
01942                                fcorrx[i][j + 1][k] * f3 +
01943                                fcorrx[i][j + 1][k + 1] * f4 +
01944                                fcorrx[i + 1][j][k] * f5 +
01945                                fcorrx[i + 1][j][k + 1] * f6 +
01946                                fcorrx[i + 1][j + 1][k] * f7 + fcorrx[i + 1][j + 1][k + 1] * f8);
01947 
01948       acc_y += mass * signy * (fcorry[i][j][k] * f1 +
01949                                fcorry[i][j][k + 1] * f2 +
01950                                fcorry[i][j + 1][k] * f3 +
01951                                fcorry[i][j + 1][k + 1] * f4 +
01952                                fcorry[i + 1][j][k] * f5 +
01953                                fcorry[i + 1][j][k + 1] * f6 +
01954                                fcorry[i + 1][j + 1][k] * f7 + fcorry[i + 1][j + 1][k + 1] * f8);
01955 
01956       acc_z += mass * signz * (fcorrz[i][j][k] * f1 +
01957                                fcorrz[i][j][k + 1] * f2 +
01958                                fcorrz[i][j + 1][k] * f3 +
01959                                fcorrz[i][j + 1][k + 1] * f4 +
01960                                fcorrz[i + 1][j][k] * f5 +
01961                                fcorrz[i + 1][j][k + 1] * f6 +
01962                                fcorrz[i + 1][j + 1][k] * f7 + fcorrz[i + 1][j + 1][k + 1] * f8);
01963       cost++;
01964     }
01965 
01966 
01967   /* add the result at the proper place */
01968 
01969   if(mode == 0)
01970     {
01971       P[target].GravAccel[0] += acc_x;
01972       P[target].GravAccel[1] += acc_y;
01973       P[target].GravAccel[2] += acc_z;
01974       P[target].GravCost += cost;
01975     }
01976   else
01977     {
01978       GravDataResult[target].u.Acc[0] += acc_x;
01979       GravDataResult[target].u.Acc[1] += acc_y;
01980       GravDataResult[target].u.Acc[2] += acc_z;
01981       GravDataResult[target].w.Ninteractions += cost;
01982     }
01983 
01984   return cost;
01985 }
01986 
01987 #endif
01988 
01989 
01990 
01991 
01992 
01993 
01998 void force_treeevaluate_potential(int target, int mode)
01999 {
02000   struct NODE *nop = 0;
02001   int no, ptype;
02002   double r2, dx, dy, dz, mass, r, u, h, h_inv, wp;
02003   double pot, pos_x, pos_y, pos_z, aold;
02004 #ifdef ADAPTIVE_GRAVSOFT_FORGAS
02005   double soft = 0;
02006 #endif
02007 #ifdef PERIODIC
02008   double boxsize, boxhalf;
02009 
02010   boxsize = All.BoxSize;
02011   boxhalf = 0.5 * All.BoxSize;
02012 #endif
02013 
02014   pot = 0;
02015 
02016   if(mode == 0)
02017     {
02018       pos_x = P[target].Pos[0];
02019       pos_y = P[target].Pos[1];
02020       pos_z = P[target].Pos[2];
02021       ptype = P[target].Type;
02022       aold = All.ErrTolForceAcc * P[target].OldAcc;
02023 #ifdef ADAPTIVE_GRAVSOFT_FORGAS
02024       if(ptype == 0)
02025         soft = SphP[target].Hsml;
02026 #endif
02027     }
02028   else
02029     {
02030       pos_x = GravDataGet[target].u.Pos[0];
02031       pos_y = GravDataGet[target].u.Pos[1];
02032       pos_z = GravDataGet[target].u.Pos[2];
02033 #ifdef UNEQUALSOFTENINGS
02034       ptype = GravDataGet[target].Type;
02035 #else
02036       ptype = P[0].Type;
02037 #endif
02038       aold = All.ErrTolForceAcc * GravDataGet[target].w.OldAcc;
02039 #ifdef ADAPTIVE_GRAVSOFT_FORGAS
02040       if(ptype == 0)
02041         soft = GravDataGet[target].Soft;
02042 #endif
02043     }
02044 
02045 
02046 #ifndef UNEQUALSOFTENINGS
02047   h = All.ForceSoftening[ptype];
02048   h_inv = 1.0 / h;
02049 #endif
02050   no = All.MaxPart;
02051 
02052   while(no >= 0)
02053     {
02054       if(no < All.MaxPart)      /* single particle */
02055         {
02056           /* the index of the node is the index of the particle */
02057           /* observe the sign */
02058 
02059           dx = P[no].Pos[0] - pos_x;
02060           dy = P[no].Pos[1] - pos_y;
02061           dz = P[no].Pos[2] - pos_z;
02062           mass = P[no].Mass;
02063         }
02064       else
02065         {
02066           if(no >= All.MaxPart + MaxNodes)      /* pseudo particle */
02067             {
02068               if(mode == 0)
02069                 {
02070                   Exportflag[DomainTask[no - (All.MaxPart + MaxNodes)]] = 1;
02071                 }
02072               no = Nextnode[no - MaxNodes];
02073               continue;
02074             }
02075 
02076           nop = &Nodes[no];
02077           dx = nop->u.d.s[0] - pos_x;
02078           dy = nop->u.d.s[1] - pos_y;
02079           dz = nop->u.d.s[2] - pos_z;
02080           mass = nop->u.d.mass;
02081         }
02082 
02083 #ifdef PERIODIC
02084       dx = NEAREST(dx);
02085       dy = NEAREST(dy);
02086       dz = NEAREST(dz);
02087 #endif
02088       r2 = dx * dx + dy * dy + dz * dz;
02089 
02090       if(no < All.MaxPart)
02091         {
02092 #ifdef UNEQUALSOFTENINGS
02093 #ifdef ADAPTIVE_GRAVSOFT_FORGAS
02094           if(ptype == 0)
02095             h = soft;
02096           else
02097             h = All.ForceSoftening[ptype];
02098 
02099           if(P[no].Type == 0)
02100             {
02101               if(h < SphP[no].Hsml)
02102                 h = SphP[no].Hsml;
02103             }
02104           else
02105             {
02106               if(h < All.ForceSoftening[P[no].Type])
02107                 h = All.ForceSoftening[P[no].Type];
02108             }
02109 #else
02110           h = All.ForceSoftening[ptype];
02111           if(h < All.ForceSoftening[P[no].Type])
02112             h = All.ForceSoftening[P[no].Type];
02113 #endif
02114 #endif
02115           no = Nextnode[no];
02116         }
02117       else                      /* we have an internal node. Need to check opening criterion */
02118         {
02119           if(mode == 1)
02120             {
02121               if((nop->u.d.bitflags & 3) == 1)  /* if it's a top-level node
02122                                                  * which does not contain
02123                                                  * local particles we can make
02124                                                  * a short-cut 
02125                                                  */
02126                 {
02127                   no = nop->u.d.sibling;
02128                   continue;
02129                 }
02130             }
02131 
02132           if(All.ErrTolTheta)   /* check Barnes-Hut opening criterion */
02133             {
02134               if(nop->len * nop->len > r2 * All.ErrTolTheta * All.ErrTolTheta)
02135                 {
02136                   /* open cell */
02137                   no = nop->u.d.nextnode;
02138                   continue;
02139                 }
02140             }
02141           else                  /* check relative opening criterion */
02142             {
02143               if(mass * nop->len * nop->len > r2 * r2 * aold)
02144                 {
02145                   /* open cell */
02146                   no = nop->u.d.nextnode;
02147                   continue;
02148                 }
02149 
02150               if(fabs(nop->center[0] - pos_x) < 0.60 * nop->len)
02151                 {
02152                   if(fabs(nop->center[1] - pos_y) < 0.60 * nop->len)
02153                     {
02154                       if(fabs(nop->center[2] - pos_z) < 0.60 * nop->len)
02155                         {
02156                           no = nop->u.d.nextnode;
02157                           continue;
02158                         }
02159                     }
02160                 }
02161             }
02162 #ifdef UNEQUALSOFTENINGS
02163 #ifndef ADAPTIVE_GRAVSOFT_FORGAS
02164           h = All.ForceSoftening[ptype];
02165           if(h < All.ForceSoftening[(nop->u.d.bitflags >> 2) & 7])
02166             {
02167               h = All.ForceSoftening[(nop->u.d.bitflags >> 2) & 7];
02168               if(r2 < h * h)
02169                 {
02170                   if(((nop->u.d.bitflags >> 5) & 1))    /* bit-5 signals that there are particles of different softening in the node */
02171                     {
02172                       no = nop->u.d.nextnode;
02173                       continue;
02174                     }
02175                 }
02176             }
02177 #else
02178           if(ptype == 0)
02179             h = soft;
02180           else
02181             h = All.ForceSoftening[ptype];
02182 
02183           if(h < nop->maxsoft)
02184             {
02185               h = nop->maxsoft;
02186               if(r2 < h * h)
02187                 {
02188                   no = nop->u.d.nextnode;
02189                   continue;
02190                 }
02191             }
02192 #endif
02193 #endif
02194 
02195           no = nop->u.d.sibling;        /* node can be used */
02196 
02197           if(mode == 1)
02198             {
02199               if(((nop->u.d.bitflags) & 1))     /* Bit 0 signals that this node belongs to top-level tree */
02200                 continue;
02201             }
02202         }
02203 
02204       r = sqrt(r2);
02205 
02206       if(r >= h)
02207         pot -= mass / r;
02208       else
02209         {
02210 #ifdef UNEQUALSOFTENINGS
02211           h_inv = 1.0 / h;
02212 #endif
02213           u = r * h_inv;
02214 
02215           if(u < 0.5)
02216             wp = -2.8 + u * u * (5.333333333333 + u * u * (6.4 * u - 9.6));
02217           else
02218             wp =
02219               -3.2 + 0.066666666667 / u + u * u * (10.666666666667 +
02220                                                    u * (-16.0 + u * (9.6 - 2.133333333333 * u)));
02221 
02222           pot += mass * h_inv * wp;
02223         }
02224 #ifdef PERIODIC
02225       pot += mass * ewald_pot_corr(dx, dy, dz);
02226 #endif
02227     }
02228 
02229   /* store result at the proper place */
02230 
02231   if(mode == 0)
02232     P[target].Potential = pot;
02233   else
02234     GravDataResult[target].u.Potential = pot;
02235 }
02236 
02237 
02238 
02239 
02240 #ifdef PMGRID
02241 
02245 void force_treeevaluate_potential_shortrange(int target, int mode)
02246 {
02247   struct NODE *nop = 0;
02248   int no, ptype, tabindex;
02249   double r2, dx, dy, dz, mass, r, u, h, h_inv, wp;
02250   double pot, pos_x, pos_y, pos_z, aold;
02251   double eff_dist, fac, rcut, asmth, asmthfac;
02252   double dxx, dyy, dzz;
02253 #ifdef ADAPTIVE_GRAVSOFT_FORGAS
02254   double soft = 0;
02255 #endif
02256 
02257 #ifdef PERIODIC
02258   double boxsize, boxhalf;
02259 
02260   boxsize = All.BoxSize;
02261   boxhalf = 0.5 * All.BoxSize;
02262 #endif
02263 
02264   pot = 0;
02265 
02266   if(mode == 0)
02267     {
02268       pos_x = P[target].Pos[0];
02269       pos_y = P[target].Pos[1];
02270       pos_z = P[target].Pos[2];
02271       ptype = P[target].Type;
02272       aold = All.ErrTolForceAcc * P[target].OldAcc;
02273 #ifdef ADAPTIVE_GRAVSOFT_FORGAS
02274       if(ptype == 0)
02275         soft = SphP[target].Hsml;
02276 #endif
02277     }
02278   else
02279     {
02280       pos_x = GravDataGet[target].u.Pos[0];
02281       pos_y = GravDataGet[target].u.Pos[1];
02282       pos_z = GravDataGet[target].u.Pos[2];
02283 #ifdef UNEQUALSOFTENINGS
02284       ptype = GravDataGet[target].Type;
02285 #else
02286       ptype = P[0].Type;
02287 #endif
02288       aold = All.ErrTolForceAcc * GravDataGet[target].w.OldAcc;
02289 #ifdef ADAPTIVE_GRAVSOFT_FORGAS
02290       if(ptype == 0)
02291         soft = GravDataGet[target].Soft;
02292 #endif
02293     }
02294 
02295 
02296   rcut = All.Rcut[0];
02297   asmth = All.Asmth[0];
02298 #ifdef PLACEHIGHRESREGION
02299   if(((1 << ptype) & (PLACEHIGHRESREGION)))
02300     {
02301       rcut = All.Rcut[1];
02302       asmth = All.Asmth[1];
02303     }
02304 #endif
02305   asmthfac = 0.5 / asmth * (NTAB / 3.0);
02306 
02307 #ifndef UNEQUALSOFTENINGS
02308   h = All.ForceSoftening[ptype];
02309   h_inv = 1.0 / h;
02310 #endif
02311 
02312   no = All.MaxPart;
02313 
02314   while(no >= 0)
02315     {
02316       if(no < All.MaxPart)      /* single particle */
02317         {
02318           /* the index of the node is the index of the particle */
02319           /* observe the sign  */
02320 
02321           dx = P[no].Pos[0] - pos_x;
02322           dy = P[no].Pos[1] - pos_y;
02323           dz = P[no].Pos[2] - pos_z;
02324           mass = P[no].Mass;
02325         }
02326       else
02327         {
02328           if(no >= All.MaxPart + MaxNodes)      /* pseudo particle */
02329             {
02330               if(mode == 0)
02331                 {
02332                   Exportflag[DomainTask[no - (All.MaxPart + MaxNodes)]] = 1;
02333                 }
02334               no = Nextnode[no - MaxNodes];
02335               continue;
02336             }
02337 
02338           nop = &Nodes[no];
02339           dx = nop->u.d.s[0] - pos_x;
02340           dy = nop->u.d.s[1] - pos_y;
02341           dz = nop->u.d.s[2] - pos_z;
02342           mass = nop->u.d.mass;
02343         }
02344 
02345 #ifdef PERIODIC
02346       dx = NEAREST(dx);
02347       dy = NEAREST(dy);
02348       dz = NEAREST(dz);
02349 #endif
02350       r2 = dx * dx + dy * dy + dz * dz;
02351 
02352       if(no < All.MaxPart)
02353         {
02354 #ifdef UNEQUALSOFTENINGS
02355 #ifdef ADAPTIVE_GRAVSOFT_FORGAS
02356           if(ptype == 0)
02357             h = soft;
02358           else
02359             h = All.ForceSoftening[ptype];
02360 
02361           if(P[no].Type == 0)
02362             {
02363               if(h < SphP[no].Hsml)
02364                 h = SphP[no].Hsml;
02365             }
02366           else
02367             {
02368               if(h < All.ForceSoftening[P[no].Type])
02369                 h = All.ForceSoftening[P[no].Type];
02370             }
02371 #else
02372           h = All.ForceSoftening[ptype];
02373           if(h < All.ForceSoftening[P[no].Type])
02374             h = All.ForceSoftening[P[no].Type];
02375 #endif
02376 #endif
02377           no = Nextnode[no];
02378         }
02379       else                      /* we have an  internal node. Need to check opening criterion */
02380         {
02381           /* check whether we can stop walking along this branch */
02382           if(no >= All.MaxPart + MaxNodes)      /* pseudo particle */
02383             {
02384               if(mode == 0)
02385                 {
02386                   Exportflag[DomainTask[no - (All.MaxPart + MaxNodes)]] = 1;
02387                 }
02388               no = Nextnode[no - MaxNodes];
02389               continue;
02390             }
02391 
02392           if(mode == 1)
02393             {
02394               if((nop->u.d.bitflags & 3) == 1)  /* if it's a top-level node which does not contain local particles */
02395                 {
02396                   no = nop->u.d.sibling;
02397                   continue;
02398                 }
02399             }
02400 
02401           eff_dist = rcut + 0.5 * nop->len;
02402 
02403           dxx = nop->center[0] - pos_x; /* observe the sign ! */
02404           dyy = nop->center[1] - pos_y; /* this vector is -y in my thesis notation */
02405           dzz = nop->center[2] - pos_z;
02406 #ifdef PERIODIC
02407           dxx = NEAREST(dxx);
02408           dyy = NEAREST(dyy);
02409           dzz = NEAREST(dzz);
02410 #endif
02411           if(dxx < -eff_dist || dxx > eff_dist)
02412             {
02413               no = nop->u.d.sibling;
02414               continue;
02415             }
02416 
02417           if(dyy < -eff_dist || dyy > eff_dist)
02418             {
02419               no = nop->u.d.sibling;
02420               continue;
02421             }
02422 
02423           if(dzz < -eff_dist || dzz > eff_dist)
02424             {
02425               no = nop->u.d.sibling;
02426               continue;
02427             }
02428 
02429           if(All.ErrTolTheta)   /* check Barnes-Hut opening criterion */
02430             {
02431               if(nop->len * nop->len > r2 * All.ErrTolTheta * All.ErrTolTheta)
02432                 {
02433                   /* open cell */
02434                   no = nop->u.d.nextnode;
02435                   continue;
02436                 }
02437             }
02438           else                  /* check relative opening criterion */
02439             {
02440               if(mass * nop->len * nop->len > r2 * r2 * aold)
02441                 {
02442                   /* open cell */
02443                   no = nop->u.d.nextnode;
02444                   continue;
02445                 }
02446 
02447               if(fabs(nop->center[0] - pos_x) < 0.60 * nop->len)
02448                 {
02449                   if(fabs(nop->center[1] - pos_y) < 0.60 * nop->len)
02450                     {
02451                       if(fabs(nop->center[2] - pos_z) < 0.60 * nop->len)
02452                         {
02453                           no = nop->u.d.nextnode;
02454                           continue;
02455                         }
02456                     }
02457                 }
02458             }
02459 
02460 #ifdef UNEQUALSOFTENINGS
02461 #ifndef ADAPTIVE_GRAVSOFT_FORGAS
02462           h = All.ForceSoftening[ptype];
02463           if(h < All.ForceSoftening[(nop->u.d.bitflags >> 2) & 7])
02464             {
02465               h = All.ForceSoftening[(nop->u.d.bitflags >> 2) & 7];
02466               if(r2 < h * h)
02467                 {
02468                   /* bit-5 signals that there are particles of
02469                    * different softening in the node
02470                    */
02471                   if(((nop->u.d.bitflags >> 5) & 1))
02472                     {
02473                       no = nop->u.d.nextnode;
02474                       continue;
02475                     }
02476                 }
02477             }
02478 #else
02479           if(ptype == 0)
02480             h = soft;
02481           else
02482             h = All.ForceSoftening[ptype];
02483 
02484           if(h < nop->maxsoft)
02485             {
02486               h = nop->maxsoft;
02487               if(r2 < h * h)
02488                 {
02489                   no = nop->u.d.nextnode;
02490                   continue;
02491                 }
02492             }
02493 #endif
02494 #endif
02495           no = nop->u.d.sibling;        /* node can be used */
02496 
02497           if(mode == 1)
02498             {
02499               if(((nop->u.d.bitflags) & 1))     /* Bit 0 signals that this node belongs to top-level tree */
02500                 continue;
02501             }
02502         }
02503 
02504       r = sqrt(r2);
02505 
02506       tabindex = (int) (r * asmthfac);
02507 
02508       if(tabindex < NTAB)
02509         {
02510           fac = shortrange_table_potential[tabindex];
02511 
02512           if(r >= h)
02513             pot -= fac * mass / r;
02514           else
02515             {
02516 #ifdef UNEQUALSOFTENINGS
02517               h_inv = 1.0 / h;
02518 #endif
02519               u = r * h_inv;
02520 
02521               if(u < 0.5)
02522                 wp = -2.8 + u * u * (5.333333333333 + u * u * (6.4 * u - 9.6));
02523               else
02524                 wp =
02525                   -3.2 + 0.066666666667 / u + u * u * (10.666666666667 +
02526                                                        u * (-16.0 + u * (9.6 - 2.133333333333 * u)));
02527               pot += fac * mass * h_inv * wp;
02528             }
02529         }
02530     }
02531 
02532 
02533   /* store result at the proper place */
02534   if(mode == 0)
02535     P[target].Potential = pot;
02536   else
02537     GravDataResult[target].u.Potential = pot;
02538 }
02539 
02540 #endif
02541 
02542 
02543 
02549 void force_treeallocate(int maxnodes, int maxpart)
02550 {
02551   int i;
02552   size_t bytes;
02553   double allbytes = 0;
02554   double u;
02555 
02556   MaxNodes = maxnodes;
02557 
02558   if(!(Nodes_base = malloc(bytes = (MaxNodes + 1) * sizeof(struct NODE))))
02559     {
02560       printf("failed to allocate memory for %d tree-nodes (%g MB).\n", MaxNodes, bytes / (1024.0 * 1024.0));
02561       endrun(3);
02562     }
02563   allbytes += bytes;
02564 
02565   if(!(Extnodes_base = malloc(bytes = (MaxNodes + 1) * sizeof(struct extNODE))))
02566     {
02567       printf("failed to allocate memory for %d tree-extnodes (%g MB).\n", MaxNodes,
02568              bytes / (1024.0 * 1024.0));
02569       endrun(3);
02570     }
02571   allbytes += bytes;
02572 
02573   Nodes = Nodes_base - All.MaxPart;
02574   Extnodes = Extnodes_base - All.MaxPart;
02575 
02576   if(!(Nextnode = malloc(bytes = (maxpart + MAXTOPNODES) * sizeof(int))))
02577     {
02578       printf("Failed to allocate %d spaces for 'Nextnode' array (%g MB)\n", maxpart + MAXTOPNODES,
02579              bytes / (1024.0 * 1024.0));
02580       exit(0);
02581     }
02582   allbytes += bytes;
02583 
02584   if(!(Father = malloc(bytes = (maxpart) * sizeof(int))))
02585     {
02586       printf("Failed to allocate %d spaces for 'Father' array (%g MB)\n", maxpart, bytes / (1024.0 * 1024.0));
02587       exit(0);
02588     }
02589   allbytes += bytes;
02590 
02591   if(first_flag == 0)
02592     {
02593       first_flag = 1;
02594 
02595       if(ThisTask == 0)
02596         printf("\nAllocated %g MByte for BH-tree. %d\n\n", allbytes / (1024.0 * 1024.0), sizeof(struct NODE)+sizeof(struct extNODE));
02597 
02598       tabfac = NTAB / 3.0;
02599 
02600       for(i = 0; i < NTAB; i++)
02601         {
02602           u = 3.0 / NTAB * (i + 0.5);
02603           shortrange_table[i] = erfc(u) + 2.0 * u / sqrt(M_PI) * exp(-u * u);
02604           shortrange_table_potential[i] = erfc(u);
02605         }
02606     }
02607 }
02608 
02609 
02613 void force_treefree(void)
02614 {
02615   free(Father);
02616   free(Nextnode);
02617   free(Extnodes_base);
02618   free(Nodes_base);
02619 }
02620 
02621 
02622 
02623 
02629 #ifdef FORCETEST
02630 int force_treeevaluate_direct(int target, int mode)
02631 {
02632   double epsilon;
02633   double h, h_inv, dx, dy, dz, r, r2, u, r_inv, fac;
02634   int i, ptype;
02635   double pos_x, pos_y, pos_z;
02636   double acc_x, acc_y, acc_z;
02637 
02638 #ifdef PERIODIC
02639   double fcorr[3];
02640 #endif
02641 #ifdef PERIODIC
02642   double boxsize, boxhalf;
02643 
02644   boxsize = All.BoxSize;
02645   boxhalf = 0.5 * All.BoxSize;
02646 #endif
02647 
02648   acc_x = 0;
02649   acc_y = 0;
02650   acc_z = 0;
02651 
02652   if(mode == 0)
02653     {
02654       pos_x = P[target].Pos[0];
02655       pos_y = P[target].Pos[1];
02656       pos_z = P[target].Pos[2];
02657       ptype = P[target].Type;
02658     }
02659   else
02660     {
02661       pos_x = GravDataGet[target].u.Pos[0];
02662       pos_y = GravDataGet[target].u.Pos[1];
02663       pos_z = GravDataGet[target].u.Pos[2];
02664 #ifdef UNEQUALSOFTENINGS
02665       ptype = GravDataGet[target].Type;
02666 #else
02667       ptype = P[0].Type;
02668 #endif
02669     }
02670 
02671   for(i = 0; i < NumPart; i++)
02672     {
02673       epsilon = dmax(All.ForceSoftening[P[i].Type], All.ForceSoftening[ptype]);
02674 
02675       h = epsilon;
02676       h_inv = 1 / h;
02677 
02678       dx = P[i].Pos[0] - pos_x;
02679       dy = P[i].Pos[1] - pos_y;
02680       dz = P[i].Pos[2] - pos_z;
02681 
02682 #ifdef PERIODIC
02683       while(dx > boxhalf)
02684         dx -= boxsize;
02685       while(dy > boxhalf)
02686         dy -= boxsize;
02687       while(dz > boxhalf)
02688         dz -= boxsize;
02689       while(dx < -boxhalf)
02690         dx += boxsize;
02691       while(dy < -boxhalf)
02692         dy += boxsize;
02693       while(dz < -boxhalf)
02694         dz += boxsize;
02695 #endif
02696       r2 = dx * dx + dy * dy + dz * dz;
02697 
02698       r = sqrt(r2);
02699 
02700       u = r * h_inv;
02701 
02702       if(u >= 1)
02703         {
02704           r_inv = 1 / r;
02705 
02706           fac = P[i].Mass * r_inv * r_inv * r_inv;
02707         }
02708       else
02709         {
02710           if(u < 0.5)
02711             fac = P[i].Mass * h_inv * h_inv * h_inv * (10.666666666667 + u * u * (32.0 * u - 38.4));
02712           else
02713             fac =
02714               P[i].Mass * h_inv * h_inv * h_inv * (21.333333333333 -
02715                                                    48.0 * u + 38.4 * u * u -
02716                                                    10.666666666667 * u * u *
02717                                                    u - 0.066666666667 / (u * u * u));
02718         }
02719 
02720       acc_x += dx * fac;
02721       acc_y += dy * fac;
02722       acc_z += dz * fac;
02723 
02724 #ifdef PERIODIC
02725       if(u > 1.0e-5)
02726         {
02727           ewald_corr(dx, dy, dz, fcorr);
02728 
02729           acc_x += P[i].Mass * fcorr[0];
02730           acc_y += P[i].Mass * fcorr[1];
02731           acc_z += P[i].Mass * fcorr[2];
02732         }
02733 #endif
02734     }
02735 
02736 
02737   if(mode == 0)
02738     {
02739       P[target].GravAccelDirect[0] = acc_x;
02740       P[target].GravAccelDirect[1] = acc_y;
02741       P[target].GravAccelDirect[2] = acc_z;
02742     }
02743   else
02744     {
02745       GravDataResult[target].u.Acc[0] = acc_x;
02746       GravDataResult[target].u.Acc[1] = acc_y;
02747       GravDataResult[target].u.Acc[2] = acc_z;
02748     }
02749 
02750 
02751   return NumPart;
02752 }
02753 #endif
02754 
02755 
02761 void dump_particles(void)
02762 {
02763   FILE *fd;
02764   char buffer[200];
02765   int i;
02766 
02767   sprintf(buffer, "particles%d.dat", ThisTask);
02768   fd = fopen(buffer, "w");
02769   my_fwrite(&NumPart, 1, sizeof(int), fd);
02770 
02771   for(i = 0; i < NumPart; i++)
02772     my_fwrite(&P[i].Pos[0], 3, sizeof(FLOAT), fd);
02773 
02774   for(i = 0; i < NumPart; i++)
02775     my_fwrite(&P[i].Vel[0], 3, sizeof(FLOAT), fd);
02776 
02777   for(i = 0; i < NumPart; i++)
02778     my_fwrite(&P[i].ID, 1, sizeof(int), fd);
02779 
02780   fclose(fd);
02781 }
02782 
02783 
02784 
02785 #ifdef PERIODIC
02786 
02800 void ewald_init(void)
02801 {
02802   int i, j, k, beg, len, size, n, task, count;
02803   double x[3], force[3];
02804   char buf[200];
02805   FILE *fd;
02806 
02807   if(ThisTask == 0)
02808     {
02809       printf("initialize Ewald correction...\n");
02810       fflush(stdout);
02811     }
02812 
02813 #ifdef DOUBLEPRECISION
02814   sprintf(buf, "ewald_spc_table_%d_dbl.dat", EN);
02815 #else
02816   sprintf(buf, "ewald_spc_table_%d.dat", EN);
02817 #endif
02818 
02819   if((fd = fopen(buf, "r")))
02820     {
02821       if(ThisTask == 0)
02822         {
02823           printf("\nreading Ewald tables from file `%s'\n", buf);
02824           fflush(stdout);
02825         }
02826 
02827       my_fread(&fcorrx[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
02828       my_fread(&fcorry[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
02829       my_fread(&fcorrz[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
02830       my_fread(&potcorr[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
02831       fclose(fd);
02832     }
02833   else
02834     {
02835       if(ThisTask == 0)
02836         {
02837           printf("\nNo Ewald tables in file `%s' found.\nRecomputing them...\n", buf);
02838           fflush(stdout);
02839         }
02840 
02841       /* ok, let's recompute things. Actually, we do that in parallel. */
02842 
02843       size = (EN + 1) * (EN + 1) * (EN + 1) / NTask;
02844 
02845 
02846       beg = ThisTask * size;
02847       len = size;
02848       if(ThisTask == (NTask - 1))
02849         len = (EN + 1) * (EN + 1) * (EN + 1) - beg;
02850 
02851       for(i = 0, count = 0; i <= EN; i++)
02852         for(j = 0; j <= EN; j++)
02853           for(k = 0; k <= EN; k++)
02854             {
02855               n = (i * (EN + 1) + j) * (EN + 1) + k;
02856               if(n >= beg && n < (beg + len))
02857                 {
02858                   if(ThisTask == 0)
02859                     {
02860                       if((count % (len / 20)) == 0)
02861                         {
02862                           printf("%4.1f percent done\n", count / (len / 100.0));
02863                           fflush(stdout);
02864                         }
02865                     }
02866 
02867                   x[0] = 0.5 * ((double) i) / EN;
02868                   x[1] = 0.5 * ((double) j) / EN;
02869                   x[2] = 0.5 * ((double) k) / EN;
02870 
02871                   ewald_force(i, j, k, x, force);
02872 
02873                   fcorrx[i][j][k] = force[0];
02874                   fcorry[i][j][k] = force[1];
02875                   fcorrz[i][j][k] = force[2];
02876 
02877                   if(i + j + k == 0)
02878                     potcorr[i][j][k] = 2.8372975;
02879                   else
02880                     potcorr[i][j][k] = ewald_psi(x);
02881 
02882                   count++;
02883                 }
02884             }
02885 
02886       for(task = 0; task < NTask; task++)
02887         {
02888           beg = task * size;
02889           len = size;
02890           if(task == (NTask - 1))
02891             len = (EN + 1) * (EN + 1) * (EN + 1) - beg;
02892 
02893 #ifdef DOUBLEPRECISION
02894           MPI_Bcast(&fcorrx[0][0][beg], len, MPI_DOUBLE, task, MPI_COMM_WORLD);
02895           MPI_Bcast(&fcorry[0][0][beg], len, MPI_DOUBLE, task, MPI_COMM_WORLD);
02896           MPI_Bcast(&fcorrz[0][0][beg], len, MPI_DOUBLE, task, MPI_COMM_WORLD);
02897           MPI_Bcast(&potcorr[0][0][beg], len, MPI_DOUBLE, task, MPI_COMM_WORLD);
02898 #else
02899           MPI_Bcast(&fcorrx[0][0][beg], len, MPI_FLOAT, task, MPI_COMM_WORLD);
02900           MPI_Bcast(&fcorry[0][0][beg], len, MPI_FLOAT, task, MPI_COMM_WORLD);
02901           MPI_Bcast(&fcorrz[0][0][beg], len, MPI_FLOAT, task, MPI_COMM_WORLD);
02902           MPI_Bcast(&potcorr[0][0][beg], len, MPI_FLOAT, task, MPI_COMM_WORLD);
02903 #endif
02904         }
02905 
02906       if(ThisTask == 0)
02907         {
02908           printf("\nwriting Ewald tables to file `%s'\n", buf);
02909           fflush(stdout);
02910 
02911           if((fd = fopen(buf, "w")))
02912             {
02913               my_fwrite(&fcorrx[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
02914               my_fwrite(&fcorry[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
02915               my_fwrite(&fcorrz[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
02916               my_fwrite(&potcorr[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
02917               fclose(fd);
02918             }
02919         }
02920     }
02921 
02922   fac_intp = 2 * EN / All.BoxSize;
02923 
02924   for(i = 0; i <= EN; i++)
02925     for(j = 0; j <= EN; j++)
02926       for(k = 0; k <= EN; k++)
02927         {
02928           potcorr[i][j][k] /= All.BoxSize;
02929           fcorrx[i][j][k] /= All.BoxSize * All.BoxSize;
02930           fcorry[i][j][k] /= All.BoxSize * All.BoxSize;
02931           fcorrz[i][j][k] /= All.BoxSize * All.BoxSize;
02932         }
02933 
02934   if(ThisTask == 0)
02935     {
02936       printf("initialization of periodic boundaries finished.\n");
02937       fflush(stdout);
02938     }
02939 }
02940 
02941 
02948 #ifdef FORCETEST
02949 void ewald_corr(double dx, double dy, double dz, double *fper)
02950 {
02951   int signx, signy, signz;
02952   int i, j, k;
02953   double u, v, w;
02954   double f1, f2, f3, f4, f5, f6, f7, f8;
02955 
02956   if(dx < 0)
02957     {
02958       dx = -dx;
02959       signx = +1;
02960     }
02961   else
02962     signx = -1;
02963 
02964   if(dy < 0)
02965     {
02966       dy = -dy;
02967       signy = +1;
02968     }
02969   else
02970     signy = -1;
02971 
02972   if(dz < 0)
02973     {
02974       dz = -dz;
02975       signz = +1;
02976     }
02977   else
02978     signz = -1;
02979 
02980   u = dx * fac_intp;
02981   i = (int) u;
02982   if(i >= EN)
02983     i = EN - 1;
02984   u -= i;
02985   v = dy * fac_intp;
02986   j = (int) v;
02987   if(j >= EN)
02988     j = EN - 1;
02989   v -= j;
02990   w = dz * fac_intp;
02991   k = (int) w;
02992   if(k >= EN)
02993     k = EN - 1;
02994   w -= k;
02995 
02996   f1 = (1 - u) * (1 - v) * (1 - w);
02997   f2 = (1 - u) * (1 - v) * (w);
02998   f3 = (1 - u) * (v) * (1 - w);
02999   f4 = (1 - u) * (v) * (w);
03000   f5 = (u) * (1 - v) * (1 - w);
03001   f6 = (u) * (1 - v) * (w);
03002   f7 = (u) * (v) * (1 - w);
03003   f8 = (u) * (v) * (w);
03004 
03005   fper[0] = signx * (fcorrx[i][j][k] * f1 +
03006                      fcorrx[i][j][k + 1] * f2 +
03007                      fcorrx[i][j + 1][k] * f3 +
03008                      fcorrx[i][j + 1][k + 1] * f4 +
03009                      fcorrx[i + 1][j][k] * f5 +
03010                      fcorrx[i + 1][j][k + 1] * f6 +
03011                      fcorrx[i + 1][j + 1][k] * f7 + fcorrx[i + 1][j + 1][k + 1] * f8);
03012 
03013   fper[1] = signy * (fcorry[i][j][k] * f1 +
03014                      fcorry[i][j][k + 1] * f2 +
03015                      fcorry[i][j + 1][k] * f3 +
03016                      fcorry[i][j + 1][k + 1] * f4 +
03017                      fcorry[i + 1][j][k] * f5 +
03018                      fcorry[i + 1][j][k + 1] * f6 +
03019                      fcorry[i + 1][j + 1][k] * f7 + fcorry[i + 1][j + 1][k + 1] * f8);
03020 
03021   fper[2] = signz * (fcorrz[i][j][k] * f1 +
03022                      fcorrz[i][j][k + 1] * f2 +
03023                      fcorrz[i][j + 1][k] * f3 +
03024                      fcorrz[i][j + 1][k + 1] * f4 +
03025                      fcorrz[i + 1][j][k] * f5 +
03026                      fcorrz[i + 1][j][k + 1] * f6 +
03027                      fcorrz[i + 1][j + 1][k] * f7 + fcorrz[i + 1][j + 1][k + 1] * f8);
03028 }
03029 #endif
03030 
03031 
03038 double ewald_pot_corr(double dx, double dy, double dz)
03039 {
03040   int i, j, k;
03041   double u, v, w;
03042   double f1, f2, f3, f4, f5, f6, f7, f8;
03043 
03044   if(dx < 0)
03045     dx = -dx;
03046 
03047   if(dy < 0)
03048     dy = -dy;
03049 
03050   if(dz < 0)
03051     dz = -dz;
03052 
03053   u = dx * fac_intp;
03054   i = (int) u;
03055   if(i >= EN)
03056     i = EN - 1;
03057   u -= i;
03058   v = dy * fac_intp;
03059   j = (int) v;
03060   if(j >= EN)
03061     j = EN - 1;
03062   v -= j;
03063   w = dz * fac_intp;
03064   k = (int) w;
03065   if(k >= EN)
03066     k = EN - 1;
03067   w -= k;
03068 
03069   f1 = (1 - u) * (1 - v) * (1 - w);
03070   f2 = (1 - u) * (1 - v) * (w);
03071   f3 = (1 - u) * (v) * (1 - w);
03072   f4 = (1 - u) * (v) * (w);
03073   f5 = (u) * (1 - v) * (1 - w);
03074   f6 = (u) * (1 - v) * (w);
03075   f7 = (u) * (v) * (1 - w);
03076   f8 = (u) * (v) * (w);
03077 
03078   return potcorr[i][j][k] * f1 +
03079     potcorr[i][j][k + 1] * f2 +
03080     potcorr[i][j + 1][k] * f3 +
03081     potcorr[i][j + 1][k + 1] * f4 +
03082     potcorr[i + 1][j][k] * f5 +
03083     potcorr[i + 1][j][k + 1] * f6 + potcorr[i + 1][j + 1][k] * f7 + potcorr[i + 1][j + 1][k + 1] * f8;
03084 }
03085 
03086 
03087 
03091 double ewald_psi(double x[3])
03092 {
03093   double alpha, psi;
03094   double r, sum1, sum2, hdotx;
03095   double dx[3];
03096   int i, n[3], h[3], h2;
03097 
03098   alpha = 2.0;
03099 
03100   for(n[0] = -4, sum1 = 0; n[0] <= 4; n[0]++)
03101     for(n[1] = -4; n[1] <= 4; n[1]++)
03102       for(n[2] = -4; n[2] <= 4; n[2]++)
03103         {
03104           for(i = 0; i < 3; i++)
03105             dx[i] = x[i] - n[i];
03106 
03107           r = sqrt(dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]);
03108           sum1 += erfc(alpha * r) / r;
03109         }
03110 
03111   for(h[0] = -4, sum2 = 0; h[0] <= 4; h[0]++)
03112     for(h[1] = -4; h[1] <= 4; h[1]++)
03113       for(h[2] = -4; h[2] <= 4; h[2]++)
03114         {
03115           hdotx = x[0] * h[0] + x[1] * h[1] + x[2] * h[2];
03116           h2 = h[0] * h[0] + h[1] * h[1] + h[2] * h[2];
03117           if(h2 > 0)
03118             sum2 += 1 / (M_PI * h2) * exp(-M_PI * M_PI * h2 / (alpha * alpha)) * cos(2 * M_PI * hdotx);
03119         }
03120 
03121   r = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
03122 
03123   psi = M_PI / (alpha * alpha) - sum1 - sum2 + 1 / r;
03124 
03125   return psi;
03126 }
03127 
03128 
03132 void ewald_force(int iii, int jjj, int kkk, double x[3], double force[3])
03133 {
03134   double alpha, r2;
03135   double r, val, hdotx, dx[3];
03136   int i, h[3], n[3], h2;
03137 
03138   alpha = 2.0;
03139 
03140   for(i = 0; i < 3; i++)
03141     force[i] = 0;
03142 
03143   if(iii == 0 && jjj == 0 && kkk == 0)
03144     return;
03145 
03146   r2 = x[0] * x[0] + x[1] * x[1] + x[2] * x[2];
03147 
03148   for(i = 0; i < 3; i++)
03149     force[i] += x[i] / (r2 * sqrt(r2));
03150 
03151   for(n[0] = -4; n[0] <= 4; n[0]++)
03152     for(n[1] = -4; n[1] <= 4; n[1]++)
03153       for(n[2] = -4; n[2] <= 4; n[2]++)
03154         {
03155           for(i = 0; i < 3; i++)
03156             dx[i] = x[i] - n[i];
03157 
03158           r = sqrt(dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]);
03159 
03160           val = erfc(alpha * r) + 2 * alpha * r / sqrt(M_PI) * exp(-alpha * alpha * r * r);
03161 
03162           for(i = 0; i < 3; i++)
03163             force[i] -= dx[i] / (r * r * r) * val;
03164         }
03165 
03166   for(h[0] = -4; h[0] <= 4; h[0]++)
03167     for(h[1] = -4; h[1] <= 4; h[1]++)
03168       for(h[2] = -4; h[2] <= 4; h[2]++)
03169         {
03170           hdotx = x[0] * h[0] + x[1] * h[1] + x[2] * h[2];
03171           h2 = h[0] * h[0] + h[1] * h[1] + h[2] * h[2];
03172 
03173           if(h2 > 0)
03174             {
03175               val = 2.0 / ((double) h2) * exp(-M_PI * M_PI * h2 / (alpha * alpha)) * sin(2 * M_PI * hdotx);
03176 
03177               for(i = 0; i < 3; i++)
03178                 force[i] -= h[i] * val;
03179             }
03180         }
03181 }
03182 
03183 #endif

Generated on Sun May 22 17:33:28 2005 for GADGET-2 by  doxygen 1.3.9.1