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
00103 nfree = All.MaxPart;
00104 nfreep = &Nodes[nfree];
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
00118
00119
00120
00121
00122
00123 force_create_empty_nodes(All.MaxPart, 0, 1, 0, 0, 0, &numnodes, &nfree);
00124
00125
00126
00127
00128
00129
00130
00131 nfreep = &Nodes[nfree];
00132 parent = -1;
00133
00134
00135
00136 for(i = 0; i < npart; i++)
00137 {
00138
00139
00140
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)
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)
00170 {
00171 parent = th;
00172 th = nn;
00173 }
00174 else
00175 {
00176
00177
00178
00179 Nodes[th].u.suns[subnode] = i;
00180 break;
00181 }
00182 }
00183 else
00184 {
00185
00186
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
00229
00230
00231
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;
00242
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
00262 force_insert_pseudo_particles();
00263
00264
00265
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)
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;
00366
00367 while(1)
00368 {
00369 if(th >= All.MaxPart)
00370 {
00371 if(th >= All.MaxPart + MaxNodes)
00372 endrun(888);
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)
00385 {
00386 th = nn;
00387 }
00388 else
00389 {
00390
00391
00392
00393 Nodes[th].u.suns[subnode] = All.MaxPart + MaxNodes + i;
00394
00395 break;
00396 }
00397 }
00398 else
00399 {
00400 endrun(889);
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)
00439 {
00440 for(j = 0; j < 8; j++)
00441 suns[j] = Nodes[no].u.suns[j];
00442
00443 if(last >= 0)
00444 {
00445 if(last >= All.MaxPart)
00446 {
00447 if(last >= All.MaxPart + MaxNodes)
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
00480 for(jj = j + 1; jj < 8; jj++)
00481 if((pp = suns[jj]) >= 0)
00482 break;
00483
00484 if(jj < 8)
00485 nextsib = pp;
00486 else
00487 nextsib = sib;
00488
00489 force_update_node_recursive(p, nextsib, no);
00490
00491
00492 if(p >= All.MaxPart)
00493 {
00494 if(p >= All.MaxPart + MaxNodes)
00495 {
00496
00497
00498
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
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
00642 {
00643 if(last >= 0)
00644 {
00645 if(last >= All.MaxPart)
00646 {
00647 if(last >= All.MaxPart + MaxNodes)
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)
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
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
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
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
00839
00840 for(i = DomainMyStart; i <= DomainMyLast; i++)
00841 {
00842
00843
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
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
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
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;
01168
01169 while(no >= 0)
01170 {
01171 if(no < All.MaxPart)
01172 {
01173
01174
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)
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
01235 {
01236 if(mode == 1)
01237 {
01238 if((nop->u.d.bitflags & 3) == 1)
01239
01240
01241
01242 {
01243 no = nop->u.d.sibling;
01244 continue;
01245 }
01246 }
01247
01248
01249 if(All.ErrTolTheta)
01250 {
01251 if(nop->len * nop->len > r2 * All.ErrTolTheta * All.ErrTolTheta)
01252 {
01253
01254 no = nop->u.d.nextnode;
01255 continue;
01256 }
01257 }
01258 else
01259 {
01260 if(mass * nop->len * nop->len > r2 * r2 * aold)
01261 {
01262
01263 no = nop->u.d.nextnode;
01264 continue;
01265 }
01266
01267
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))
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;
01317
01318 if(mode == 1)
01319 {
01320 if(((nop->u.d.bitflags) & 1))
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
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;
01463
01464 while(no >= 0)
01465 {
01466 if(no < All.MaxPart)
01467 {
01468
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
01506 {
01507 if(no >= All.MaxPart + MaxNodes)
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)
01522
01523
01524
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
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)
01582 {
01583 if(nop->len * nop->len > r2 * All.ErrTolTheta * All.ErrTolTheta)
01584 {
01585
01586 no = nop->u.d.nextnode;
01587 continue;
01588 }
01589 }
01590 else
01591 {
01592 if(mass * nop->len * nop->len > r2 * r2 * aold)
01593 {
01594
01595 no = nop->u.d.nextnode;
01596 continue;
01597 }
01598
01599
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))
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;
01648
01649 if(mode == 1)
01650 {
01651 if(((nop->u.d.bitflags) & 1))
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
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)
01758 {
01759
01760
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)
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
01794 {
01795 openflag = 0;
01796
01797 r2 = dx * dx + dy * dy + dz * dz;
01798
01799 if(All.ErrTolTheta)
01800 {
01801 if(nop->len * nop->len > r2 * All.ErrTolTheta * All.ErrTolTheta)
01802 {
01803 openflag = 1;
01804 }
01805 }
01806 else
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
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
01868
01869
01870 if(nop->len > 0.20 * boxsize)
01871 {
01872
01873 no = nop->u.d.nextnode;
01874 continue;
01875 }
01876 }
01877
01878 no = nop->u.d.sibling;
01879
01880 if(mode == 1)
01881 {
01882 if((nop->u.d.bitflags & 1))
01883 continue;
01884 }
01885 }
01886
01887
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
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
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)
02055 {
02056
02057
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)
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
02118 {
02119 if(mode == 1)
02120 {
02121 if((nop->u.d.bitflags & 3) == 1)
02122
02123
02124
02125
02126 {
02127 no = nop->u.d.sibling;
02128 continue;
02129 }
02130 }
02131
02132 if(All.ErrTolTheta)
02133 {
02134 if(nop->len * nop->len > r2 * All.ErrTolTheta * All.ErrTolTheta)
02135 {
02136
02137 no = nop->u.d.nextnode;
02138 continue;
02139 }
02140 }
02141 else
02142 {
02143 if(mass * nop->len * nop->len > r2 * r2 * aold)
02144 {
02145
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))
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;
02196
02197 if(mode == 1)
02198 {
02199 if(((nop->u.d.bitflags) & 1))
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
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)
02317 {
02318
02319
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)
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
02380 {
02381
02382 if(no >= All.MaxPart + MaxNodes)
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)
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;
02404 dyy = nop->center[1] - pos_y;
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)
02430 {
02431 if(nop->len * nop->len > r2 * All.ErrTolTheta * All.ErrTolTheta)
02432 {
02433
02434 no = nop->u.d.nextnode;
02435 continue;
02436 }
02437 }
02438 else
02439 {
02440 if(mass * nop->len * nop->len > r2 * r2 * aold)
02441 {
02442
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
02469
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;
02496
02497 if(mode == 1)
02498 {
02499 if(((nop->u.d.bitflags) & 1))
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
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
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