12#include "gadgetconfig.h"
22#include "../data/allvars.h"
23#include "../data/dtypes.h"
24#include "../data/intposconvert.h"
25#include "../data/mymalloc.h"
26#include "../domain/domain.h"
27#include "../gravity/ewald.h"
28#include "../gravity/grav_forcetest.h"
29#include "../gravtree/gravtree.h"
30#include "../logs/logs.h"
31#include "../logs/timer.h"
32#include "../main/main.h"
33#include "../main/simulation.h"
34#include "../mpi_utils/generic_comm.h"
35#include "../mpi_utils/mpi_utils.h"
36#include "../ngbtree/ngbtree.h"
38#include "../system/system.h"
39#include "../time_integration/timestep.h"
57 unsigned char SofteningClass;
67#if defined(PMGRID) && defined(PERIODIC) && !defined(TREEPM_NOTIMESPLIT)
68 double AccShortRange[3];
70#ifdef PLACEHIGHRESREGION
71 double AccVeryShortRange[3];
72 double PotVeryShortRange;
79class frctest_comm :
public my_comm
84 : my_comm(dptr, tptr, pptr)
89 using my_comm::Thread;
93 void particle2in(frctest_in *in,
int i)
override
95 for(
int j = 0; j < 3; j++)
96 in->IntPos[j] = Tp->P[i].IntPos[j];
98 in->Type = Tp->P[i].getType();
100 in->SofteningClass = Tp->P[i].getSofteningClass();
104 void out2particle(frctest_out *out,
int i,
int mode)
override
108 Tp->P[i].GravAccelDirect[0] = out->Acc[0];
109 Tp->P[i].GravAccelDirect[1] = out->Acc[1];
110 Tp->P[i].GravAccelDirect[2] = out->Acc[2];
111 Tp->P[i].PotentialDirect = out->Pot;
113 Tp->P[i].DistToID1 = out->DistToID1;
114#if defined(PMGRID) && defined(PERIODIC) && !defined(TREEPM_NOTIMESPLIT)
115 Tp->P[i].GravAccelShortRange[0] = out->AccShortRange[0];
116 Tp->P[i].GravAccelShortRange[1] = out->AccShortRange[1];
117 Tp->P[i].GravAccelShortRange[2] = out->AccShortRange[2];
118 Tp->P[i].PotentialShortRange = out->PotShortRange;
119#ifdef PLACEHIGHRESREGION
120 Tp->P[i].GravAccelVeryShortRange[0] = out->AccVeryShortRange[0];
121 Tp->P[i].GravAccelVeryShortRange[1] = out->AccVeryShortRange[1];
122 Tp->P[i].GravAccelVeryShortRange[2] = out->AccVeryShortRange[2];
123 Tp->P[i].PotentialVeryShortRange = out->PotVeryShortRange;
129 Tp->P[i].GravAccelDirect[0] += out->Acc[0];
130 Tp->P[i].GravAccelDirect[1] += out->Acc[1];
131 Tp->P[i].GravAccelDirect[2] += out->Acc[2];
132 Tp->P[i].PotentialDirect += out->Pot;
133 if(out->DistToID1 > 0)
134 Tp->P[i].DistToID1 = out->DistToID1;
135#if defined(PMGRID) && defined(PERIODIC) && !defined(TREEPM_NOTIMESPLIT)
136 Tp->P[i].GravAccelShortRange[0] += out->AccShortRange[0];
137 Tp->P[i].GravAccelShortRange[1] += out->AccShortRange[1];
138 Tp->P[i].GravAccelShortRange[2] += out->AccShortRange[2];
139 Tp->P[i].PotentialShortRange += out->PotShortRange;
140#ifdef PLACEHIGHRESREGION
141 Tp->P[i].GravAccelVeryShortRange[0] += out->AccVeryShortRange[0];
142 Tp->P[i].GravAccelVeryShortRange[1] += out->AccVeryShortRange[1];
143 Tp->P[i].GravAccelVeryShortRange[2] += out->AccVeryShortRange[2];
144 Tp->P[i].PotentialVeryShortRange += out->PotVeryShortRange;
150 int evaluate(
int target,
int mode,
int thread_id,
int action, frctest_in *in,
int numnodes,
node_info *firstnode,
151 frctest_out &out)
override
156 for(
int n = 0; n < this->D->NTopleaves; n++)
158 int task = D->TaskOfLeaf[n];
160 if(task == D->ThisTask)
163 if(Thread.Exportflag[task] == target)
166 int no = n + this->Tree->MaxPart + this->Tree->MaxNodes;
168 this->Tree->tree_export_node_threads(no, target, &Thread);
176#if defined(PMGRID) && defined(PERIODIC) && !defined(TREEPM_NOTIMESPLIT)
177 out.PotShortRange = 0;
178#ifdef PLACEHIGHRESREGION
179 out.PotVeryShortRange = 0;
182 for(
int i = 0; i < 3; i++)
185#if defined(PMGRID) && defined(PERIODIC) && !defined(TREEPM_NOTIMESPLIT)
186 out.AccShortRange[i] = 0;
187#ifdef PLACEHIGHRESREGION
188 out.AccVeryShortRange[i] = 0;
193 double disttoid1 = 0;
195 for(
int idx = 0; idx < Tp->nsource; idx++)
197 int j = Tp->indexlist[idx];
213 Tp->nearest_image_intpos_to_pos(Tp->P[j].IntPos, intpos, dxyz);
215 double r2 = dxyz[0] * dxyz[0] + dxyz[1] * dxyz[1] + dxyz[2] * dxyz[2];
217 double mass = Tp->P[j].getMass();
223 if(Tp->P[j].ID.get() == 1)
233 double wp_newton, fac_newton;
237 fac_newton = mass / (r2 * r);
238 wp_newton = -mass / r;
255 double h_inv = 1.0 / hmax;
256 double h3_inv = h_inv * h_inv * h_inv;
257 double u = r * h_inv;
267 double u2 = u * u, u3 = u2 * u;
276#if defined(PMGRID) && defined(PERIODIC) && !defined(TREEPM_NOTIMESPLIT)
278 double asmth = Tp->Asmth[0];
279 double u = 0.5 / asmth * r;
281 double factor_force = (
erfc(u) + 2.0 * u /
sqrt(
M_PI) *
exp(-u * u) - 1.0);
282 double factor_pot =
erfc(u);
284 double facs = fac + fac_newton * factor_force;
285 double wps = wp + (r > 0 ? wp_newton * (factor_pot - 1.0) : mass / (asmth *
sqrt(
M_PI)));
287 double acc_short_x = dxyz[0] * facs;
288 double acc_short_y = dxyz[1] * facs;
289 double acc_short_z = dxyz[2] * facs;
291#ifndef GRAVITY_TALLBOX
292 double alpha = 0.5 / asmth;
296 double pot_short = wps;
299 out.AccShortRange[0] += acc_short_x;
300 out.AccShortRange[1] += acc_short_y;
301 out.AccShortRange[2] += acc_short_z;
302 out.PotShortRange += pot_short;
304#ifdef PLACEHIGHRESREGION
305 if(Tp->check_high_res_point_location(Tp->P[j].IntPos) ==
FLAG_INSIDE &&
306 Tp->check_high_res_point_location(intpos) ==
FLAG_INSIDE)
308 double asmth = Tp->Asmth[1];
309 double u = 0.5 / asmth * r;
311 double factor_force = (
erfc(u) + 2.0 * u /
sqrt(
M_PI) *
exp(-u * u) - 1.0);
312 double factor_pot =
erfc(u);
314 double facs = fac + fac_newton * factor_force;
315 double wps = wp + (r > 0 ? wp_newton * (factor_pot - 1.0) : mass / (asmth *
sqrt(
M_PI)));
317 double alpha = 0.5 / asmth;
319 acc_short_x = dxyz[0] * facs;
320 acc_short_y = dxyz[1] * facs;
321 acc_short_z = dxyz[2] * facs;
326 out.AccVeryShortRange[0] += acc_short_x;
327 out.AccVeryShortRange[1] += acc_short_y;
328 out.AccVeryShortRange[2] += acc_short_z;
329 out.PotVeryShortRange += pot_short;
335 out.Acc[0] += fac * dxyz[0];
336 out.Acc[1] += fac * dxyz[1];
337 out.Acc[2] += fac * dxyz[2];
345 out.Pot += mass * ew.
D0phi;
346 out.Acc[0] += mass * ew.
D1phi[0];
347 out.Acc[1] += mass * ew.
D1phi[1];
348 out.Acc[2] += mass * ew.
D1phi[2];
352 out.DistToID1 = disttoid1;
362 int *TargetList = (
int *)
Mem.mymalloc(
"TargetList", Sp->
NumPart *
sizeof(
int));
375#ifdef FORCETEST_FIXEDPARTICLESET
379 P[target].SelectedFlag =
true;
381 P[target].SelectedFlag =
false;
383 if(P[target].SelectedFlag)
384 TargetList[nloc++] = target;
387 TargetList[nloc++] = target;
401#ifdef HIERARCHICAL_GRAVITY
407 for(
int idx = 0; idx < numidx; idx++)
409#ifdef HIERARCHICAL_GRAVITY
418 if(P[target].getMass() == 0)
424 D->mpi_printf(
"FORCETEST: Testing forces for %lld particles out of %lld active ones.\n", ntot,
427 frctest_comm commpattern(this->D, this->GravTree, this->Sp,
this);
436 D->mpi_printf(
"FORCETEST: Testing forces took %g sec.\n", maxt);
448 for(
int idx = 0; idx < nloc; idx++)
450 int i = TargetList[idx];
455 for(
int j = 0; j < 3; j++)
456 Sp->
P[i].GravAccelDirect[j] += fac1 * pos[j];
462 for(
int idx = 0; idx < nloc; idx++)
464 int i = TargetList[idx];
466 for(
int j = 0; j < 3; j++)
468 Sp->
P[i].GravAccelDirect[j] *=
All.
G;
469#if defined(PMGRID) && defined(PERIODIC) && !defined(TREEPM_NOTIMESPLIT)
470 Sp->
P[i].GravAccelShortRange[j] *=
All.
G;
471#ifdef PLACEHIGHRESREGION
472 Sp->
P[i].GravAccelVeryShortRange[j] *=
All.
G;
475#if(FORCETEST_TESTFORCELAW == 3)
476 Sp->
P[i].GravAccelDirectTest[j] *=
All.
G;
486 Sp->
P[i].PotentialDirect += selfpot;
487 Sp->
P[i].PotentialDirect *=
All.
G;
489#if defined(PMGRID) && defined(PERIODIC) && !defined(TREEPM_NOTIMESPLIT)
490 Sp->
P[i].PotentialShortRange += selfpot;
491 Sp->
P[i].PotentialShortRange *=
All.
G;
493#ifdef PLACEHIGHRESREGION
494 Sp->
P[i].PotentialVeryShortRange += selfpot;
495 Sp->
P[i].PotentialVeryShortRange *=
All.
G;
498#if(FORCETEST_TESTFORCELAW == 3)
499 Sp->
P[i].PotentialDirectTest += selfpot;
500 Sp->
P[i].PotentialDirectTest *=
All.
G;
511 for(
int idx = 0; idx < nloc; idx++)
513 int i = TargetList[idx];
518 for(
int j = 0; j < 3; j++)
519 Sp->
P[i].GravAccelDirect[j] += fac1 * pos[j];
525 int *nloc_tab = (
int *)
Mem.mymalloc(
"nloc_tab", D->NTask *
sizeof(
int));
526 MPI_Allgather(&nloc, 1, MPI_INT, nloc_tab, 1, MPI_INT, D->Communicator);
528 for(
int nthis = 0; nthis < D->NTask; nthis++)
530 if(nloc_tab[nthis] > 0)
532 if(nthis == D->ThisTask)
537 if(!(
Logs.FdForceTest = fopen(buf,
"a")))
538 Terminate(
"error in opening file '%s'\n", buf);
540 for(
int idx = 0; idx < nloc; idx++)
542 int i = TargetList[idx];
547#if defined(PMGRID) && defined(PERIODIC) && !defined(TREEPM_NOTIMESPLIT)
549#ifdef PLACEHIGHRESREGION
550 int flaginside = Sp->check_high_res_point_location(P[i].IntPos);
553 "%d %d %lld %g %17.12g %17.12g %17.12g %17.12g %12.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g "
554 "%17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g "
555 "%17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g\n",
556 P[i].getType(), flaginside, (
long long)P[i].ID.get(),
All.
Time, pos[0], pos[1], pos[2], P[i].DistToID1,
557 P[i].GravAccelDirect[0], P[i].GravAccelDirect[1], P[i].GravAccelDirect[2], P[i].GravAccelShortRange[0],
558 P[i].GravAccelShortRange[1], P[i].GravAccelShortRange[2], P[i].GravAccelVeryShortRange[0],
559 P[i].GravAccelVeryShortRange[1], P[i].GravAccelVeryShortRange[2], P[i].GravAccel[0], P[i].GravAccel[1],
560 P[i].GravAccel[2], P[i].GravPM[0], P[i].GravPM[1], P[i].GravPM[2], P[i].GravAccelHPM[0], P[i].GravAccelHPM[1],
561 P[i].GravAccelHPM[2], P[i].PotentialDirect, P[i].PotentialShortRange, P[i].PotentialVeryShortRange,
562 P[i].Potential, P[i].PM_Potential, P[i].PotentialHPM, Sp->Asmth[1]);
566 "%d %d %lld %g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g "
568 "%17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g\n",
569 P[i].getType(), timebin, (
long long)P[i].ID.get(),
All.
Time, pos[0], pos[1], pos[2], P[i].DistToID1,
570 P[i].GravAccelDirect[0], P[i].GravAccelDirect[1], P[i].GravAccelDirect[2], P[i].GravAccelShortRange[0],
571 P[i].GravAccelShortRange[1], P[i].GravAccelShortRange[2], P[i].GravAccel[0], P[i].GravAccel[1],
572 P[i].GravAccel[2], P[i].GravPM[0], P[i].GravPM[1], P[i].GravPM[2], P[i].PotentialDirect,
573 P[i].PotentialShortRange, P[i].Potential, P[i].PM_Potential);
576 fprintf(
Logs.FdForceTest,
577 "%d %d %lld %g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g %17.12g "
579 P[i].getType(), timebin, (
long long)P[i].ID.get(),
All.
Time, pos[0], pos[1], pos[2], P[i].DistToID1,
580 P[i].GravAccelDirect[0], P[i].GravAccelDirect[1], P[i].GravAccelDirect[2], Sp->
P[i].
GravAccel[0],
585 fclose(
Logs.FdForceTest);
588 MPI_Barrier(D->Communicator);
591 Mem.myfree(nloc_tab);
596 double costtotal = Sp->
NumPart * ntot;
599 timebin, ((
double)ntot) / (Sp->
NTask * maxt + 1.0e-20), ntot / ((maxt + 1.0e-20) * Sp->
NTask),
600 ((
double)(costtotal)) / (ntot + 1.0e-20));
605 Mem.myfree(TargetList);
610#ifdef FORCETEST_TESTFORCELAW
612void sim::gravity_forcetest_testforcelaw(
void)
620 for(
int cycle = 0; cycle < Ncycles; cycle++)
622 Domain.mpi_printf(
"\nTEST-FORCE-LAW: cycle=%d|%d ----------------------------------\n\n", cycle, Ncycles);
624 double epsloc = 0, xyzloc[6] = {0, 0, 0, 0, 0, 0};
638 for(
int i = 0; i < 3; i++)
639 xyzloc[3 + i] = xyzloc[i];
641#if defined(PLACEHIGHRESREGION) && (FORCETEST_TESTFORCELAW == 2)
655 MPI_Allreduce(xyzloc, xyz, 6, MPI_DOUBLE, MPI_SUM,
Communicator);
656 MPI_Allreduce(&epsloc, &eps, 1, MPI_DOUBLE, MPI_SUM,
Communicator);
658 double rmin = 0.01 * eps;
669#if defined(PLACEHIGHRESREGION) && (FORCETEST_TESTFORCELAW == 2)
681 double dx = r *
sin(theta) *
cos(phi);
682 double dy = r *
sin(theta) *
sin(phi);
683 double dz = r *
cos(theta);
686 pos[0] = xyz[0] + dx;
687 pos[1] = xyz[1] + dy;
688 pos[2] = xyz[2] + dz;
690#if defined(PLACEHIGHRESREGION) && (FORCETEST_TESTFORCELAW == 2)
693 pos[0] = xyz[3] + dx;
694 pos[1] = xyz[4] + dy;
695 pos[2] = xyz[5] + dz;
715#if defined(PMGRID) && defined(PERIODIC) && !defined(TREEPM_NOTIMESPLIT)
global_data_all_processes All
void ewald_gridlookup(const MyIntPosType *p_intpos, const MyIntPosType *target_intpos, enum interpolate_options flag, ewald_data &fper)
void gravity_forcetest(int timebin)
void pos_to_intpos(T *posdiff, MyIntPosType *intpos)
void intpos_to_pos(MyIntPosType *intpos, T *posdiff)
void constrain_intpos(MyIntPosType *pos)
double timediff(double t0, double t1)
void compute_grav_accelerations(int timebin)
This routine computes the gravitational accelerations for all active particles.
domain< simparticles > Domain
void gravity_long_range_force(void)
void endrun(void)
This function aborts the simulations.
TimeBinData TimeBinsGravity
void mark_active_timebins(void)
#define MAXLEN_PATH_EXTRA
#define MODE_LOCAL_PARTICLES
#define TIMER_START(counter)
Starts the timer counter.
#define TIMER_STOP(counter)
Stops the timer counter.
void sumup_large_ints(int n, int *src, long long *res, MPI_Comm comm)
expr pow(half base, half exp)
int FirstInTimeBin[TIMEBINS]
long long GlobalNActiveParticles
int HighestSynchronizedTimeBin
int ComovingIntegrationOn
char OutputDir[MAXLEN_PATH]
double ForceSoftening[NSOFTCLASSES+NSOFTCLASSES_HYDRO+2]
void setSofteningClass(unsigned char softclass)
unsigned char getSofteningClass(void)
unsigned char getType(void)
vector< MyFloat > GravAccel
void setType(unsigned char type)
void myflush(FILE *fstream)
double get_random_number(void)