Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F85234166
timestep.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Fri, Sep 27, 17:01
Size
43 KB
Mime Type
text/x-c
Expires
Sun, Sep 29, 17:01 (2 d)
Engine
blob
Format
Raw Data
Handle
21146172
Attached To
rGEAR Gear
timestep.c
View Options
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <mpi.h>
#include "allvars.h"
#include "proto.h"
/*! \file timestep.c
* \brief routines for 'kicking' particles in momentum space and assigning new timesteps
*/
static
double
fac1
,
fac2
,
fac3
,
hubble_a
,
atime
,
a3inv
;
static
double
dt_displacement
=
0
;
/*! This function advances the system in momentum space, i.e. it does apply
* the 'kick' operation after the forces have been computed. Additionally, it
* assigns new timesteps to particles. At start-up, a half-timestep is
* carried out, as well as at the end of the simulation. In between, the
* half-step kick that ends the previous timestep and the half-step kick for
* the new timestep are combined into one operation.
*/
void
advance_and_find_timesteps
(
void
)
{
int
i
,
j
,
no
,
ti_step
,
ti_min
,
tend
,
tstart
;
double
dt_entr
,
dt_entr2
,
dt_gravkick
,
dt_hydrokick
,
dt_gravkick2
,
dt_hydrokick2
,
t0
,
t1
;
double
minentropy
,
aphys
;
FLOAT
dv
[
3
];
#ifdef COOLING
double
t2
,
t3
;
#endif
#ifdef FLEXSTEPS
int
ti_grp
;
#endif
#if defined(PSEUDOSYMMETRIC) && !defined(FLEXSTEPS)
double
apred
,
prob
;
int
ti_step2
;
#endif
#ifdef PMGRID
double
dt_gravkickA
,
dt_gravkickB
;
#endif
#ifdef MAKEGLASS
double
disp
,
dispmax
,
globmax
,
dmean
,
fac
,
disp2sum
,
globdisp2sum
;
#endif
t0
=
second
();
if
(
All
.
ComovingIntegrationOn
)
{
fac1
=
1
/
(
All
.
Time
*
All
.
Time
);
fac2
=
1
/
pow
(
All
.
Time
,
3
*
GAMMA
-
2
);
fac3
=
pow
(
All
.
Time
,
3
*
(
1
-
GAMMA
)
/
2.0
);
hubble_a
=
All
.
Omega0
/
(
All
.
Time
*
All
.
Time
*
All
.
Time
)
+
(
1
-
All
.
Omega0
-
All
.
OmegaLambda
)
/
(
All
.
Time
*
All
.
Time
)
+
All
.
OmegaLambda
;
hubble_a
=
All
.
Hubble
*
sqrt
(
hubble_a
);
a3inv
=
1
/
(
All
.
Time
*
All
.
Time
*
All
.
Time
);
atime
=
All
.
Time
;
}
else
fac1
=
fac2
=
fac3
=
hubble_a
=
a3inv
=
atime
=
1
;
#ifdef COOLING_GRACKLE
double
a_now
;
if
(
All
.
ComovingIntegrationOn
)
a_now
=
All
.
Time
;
else
a_now
=
1.
/
(
1.
+
All
.
GrackleRedshift
);
printf
(
"Grackle scaling factor = %g
\n
"
,
a_now
);
#endif
#ifdef NOPMSTEPADJUSTMENT
dt_displacement
=
All
.
MaxSizeTimestep
;
#else
if
(
Flag_FullStep
||
dt_displacement
==
0
)
find_dt_displacement_constraint
(
hubble_a
*
atime
*
atime
);
#endif
#ifdef PMGRID
if
(
All
.
ComovingIntegrationOn
)
dt_gravkickB
=
get_gravkick_factor
(
All
.
PM_Ti_begstep
,
All
.
Ti_Current
)
-
get_gravkick_factor
(
All
.
PM_Ti_begstep
,
(
All
.
PM_Ti_begstep
+
All
.
PM_Ti_endstep
)
/
2
);
else
dt_gravkickB
=
(
All
.
Ti_Current
-
(
All
.
PM_Ti_begstep
+
All
.
PM_Ti_endstep
)
/
2
)
*
All
.
Timebase_interval
;
if
(
All
.
PM_Ti_endstep
==
All
.
Ti_Current
)
/* need to do long-range kick */
{
/* make sure that we reconstruct the domain/tree next time because we don't kick the tree nodes in this case */
All
.
NumForcesSinceLastDomainDecomp
=
1
+
All
.
TotNumPart
*
All
.
TreeDomainUpdateFrequency
;
}
#endif
#ifdef MAKEGLASS
for
(
i
=
0
,
dispmax
=
0
,
disp2sum
=
0
;
i
<
NumPart
;
i
++
)
{
for
(
j
=
0
;
j
<
3
;
j
++
)
{
P
[
i
].
GravPM
[
j
]
*=
-
1
;
P
[
i
].
GravAccel
[
j
]
*=
-
1
;
P
[
i
].
GravAccel
[
j
]
+=
P
[
i
].
GravPM
[
j
];
P
[
i
].
GravPM
[
j
]
=
0
;
}
disp
=
sqrt
(
P
[
i
].
GravAccel
[
0
]
*
P
[
i
].
GravAccel
[
0
]
+
P
[
i
].
GravAccel
[
1
]
*
P
[
i
].
GravAccel
[
1
]
+
P
[
i
].
GravAccel
[
2
]
*
P
[
i
].
GravAccel
[
2
]);
disp
*=
2.0
/
(
3
*
All
.
Hubble
*
All
.
Hubble
);
disp2sum
+=
disp
*
disp
;
if
(
disp
>
dispmax
)
dispmax
=
disp
;
}
MPI_Allreduce
(
&
dispmax
,
&
globmax
,
1
,
MPI_DOUBLE
,
MPI_MAX
,
MPI_COMM_WORLD
);
MPI_Allreduce
(
&
disp2sum
,
&
globdisp2sum
,
1
,
MPI_DOUBLE
,
MPI_SUM
,
MPI_COMM_WORLD
);
dmean
=
pow
(
P
[
0
].
Mass
/
(
All
.
Omega0
*
3
*
All
.
Hubble
*
All
.
Hubble
/
(
8
*
M_PI
*
All
.
G
)),
1.0
/
3
);
if
(
globmax
>
dmean
)
fac
=
dmean
/
globmax
;
else
fac
=
1.0
;
if
(
ThisTask
==
0
)
{
printf
(
"
\n
glass-making: dmean= %g global disp-maximum= %g rms= %g
\n\n
"
,
dmean
,
globmax
,
sqrt
(
globdisp2sum
/
All
.
TotNumPart
));
fflush
(
stdout
);
}
for
(
i
=
0
,
dispmax
=
0
;
i
<
NumPart
;
i
++
)
{
for
(
j
=
0
;
j
<
3
;
j
++
)
{
P
[
i
].
Vel
[
j
]
=
0
;
P
[
i
].
Pos
[
j
]
+=
fac
*
P
[
i
].
GravAccel
[
j
]
*
2.0
/
(
3
*
All
.
Hubble
*
All
.
Hubble
);
P
[
i
].
GravAccel
[
j
]
=
0
;
}
}
#endif
/* Now assign new timesteps and kick */
#ifdef FLEXSTEPS
if
((
All
.
Ti_Current
%
(
4
*
All
.
PresentMinStep
))
==
0
)
if
(
All
.
PresentMinStep
<
TIMEBASE
)
All
.
PresentMinStep
*=
2
;
for
(
i
=
0
;
i
<
NumPart
;
i
++
)
{
if
(
P
[
i
].
Ti_endstep
==
All
.
Ti_Current
)
{
ti_step
=
get_timestep
(
i
,
&
aphys
,
0
);
/* make it a power 2 subdivision */
ti_min
=
TIMEBASE
;
while
(
ti_min
>
ti_step
)
ti_min
>>=
1
;
ti_step
=
ti_min
;
if
(
ti_step
<
All
.
PresentMinStep
)
All
.
PresentMinStep
=
ti_step
;
}
}
ti_step
=
All
.
PresentMinStep
;
MPI_Allreduce
(
&
ti_step
,
&
All
.
PresentMinStep
,
1
,
MPI_INT
,
MPI_MIN
,
MPI_COMM_WORLD
);
if
(
dt_displacement
<
All
.
MaxSizeTimestep
)
ti_step
=
(
int
)
(
dt_displacement
/
All
.
Timebase_interval
);
else
ti_step
=
(
int
)
(
All
.
MaxSizeTimestep
/
All
.
Timebase_interval
);
/* make it a power 2 subdivision */
ti_min
=
TIMEBASE
;
while
(
ti_min
>
ti_step
)
ti_min
>>=
1
;
All
.
PresentMaxStep
=
ti_min
;
if
(
ThisTask
==
0
)
printf
(
"Syn Range = %g PresentMinStep = %d PresentMaxStep = %d
\n
"
,
(
double
)
All
.
PresentMaxStep
/
All
.
PresentMinStep
,
All
.
PresentMinStep
,
All
.
PresentMaxStep
);
#endif
#ifdef SYNCHRONIZE_NGB_TIMESTEP
for
(
i
=
0
;
i
<
NumPart
;
i
++
)
{
P
[
i
].
Old_Ti_begstep
=
P
[
i
].
Ti_begstep
;
P
[
i
].
Old_Ti_endstep
=
P
[
i
].
Ti_endstep
;
}
#endif
for
(
i
=
0
;
i
<
NumPart
;
i
++
)
{
if
(
P
[
i
].
Ti_endstep
==
All
.
Ti_Current
)
{
ti_step
=
get_timestep
(
i
,
&
aphys
,
0
);
/* make it a power 2 subdivision */
ti_min
=
TIMEBASE
;
while
(
ti_min
>
ti_step
)
ti_min
>>=
1
;
ti_step
=
ti_min
;
#ifdef FLEXSTEPS
ti_grp
=
P
[
i
].
FlexStepGrp
%
All
.
PresentMaxStep
;
ti_grp
=
(
ti_grp
/
All
.
PresentMinStep
)
*
All
.
PresentMinStep
;
ti_step
=
((
P
[
i
].
Ti_endstep
+
ti_grp
+
ti_step
)
/
ti_step
)
*
ti_step
-
(
P
[
i
].
Ti_endstep
+
ti_grp
);
#else
#ifdef PSEUDOSYMMETRIC
if
(
P
[
i
].
Type
!=
0
)
{
if
(
P
[
i
].
Ti_endstep
>
P
[
i
].
Ti_begstep
)
{
apred
=
aphys
+
((
aphys
-
P
[
i
].
AphysOld
)
/
(
P
[
i
].
Ti_endstep
-
P
[
i
].
Ti_begstep
))
*
ti_step
;
if
(
fabs
(
apred
-
aphys
)
<
0.5
*
aphys
)
{
ti_step2
=
get_timestep
(
i
,
&
apred
,
-
1
);
ti_min
=
TIMEBASE
;
while
(
ti_min
>
ti_step2
)
ti_min
>>=
1
;
ti_step2
=
ti_min
;
if
(
ti_step2
<
ti_step
)
{
get_timestep
(
i
,
&
apred
,
ti_step
);
prob
=
((
apred
-
aphys
)
/
(
aphys
-
P
[
i
].
AphysOld
)
*
(
P
[
i
].
Ti_endstep
-
P
[
i
].
Ti_begstep
))
/
ti_step
;
if
(
prob
<
get_random_number
(
P
[
i
].
ID
))
ti_step
/=
2
;
}
else
if
(
ti_step2
>
ti_step
)
{
get_timestep
(
i
,
&
apred
,
2
*
ti_step
);
prob
=
((
apred
-
aphys
)
/
(
aphys
-
P
[
i
].
AphysOld
)
*
(
P
[
i
].
Ti_endstep
-
P
[
i
].
Ti_begstep
))
/
ti_step
;
if
(
prob
<
get_random_number
(
P
[
i
].
ID
+
1
))
ti_step
*=
2
;
}
}
}
P
[
i
].
AphysOld
=
aphys
;
}
#endif
#ifdef SYNCHRONIZATION
if
(
ti_step
>
(
P
[
i
].
Ti_endstep
-
P
[
i
].
Ti_begstep
))
/* timestep wants to increase */
{
//if(((TIMEBASE - P[i].Ti_endstep) % ti_step) > 0)
// ti_step = P[i].Ti_endstep - P[i].Ti_begstep; /* leave at old step */
while
(((
TIMEBASE
-
P
[
i
].
Ti_endstep
)
%
ti_step
)
>
0
)
/* yr : allow to increase */
ti_step
=
ti_step
/
2
;
}
#endif
#endif
/* end of FLEXSTEPS */
if
(
All
.
Ti_Current
==
TIMEBASE
)
/* we here finish the last timestep. */
ti_step
=
0
;
if
((
TIMEBASE
-
All
.
Ti_Current
)
<
ti_step
)
/* check that we don't run beyond the end */
ti_step
=
TIMEBASE
-
All
.
Ti_Current
;
#ifdef SYNCHRONIZE_NGB_TIMESTEP
/* Here, in order to performe the synchronization of the time steps
* for neighbor particles, we need to interupt the loop.
*/
P
[
i
].
Ti_step
=
ti_step
;
/* save estimated time step */
}
}
synchronize_ngb_timestep
();
for
(
i
=
0
;
i
<
NumPart
;
i
++
)
{
if
(
P
[
i
].
Old_Ti_endstep
==
All
.
Ti_Current
)
// here we use the old value, avoid problem due to the update of the timesteps
{
ti_step
=
P
[
i
].
Ti_step
;
/* recover from the estimated time step */
#endif
tstart
=
(
P
[
i
].
Ti_begstep
+
P
[
i
].
Ti_endstep
)
/
2
;
/* midpoint of old step */
tend
=
P
[
i
].
Ti_endstep
+
ti_step
/
2
;
/* midpoint of new step */
if
(
All
.
ComovingIntegrationOn
)
{
dt_entr
=
(
tend
-
tstart
)
*
All
.
Timebase_interval
;
dt_entr2
=
(
tend
-
P
[
i
].
Ti_endstep
)
*
All
.
Timebase_interval
;
dt_gravkick
=
get_gravkick_factor
(
tstart
,
tend
);
dt_hydrokick
=
get_hydrokick_factor
(
tstart
,
tend
);
dt_gravkick2
=
get_gravkick_factor
(
P
[
i
].
Ti_endstep
,
tend
);
dt_hydrokick2
=
get_hydrokick_factor
(
P
[
i
].
Ti_endstep
,
tend
);
}
else
{
dt_entr
=
dt_gravkick
=
dt_hydrokick
=
(
tend
-
tstart
)
*
All
.
Timebase_interval
;
dt_gravkick2
=
dt_hydrokick2
=
dt_entr2
=
(
tend
-
P
[
i
].
Ti_endstep
)
*
All
.
Timebase_interval
;
}
P
[
i
].
Ti_begstep
=
P
[
i
].
Ti_endstep
;
P
[
i
].
Ti_endstep
=
P
[
i
].
Ti_begstep
+
ti_step
;
#ifdef CYLINDRICAL_SYMMETRY
double
r
,
factor
;
r
=
sqrt
(
P
[
i
].
Pos
[
0
]
*
P
[
i
].
Pos
[
0
]
+
P
[
i
].
Pos
[
1
]
*
P
[
i
].
Pos
[
1
]
+
P
[
i
].
Pos
[
2
]
*
P
[
i
].
Pos
[
2
]
);
factor
=
1
/
(
r
*
r
)
*
(
P
[
i
].
Pos
[
0
]
*
P
[
i
].
GravAccel
[
0
]
+
P
[
i
].
Pos
[
1
]
*
P
[
i
].
GravAccel
[
1
]);
P
[
i
].
GravAccel
[
0
]
=
factor
*
P
[
i
].
Pos
[
0
];
P
[
i
].
GravAccel
[
1
]
=
factor
*
P
[
i
].
Pos
[
1
];
#endif
/* do the kick */
for
(
j
=
0
;
j
<
3
;
j
++
)
{
dv
[
j
]
=
0.0
;
#ifdef LIMIT_DVEL
if
(
fabs
(
P
[
i
].
GravAccel
[
j
]
*
dt_gravkick
)
>
LIMIT_DVEL
)
{
#ifdef MULTIPHASE
printf
(
"Warning(LIMIT_DVEL): ID=%d j=%d dv[j]=%g Phase=%d(setting GravAccel[j] to 0.0)
\n
"
,
P
[
i
].
ID
,
j
,
P
[
i
].
GravAccel
[
j
]
*
dt_hydrokick
,
SphP
[
i
].
Phase
);
#else
printf
(
"Warning(LIMIT_DVEL): ID=%d j=%d dv[j]=%g Phase=-(setting GravAccel[j] to 0.0)
\n
"
,
P
[
i
].
ID
,
j
,
P
[
i
].
GravAccel
[
j
]
*
dt_hydrokick
);
#endif
P
[
i
].
GravAccel
[
j
]
=
0.0
;
}
#endif
dv
[
j
]
+=
P
[
i
].
GravAccel
[
j
]
*
dt_gravkick
;
P
[
i
].
Vel
[
j
]
+=
P
[
i
].
GravAccel
[
j
]
*
dt_gravkick
;
}
if
(
P
[
i
].
Type
==
0
)
/* SPH stuff */
{
for
(
j
=
0
;
j
<
3
;
j
++
)
{
#ifdef LIMIT_DVEL
/* begin LIMIT_DVEL */
if
(
fabs
(
SphP
[
i
].
HydroAccel
[
j
]
*
dt_hydrokick
)
>
LIMIT_DVEL
)
{
#ifdef MULTIPHASE
printf
(
"Warning(LIMIT_DVEL): ID=%d j=%d dv[j]=%g Phase=%d(setting HydroAccel[j] to 0.0)
\n
"
,
P
[
i
].
ID
,
j
,
SphP
[
i
].
HydroAccel
[
j
]
*
dt_hydrokick
,
SphP
[
i
].
Phase
);
#else
printf
(
"Warning(LIMIT_DVEL): ID=%d j=%d dv[j]=%g Phase=-(setting HydroAccel[j] to 0.0)
\n
"
,
P
[
i
].
ID
,
j
,
SphP
[
i
].
HydroAccel
[
j
]
*
dt_hydrokick
);
#endif
SphP
[
i
].
HydroAccel
[
j
]
=
0.0
;
}
#endif
/* end LIMIT_DVEL */
dv
[
j
]
+=
SphP
[
i
].
HydroAccel
[
j
]
*
dt_hydrokick
;
P
[
i
].
Vel
[
j
]
+=
SphP
[
i
].
HydroAccel
[
j
]
*
dt_hydrokick
;
SphP
[
i
].
VelPred
[
j
]
=
P
[
i
].
Vel
[
j
]
-
dt_gravkick2
*
P
[
i
].
GravAccel
[
j
]
-
dt_hydrokick2
*
SphP
[
i
].
HydroAccel
[
j
];
#ifdef PMGRID
SphP
[
i
].
VelPred
[
j
]
+=
P
[
i
].
GravPM
[
j
]
*
dt_gravkickB
;
#endif
#ifdef AB_TURB
dv
[
j
]
+=
SphP
[
i
].
TurbAccel
[
j
]
*
dt_hydrokick
;
P
[
i
].
Vel
[
j
]
+=
SphP
[
i
].
TurbAccel
[
j
]
*
dt_hydrokick
;
SphP
[
i
].
VelPred
[
j
]
+=
-
dt_hydrokick2
*
SphP
[
i
].
TurbAccel
[
j
];
#endif
#ifdef DISSIPATION_FORCES
dv
[
j
]
+=
SphP
[
i
].
DissipationForcesAccel
[
j
]
*
dt_hydrokick
;
P
[
i
].
Vel
[
j
]
+=
SphP
[
i
].
DissipationForcesAccel
[
j
]
*
dt_hydrokick
;
SphP
[
i
].
VelPred
[
j
]
+=
-
dt_hydrokick2
*
SphP
[
i
].
DissipationForcesAccel
[
j
]
;
#endif
}
/***********************************************************/
/* compute spec energy lost/win by different other process */
/***********************************************************/
/***********************************************************/
/* compute entropy variation */
/***********************************************************/
/*******************************/
/* compute cooling */
/*******************************/
#ifdef COOLING
t2
=
second
();
#ifdef COOLING_GRACKLE
CoolingForOne_GRACKLE
(
i
,
dt_entr
,
dt_entr2
,
ti_step
/
2
*
All
.
Timebase_interval
,
a_now
,
a3inv
);
#else
CoolingForOne
(
i
,
tstart
,
tend
,
ti_step
,
dt_entr2
,
a3inv
,
hubble_a
);
#endif
t3
=
second
();
All
.
CPU_Cooling
+=
timediff
(
t2
,
t3
);
#else
/* In case of cooling, we prevent that the entropy (and
hence temperature decreases by more than a factor 0.5 */
if
(
SphP
[
i
].
DtEntropy
*
dt_entr
>
-
0.5
*
SphP
[
i
].
Entropy
)
SphP
[
i
].
Entropy
+=
SphP
[
i
].
DtEntropy
*
dt_entr
;
else
SphP
[
i
].
Entropy
*=
0.5
;
#ifdef MULTIPHASE
if
(
SphP
[
i
].
Phase
==
GAS_SPH
)
{
#endif
if
(
All
.
MinEgySpec
)
{
#ifdef DENSITY_INDEPENDENT_SPH
minentropy
=
All
.
MinEgySpec
*
GAMMA_MINUS1
/
pow
(
SphP
[
i
].
EgyWtDensity
*
a3inv
,
GAMMA_MINUS1
);
#else
minentropy
=
All
.
MinEgySpec
*
GAMMA_MINUS1
/
pow
(
SphP
[
i
].
Density
*
a3inv
,
GAMMA_MINUS1
);
#endif
if
(
SphP
[
i
].
Entropy
<
minentropy
)
{
SphP
[
i
].
Entropy
=
minentropy
;
SphP
[
i
].
DtEntropy
=
0
;
}
}
#ifdef MULTIPHASE
}
#endif
#endif
/* COOLING */
#ifndef COOLING
/* In case the timestep increases in the new step, we
make sure that we do not 'overcool' when deriving
predicted temperatures. The maximum timespan over
which prediction can occur is ti_step/2, i.e. from
the middle to the end of the current step */
//dt_entr = ti_step / 2 * All.Timebase_interval;
dt_entr
=
imax
(
ti_step
/
2
,
1
)
*
All
.
Timebase_interval
;
/* yr : prevent dt_entr to be zero if ti_step=1 */
if
(
SphP
[
i
].
Entropy
+
SphP
[
i
].
DtEntropy
*
dt_entr
<
0.5
*
SphP
[
i
].
Entropy
)
SphP
[
i
].
DtEntropy
=
-
0.5
*
SphP
[
i
].
Entropy
/
dt_entr
;
#ifdef ENTROPYPRED
/* now, we correct the predicted Entropy */
SphP
[
i
].
EntropyPred
=
SphP
[
i
].
Entropy
-
dt_entr2
*
SphP
[
i
].
DtEntropy
;
#ifdef COOLING
// if(All.MinEgySpec)
// minentropy = All.MinEgySpec * GAMMA_MINUS1 / pow(SphP[i].Density * a3inv, GAMMA_MINUS1);
// else
// minentropy=0;
//
// //dt_entr = imax(ti_step,1) * All.Timebase_interval;
// //if (SphP[i].EntropyPred + SphP[i].DtEntropy * dt_entr < minentropy) /* if during the next step prediction entropy may be less than zero */
// // SphP[i].DtEntropy = -(SphP[i].EntropyPred-minentropy) / dt_entr; /* modify SphP[i].DtEntropy in order to avoid problems */
//
// dt_entr = imax(ti_step / 2,1) * All.Timebase_interval;
// if(SphP[i].Entropy + SphP[i].DtEntropy * dt_entr < 0.5 * SphP[i].Entropy)
// {
// printf("(%d) particle id=%d reduces its DtEntropy (Entropy=%g DtEntropy * dt_entr=%g)\n",NTask,P[i].ID,SphP[i].Entropy,SphP[i].DtEntropy * dt_entr);
// SphP[i].DtEntropy = -0.5 * SphP[i].Entropy / dt_entr;
// }
#endif
/* COOLING */
#ifdef CHECK_ENTROPY_SIGN
if
((
SphP
[
i
].
EntropyPred
<
0
))
{
printf
(
"
\n
task=%d: EntropyPred less than zero in advance_and_find_timesteps !
\n
"
,
ThisTask
);
printf
(
"ID=%d Entropy=%g EntropyPred=%g DtEntropy=%g dt_entr=%g
\n
"
,
P
[
i
].
ID
,
SphP
[
i
].
Entropy
,
SphP
[
i
].
EntropyPred
,
SphP
[
i
].
DtEntropy
,
dt_entr
);
fflush
(
stdout
);
endrun
(
1010101000
);
}
#endif
#endif
/* ENTROPYPRED */
#endif
/* no COOLING */
#ifdef DISSIPATION_FORCES
dt_entr
=
imax
(
ti_step
/
2
,
1
)
*
All
.
Timebase_interval
;
/* yr : prevent dt_entr to be zero if ti_step=1 */
SphP
[
i
].
EnergyDissipationForces
+=
SphP
[
i
].
DtEnergyDissipationForces
*
dt_entr
;
#endif
}
/* if tree is not going to be reconstructed, kick parent nodes dynamically.
*/
if
(
All
.
NumForcesSinceLastDomainDecomp
<
All
.
TotNumPart
*
All
.
TreeDomainUpdateFrequency
)
{
no
=
Father
[
i
];
while
(
no
>=
0
)
{
for
(
j
=
0
;
j
<
3
;
j
++
)
Extnodes
[
no
].
vs
[
j
]
+=
dv
[
j
]
*
P
[
i
].
Mass
/
Nodes
[
no
].
u
.
d
.
mass
;
no
=
Nodes
[
no
].
u
.
d
.
father
;
}
}
}
}
#ifdef PMGRID
if
(
All
.
PM_Ti_endstep
==
All
.
Ti_Current
)
/* need to do long-range kick */
{
ti_step
=
TIMEBASE
;
while
(
ti_step
>
(
dt_displacement
/
All
.
Timebase_interval
))
ti_step
>>=
1
;
if
(
ti_step
>
(
All
.
PM_Ti_endstep
-
All
.
PM_Ti_begstep
))
/* PM-timestep wants to increase */
{
/* we only increase if an integer number of steps will bring us to the end */
if
(((
TIMEBASE
-
All
.
PM_Ti_endstep
)
%
ti_step
)
>
0
)
ti_step
=
All
.
PM_Ti_endstep
-
All
.
PM_Ti_begstep
;
/* leave at old step */
}
if
(
All
.
Ti_Current
==
TIMEBASE
)
/* we here finish the last timestep. */
ti_step
=
0
;
tstart
=
(
All
.
PM_Ti_begstep
+
All
.
PM_Ti_endstep
)
/
2
;
tend
=
All
.
PM_Ti_endstep
+
ti_step
/
2
;
if
(
All
.
ComovingIntegrationOn
)
dt_gravkick
=
get_gravkick_factor
(
tstart
,
tend
);
else
dt_gravkick
=
(
tend
-
tstart
)
*
All
.
Timebase_interval
;
All
.
PM_Ti_begstep
=
All
.
PM_Ti_endstep
;
All
.
PM_Ti_endstep
=
All
.
PM_Ti_begstep
+
ti_step
;
if
(
All
.
ComovingIntegrationOn
)
dt_gravkickB
=
-
get_gravkick_factor
(
All
.
PM_Ti_begstep
,
(
All
.
PM_Ti_begstep
+
All
.
PM_Ti_endstep
)
/
2
);
else
dt_gravkickB
=
-
((
All
.
PM_Ti_begstep
+
All
.
PM_Ti_endstep
)
/
2
-
All
.
PM_Ti_begstep
)
*
All
.
Timebase_interval
;
for
(
i
=
0
;
i
<
NumPart
;
i
++
)
{
for
(
j
=
0
;
j
<
3
;
j
++
)
/* do the kick */
P
[
i
].
Vel
[
j
]
+=
P
[
i
].
GravPM
[
j
]
*
dt_gravkick
;
if
(
P
[
i
].
Type
==
0
)
{
if
(
All
.
ComovingIntegrationOn
)
{
dt_gravkickA
=
get_gravkick_factor
(
P
[
i
].
Ti_begstep
,
All
.
Ti_Current
)
-
get_gravkick_factor
(
P
[
i
].
Ti_begstep
,
(
P
[
i
].
Ti_begstep
+
P
[
i
].
Ti_endstep
)
/
2
);
dt_hydrokick
=
get_hydrokick_factor
(
P
[
i
].
Ti_begstep
,
All
.
Ti_Current
)
-
get_hydrokick_factor
(
P
[
i
].
Ti_begstep
,
(
P
[
i
].
Ti_begstep
+
P
[
i
].
Ti_endstep
)
/
2
);
}
else
dt_gravkickA
=
dt_hydrokick
=
(
All
.
Ti_Current
-
(
P
[
i
].
Ti_begstep
+
P
[
i
].
Ti_endstep
)
/
2
)
*
All
.
Timebase_interval
;
for
(
j
=
0
;
j
<
3
;
j
++
)
SphP
[
i
].
VelPred
[
j
]
=
P
[
i
].
Vel
[
j
]
+
P
[
i
].
GravAccel
[
j
]
*
dt_gravkickA
+
SphP
[
i
].
HydroAccel
[
j
]
*
dt_hydrokick
+
P
[
i
].
GravPM
[
j
]
*
dt_gravkickB
;
}
}
}
#endif
#ifdef CHIMIE_THERMAL_FEEDBACK
chimie_apply_thermal_feedback
();
#endif
t1
=
second
();
All
.
CPU_TimeLine
+=
timediff
(
t0
,
t1
);
#ifdef DETAILED_CPU
All
.
CPU_Leapfrog
+=
timediff
(
t0
,
t1
);
#endif
#ifdef COOLING
//All.CPU_TimeLine -= All.CPU_Cooling;
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
if
(
SetMinTimeStepForActives
)
SetMinTimeStepForActives
=
0
;
#endif
#ifdef SYNCHRONIZE_NGB_TIMESTEP
#ifdef OUTPUTOPTVAR1
for
(
i
=
0
;
i
<
N_gas
;
i
++
)
SphP
[
i
].
OptVar1
=
(
float
)
(
P
[
i
].
Ti_endstep
-
P
[
i
].
Ti_begstep
);
#endif
#endif
}
/*! This function normally (for flag==0) returns the maximum allowed timestep
* of a particle, expressed in terms of the integer mapping that is used to
* represent the total simulated timespan. The physical acceleration is
* returned in `aphys'. The latter is used in conjunction with the
* PSEUDOSYMMETRIC integration option, which also makes of the second
* function of get_timestep. When it is called with a finite timestep for
* flag, it returns the physical acceleration that would lead to this
* timestep, assuming timestep criterion 0.
*/
int
get_timestep
(
int
p
,
/*!< particle index */
double
*
aphys
,
/*!< acceleration (physical units) */
int
flag
/*!< either 0 for normal operation, or finite timestep to get corresponding
aphys */
)
{
double
ax
,
ay
,
az
,
ac
,
csnd
;
double
dt
=
0
,
dt_courant
=
0
,
dt_accel
;
int
ti_step
;
#ifdef CONDUCTION
double
dt_cond
;
#endif
if
(
flag
==
0
)
{
ax
=
fac1
*
P
[
p
].
GravAccel
[
0
];
ay
=
fac1
*
P
[
p
].
GravAccel
[
1
];
az
=
fac1
*
P
[
p
].
GravAccel
[
2
];
#ifdef PMGRID
ax
+=
fac1
*
P
[
p
].
GravPM
[
0
];
ay
+=
fac1
*
P
[
p
].
GravPM
[
1
];
az
+=
fac1
*
P
[
p
].
GravPM
[
2
];
#endif
if
(
P
[
p
].
Type
==
0
)
{
#ifndef TIMESTEP_UPDATE_FOR_FEEDBACK
ax
+=
fac2
*
SphP
[
p
].
HydroAccel
[
0
];
ay
+=
fac2
*
SphP
[
p
].
HydroAccel
[
1
];
az
+=
fac2
*
SphP
[
p
].
HydroAccel
[
2
];
#else
#ifdef CHIMIE_THERMAL_FEEDBACK
if
((
SphP
[
p
].
DeltaEgySpec
==-
1
)
||
(
SphP
[
p
].
DeltaEgySpec
>
0
))
{
ax
+=
fac2
*
SphP
[
p
].
FeedbackUpdatedAccel
[
0
];
ay
+=
fac2
*
SphP
[
p
].
FeedbackUpdatedAccel
[
1
];
az
+=
fac2
*
SphP
[
p
].
FeedbackUpdatedAccel
[
2
];
if
(
SphP
[
p
].
DeltaEgySpec
==-
1
)
SphP
[
p
].
DeltaEgySpec
=
0
;
/* unflag */
}
else
{
ax
+=
fac2
*
SphP
[
p
].
HydroAccel
[
0
];
ay
+=
fac2
*
SphP
[
p
].
HydroAccel
[
1
];
az
+=
fac2
*
SphP
[
p
].
HydroAccel
[
2
];
}
#else
ax
+=
fac2
*
SphP
[
p
].
HydroAccel
[
0
];
ay
+=
fac2
*
SphP
[
p
].
HydroAccel
[
1
];
az
+=
fac2
*
SphP
[
p
].
HydroAccel
[
2
];
#endif
#endif
#ifdef DISSIPATION_FORCES
ax
+=
fac2
*
SphP
[
p
].
DissipationForcesAccel
[
0
];
ay
+=
fac2
*
SphP
[
p
].
DissipationForcesAccel
[
1
];
az
+=
fac2
*
SphP
[
p
].
DissipationForcesAccel
[
2
];
#endif
#ifdef AB_TURB
ax
+=
fac2
*
SphP
[
p
].
TurbAccel
[
0
];
ay
+=
fac2
*
SphP
[
p
].
TurbAccel
[
1
];
az
+=
fac2
*
SphP
[
p
].
TurbAccel
[
2
];
#endif
}
ac
=
sqrt
(
ax
*
ax
+
ay
*
ay
+
az
*
az
);
/* this is now the physical acceleration */
*
aphys
=
ac
;
}
else
ac
=
*
aphys
;
if
(
ac
==
0
)
ac
=
1.0e-30
;
switch
(
All
.
TypeOfTimestepCriterion
)
{
case
0
:
if
(
flag
>
0
)
{
dt
=
flag
*
All
.
Timebase_interval
;
dt
/=
hubble_a
;
/* convert dloga to physical timestep */
ac
=
2
*
All
.
ErrTolIntAccuracy
*
atime
*
All
.
SofteningTable
[
P
[
p
].
Type
]
/
(
dt
*
dt
);
*
aphys
=
ac
;
return
flag
;
}
#ifdef IMPROVED_TIMESTEP_CRITERION_FORGAS
if
(
P
[
p
].
Type
==
0
)
dt
=
dt_accel
=
sqrt
(
2
*
All
.
ErrTolIntAccuracy
*
atime
*
dmin
(
SphP
[
p
].
Hsml
,
All
.
SofteningTable
[
P
[
p
].
Type
])
/
ac
);
else
dt
=
dt_accel
=
sqrt
(
2
*
All
.
ErrTolIntAccuracy
*
atime
*
All
.
SofteningTable
[
P
[
p
].
Type
]
/
ac
);
#else
dt
=
dt_accel
=
sqrt
(
2
*
All
.
ErrTolIntAccuracy
*
atime
*
All
.
SofteningTable
[
P
[
p
].
Type
]
/
ac
);
#endif
#ifdef ADAPTIVE_GRAVSOFT_FORGAS
if
(
P
[
p
].
Type
==
0
)
dt
=
dt_accel
=
sqrt
(
2
*
All
.
ErrTolIntAccuracy
*
atime
*
SphP
[
p
].
Hsml
/
2.8
/
ac
);
#endif
break
;
default:
endrun
(
888
);
break
;
}
if
(
P
[
p
].
Type
==
0
)
{
#ifdef DENSITY_INDEPENDENT_SPH
csnd
=
sqrt
(
GAMMA
*
SphP
[
p
].
Pressure
/
SphP
[
p
].
EgyWtDensity
);
#else
csnd
=
sqrt
(
GAMMA
*
SphP
[
p
].
Pressure
/
SphP
[
p
].
Density
);
#endif
if
(
All
.
ComovingIntegrationOn
)
dt_courant
=
2
*
All
.
CourantFac
*
All
.
Time
*
SphP
[
p
].
Hsml
/
(
fac3
*
SphP
[
p
].
MaxSignalVel
);
else
dt_courant
=
2
*
All
.
CourantFac
*
SphP
[
p
].
Hsml
/
SphP
[
p
].
MaxSignalVel
;
if
(
dt_courant
<
dt
)
#ifndef MULTIPHASE
dt
=
dt_courant
;
#else
{
if
(
SphP
[
p
].
MaxSignalVel
!=
0
);
dt
=
dt_courant
;
}
#endif
// #ifdef CHIMIE_THERMAL_FEEDBACK
//
// float f;
// double EgySpec,NewEgySpec;
//
// if (SphP[p].DeltaEgySpec > 0)
// {
//
// /* spec energy at current step */
// EgySpec = SphP[p].EntropyPred / GAMMA_MINUS1 * pow(SphP[p].Density*a3inv, GAMMA_MINUS1);
//
// /* new egyspec */
// NewEgySpec = EgySpec + SphP[p].DeltaEgySpec;
//
// f = NewEgySpec/EgySpec;
//
// //if (f>1)
// // dt = dt / f;
// }
//
// #endif
#ifdef CHIMIE_KINETIC_FEEDBACK
double
dt_kinetic_feedback
;
double
SupernovaKieticFeedbackIntAccuracy
=
0.1
;
dt_kinetic_feedback
=
SupernovaKieticFeedbackIntAccuracy
*
All
.
SofteningTable
[
P
[
p
].
Type
]
/
All
.
ChimieWindSpeed
;
if
(
dt_kinetic_feedback
<
dt
)
dt
=
dt_kinetic_feedback
;
#endif
#ifdef FEEDBACK_WIND
double
dt_feedback_wind
;
double
vwind
;
vwind
=
sqrt
(
SphP
[
p
].
FeedbackWindVel
[
0
]
*
SphP
[
p
].
FeedbackWindVel
[
0
]
+
SphP
[
p
].
FeedbackWindVel
[
1
]
*
SphP
[
p
].
FeedbackWindVel
[
1
]
+
SphP
[
p
].
FeedbackWindVel
[
2
]
*
SphP
[
p
].
FeedbackWindVel
[
2
]
);
if
(
vwind
>
0
)
{
dt_feedback_wind
=
All
.
SupernovaWindIntAccuracy
*
All
.
SofteningTable
[
P
[
p
].
Type
]
/
vwind
;
SphP
[
p
].
FeedbackWindVel
[
0
]
=
0
;
SphP
[
p
].
FeedbackWindVel
[
1
]
=
0
;
SphP
[
p
].
FeedbackWindVel
[
2
]
=
0
;
if
(
dt_feedback_wind
<
dt
)
dt
=
dt_feedback_wind
;
}
#endif
}
#ifdef CHIMIE
int
m
;
double
dt_chimie
;
if
(
P
[
p
].
Type
==
ST
)
{
//m = P[p].StPIdx;
//if (StP[m].Flag)
{
dt_chimie
=
All
.
ChimieMaxSizeTimestep
;
}
if
(
dt_chimie
<
dt
)
dt
=
dt_chimie
;
}
#endif
/* convert the physical timestep to dloga if needed. Note: If comoving integration has not been selected,
hubble_a=1.
*/
dt
*=
hubble_a
;
if
(
dt
>=
All
.
MaxSizeTimestep
)
dt
=
All
.
MaxSizeTimestep
;
if
(
dt
>=
dt_displacement
)
dt
=
dt_displacement
;
if
(
dt
<
All
.
MinSizeTimestep
)
{
#ifndef NOSTOP_WHEN_BELOW_MINTIMESTEP
printf
(
"warning: Timestep wants to be below the limit `MinSizeTimestep'
\n
"
);
if
(
P
[
p
].
Type
==
0
)
{
printf
(
"Part-ID=%d dt=%g dtc=%g ac=%g xyz=(%g|%g|%g) hsml=%g maxsignalvel=%g dt0=%g eps=%g
\n
"
,
(
int
)
P
[
p
].
ID
,
dt
,
dt_courant
*
hubble_a
,
ac
,
P
[
p
].
Pos
[
0
],
P
[
p
].
Pos
[
1
],
P
[
p
].
Pos
[
2
],
SphP
[
p
].
Hsml
,
SphP
[
p
].
MaxSignalVel
,
sqrt
(
2
*
All
.
ErrTolIntAccuracy
*
atime
*
All
.
SofteningTable
[
P
[
p
].
Type
]
/
ac
)
*
hubble_a
,
All
.
SofteningTable
[
P
[
p
].
Type
]);
}
else
{
printf
(
"Part-ID=%d dt=%g ac=%g xyz=(%g|%g|%g)
\n
"
,
(
int
)
P
[
p
].
ID
,
dt
,
ac
,
P
[
p
].
Pos
[
0
],
P
[
p
].
Pos
[
1
],
P
[
p
].
Pos
[
2
]);
}
fflush
(
stdout
);
endrun
(
888
);
#endif
dt
=
All
.
MinSizeTimestep
;
}
ti_step
=
dt
/
All
.
Timebase_interval
;
#ifdef CHIMIE_KINETIC_FEEDBACK
//if(SetMinTimeStepForActives)
// ti_step=1;
#endif
if
(
!
(
ti_step
>
0
&&
ti_step
<
TIMEBASE
))
{
printf
(
"
\n
Error: A timestep of size zero was assigned on the integer timeline!
\n
"
"We better stop.
\n
"
"Task=%d Part-ID=%d dt=%g tibase=%g ti_step=%d ac=%g xyz=(%g|%g|%g) tree=(%g|%g%g)
\n\n
"
,
ThisTask
,
(
int
)
P
[
p
].
ID
,
dt
,
All
.
Timebase_interval
,
ti_step
,
ac
,
P
[
p
].
Pos
[
0
],
P
[
p
].
Pos
[
1
],
P
[
p
].
Pos
[
2
],
P
[
p
].
GravAccel
[
0
],
P
[
p
].
GravAccel
[
1
],
P
[
p
].
GravAccel
[
2
]);
#ifdef PMGRID
printf
(
"pm_force=(%g|%g|%g)
\n
"
,
P
[
p
].
GravPM
[
0
],
P
[
p
].
GravPM
[
1
],
P
[
p
].
GravPM
[
2
]);
#endif
if
(
P
[
p
].
Type
==
0
)
printf
(
"hydro-frc=(%g|%g|%g)
\n
"
,
SphP
[
p
].
HydroAccel
[
0
],
SphP
[
p
].
HydroAccel
[
1
],
SphP
[
p
].
HydroAccel
[
2
]);
#ifdef FEEDBACK_WIND
if
(
P
[
p
].
Type
==
0
)
printf
(
"feedback-vel=(%g|%g|%g)
\n
"
,
SphP
[
p
].
FeedbackWindVel
[
0
],
SphP
[
p
].
FeedbackWindVel
[
1
],
SphP
[
p
].
FeedbackWindVel
[
2
]);
#endif
fflush
(
stdout
);
endrun
(
818
);
}
return
ti_step
;
}
/*! This function computes an upper limit ('dt_displacement') to the global
* timestep of the system based on the rms velocities of particles. For
* cosmological simulations, the criterion used is that the rms displacement
* should be at most a fraction MaxRMSDisplacementFac of the mean particle
* separation. Note that the latter is estimated using the assigned particle
* masses, separately for each particle type. If comoving integration is not
* used, the function imposes no constraint on the timestep.
*/
void
find_dt_displacement_constraint
(
double
hfac
/*!< should be a^2*H(a) */
)
{
int
i
,
j
,
type
,
*
temp
;
int
count
[
6
];
long
long
count_sum
[
6
];
double
v
[
6
],
v_sum
[
6
],
mim
[
6
],
min_mass
[
6
];
double
dt
,
dmean
,
asmth
=
0
;
dt_displacement
=
All
.
MaxSizeTimestep
;
if
(
All
.
ComovingIntegrationOn
)
{
for
(
type
=
0
;
type
<
6
;
type
++
)
{
count
[
type
]
=
0
;
v
[
type
]
=
0
;
mim
[
type
]
=
1.0e30
;
}
for
(
i
=
0
;
i
<
NumPart
;
i
++
)
{
v
[
P
[
i
].
Type
]
+=
P
[
i
].
Vel
[
0
]
*
P
[
i
].
Vel
[
0
]
+
P
[
i
].
Vel
[
1
]
*
P
[
i
].
Vel
[
1
]
+
P
[
i
].
Vel
[
2
]
*
P
[
i
].
Vel
[
2
];
if
(
mim
[
P
[
i
].
Type
]
>
P
[
i
].
Mass
)
mim
[
P
[
i
].
Type
]
=
P
[
i
].
Mass
;
count
[
P
[
i
].
Type
]
++
;
}
MPI_Allreduce
(
v
,
v_sum
,
6
,
MPI_DOUBLE
,
MPI_SUM
,
MPI_COMM_WORLD
);
MPI_Allreduce
(
mim
,
min_mass
,
6
,
MPI_DOUBLE
,
MPI_MIN
,
MPI_COMM_WORLD
);
temp
=
malloc
(
NTask
*
6
*
sizeof
(
int
));
MPI_Allgather
(
count
,
6
,
MPI_INT
,
temp
,
6
,
MPI_INT
,
MPI_COMM_WORLD
);
for
(
i
=
0
;
i
<
6
;
i
++
)
{
count_sum
[
i
]
=
0
;
for
(
j
=
0
;
j
<
NTask
;
j
++
)
count_sum
[
i
]
+=
temp
[
j
*
6
+
i
];
}
free
(
temp
);
for
(
type
=
0
;
type
<
6
;
type
++
)
{
if
(
count_sum
[
type
]
>
0
)
{
if
(
type
==
0
)
dmean
=
pow
(
min_mass
[
type
]
/
(
All
.
OmegaBaryon
*
3
*
All
.
Hubble
*
All
.
Hubble
/
(
8
*
M_PI
*
All
.
G
)),
1.0
/
3
);
else
dmean
=
pow
(
min_mass
[
type
]
/
((
All
.
Omega0
-
All
.
OmegaBaryon
)
*
3
*
All
.
Hubble
*
All
.
Hubble
/
(
8
*
M_PI
*
All
.
G
)),
1.0
/
3
);
dt
=
All
.
MaxRMSDisplacementFac
*
hfac
*
dmean
/
sqrt
(
v_sum
[
type
]
/
count_sum
[
type
]);
#ifdef PMGRID
asmth
=
All
.
Asmth
[
0
];
#ifdef PLACEHIGHRESREGION
if
(((
1
<<
type
)
&
(
PLACEHIGHRESREGION
)))
asmth
=
All
.
Asmth
[
1
];
#endif
if
(
asmth
<
dmean
)
dt
=
All
.
MaxRMSDisplacementFac
*
hfac
*
asmth
/
sqrt
(
v_sum
[
type
]
/
count_sum
[
type
]);
#endif
if
(
ThisTask
==
0
)
printf
(
"type=%d dmean=%g asmth=%g minmass=%g a=%g sqrt(<p^2>)=%g dlogmax=%g
\n
"
,
type
,
dmean
,
asmth
,
min_mass
[
type
],
All
.
Time
,
sqrt
(
v_sum
[
type
]
/
count_sum
[
type
]),
dt
);
if
(
dt
<
dt_displacement
)
dt_displacement
=
dt
;
}
}
if
(
ThisTask
==
0
)
printf
(
"displacement time constraint: %g (%g)
\n
"
,
dt_displacement
,
All
.
MaxSizeTimestep
);
}
}
#ifdef SYNCHRONIZE_NGB_TIMESTEP
#ifdef PERIODIC
static
double
boxSize
,
boxHalf
;
#ifdef LONG_X
static
double
boxSize_X
,
boxHalf_X
;
#else
#define boxSize_X boxSize
#define boxHalf_X boxHalf
#endif
#ifdef LONG_Y
static
double
boxSize_Y
,
boxHalf_Y
;
#else
#define boxSize_Y boxSize
#define boxHalf_Y boxHalf
#endif
#ifdef LONG_Z
static
double
boxSize_Z
,
boxHalf_Z
;
#else
#define boxSize_Z boxSize
#define boxHalf_Z boxHalf
#endif
#endif
static
int
NDone
;
static
long
long
NTotDone
;
/*! This function share the timesteps between particles
* according the the Saitoh and Makino rule.
*/
void
synchronize_ngb_timestep
()
{
long
long
ntot
,
ntotleft
;
int
i
,
j
,
k
,
n
,
ngrp
,
maxfill
,
source
,
ndone
;
int
*
nbuffer
,
*
noffset
,
*
nsend_local
,
*
nsend
,
*
numlist
,
*
ndonelist
;
int
level
,
sendTask
,
recvTask
,
nexport
,
place
;
double
t0
,
t1
;
double
timecomp
=
0
,
timeimbalance
=
0
,
timecommsumm
=
0
;
MPI_Status
status
;
int
CptLimit
=
0
;
int
shrinkcount
=
0
,
shrinktot
=
0
;
int
tstart
,
tend
;
double
dt_entr
;
double
dt_gravkick
;
double
dt_hydrokick
;
int
counter
;
#ifdef PERIODIC
boxSize
=
All
.
BoxSize
;
boxHalf
=
0.5
*
All
.
BoxSize
;
#ifdef LONG_X
boxHalf_X
=
boxHalf
*
LONG_X
;
boxSize_X
=
boxSize
*
LONG_X
;
#endif
#ifdef LONG_Y
boxHalf_Y
=
boxHalf
*
LONG_Y
;
boxSize_Y
=
boxSize
*
LONG_Y
;
#endif
#ifdef LONG_Z
boxHalf_Z
=
boxHalf
*
LONG_Z
;
boxSize_Z
=
boxSize
*
LONG_Z
;
#endif
#endif
/* `NumSphUpdate' gives the number of particles on this processor that want a force update */
for
(
n
=
0
,
NumSphUpdate
=
0
;
n
<
N_gas
;
n
++
)
{
#ifdef SFR
if
((
P
[
n
].
Ti_endstep
==
All
.
Ti_Current
)
&&
(
P
[
n
].
Type
==
0
))
#else
if
(
P
[
n
].
Ti_endstep
==
All
.
Ti_Current
)
#endif
#ifdef MULTIPHASE
if
(
SphP
[
n
].
Phase
==
GAS_SPH
)
#endif
NumSphUpdate
++
;
}
numlist
=
malloc
(
NTask
*
sizeof
(
int
)
*
NTask
);
MPI_Allgather
(
&
NumSphUpdate
,
1
,
MPI_INT
,
numlist
,
1
,
MPI_INT
,
MPI_COMM_WORLD
);
for
(
i
=
0
,
ntot
=
0
;
i
<
NTask
;
i
++
)
ntot
+=
numlist
[
i
];
free
(
numlist
);
noffset
=
malloc
(
sizeof
(
int
)
*
NTask
);
/* offsets of bunches in common list */
nbuffer
=
malloc
(
sizeof
(
int
)
*
NTask
);
nsend_local
=
malloc
(
sizeof
(
int
)
*
NTask
);
nsend
=
malloc
(
sizeof
(
int
)
*
NTask
*
NTask
);
ndonelist
=
malloc
(
sizeof
(
int
)
*
NTask
);
if
(
ThisTask
==
0
)
printf
(
"start synchronize ngb timestep
\n
"
);
NTotDone
=
1
;
//NTotDone=0; /* if we want to disable the multi loop */
/* loop for time-step limiter */
while
(
NTotDone
>
0
)
{
NDone
=
0
;
i
=
0
;
/* first particle for this task */
ntotleft
=
ntot
;
/* particles left for all tasks together */
while
(
ntotleft
>
0
)
{
for
(
j
=
0
;
j
<
NTask
;
j
++
)
nsend_local
[
j
]
=
0
;
/* do local particles and prepare export list */
t0
=
second
();
for
(
nexport
=
0
,
ndone
=
0
;
i
<
N_gas
&&
nexport
<
All
.
BunchSizeSynchronizeNgBTimestep
-
NTask
;
i
++
)
#ifdef SFR
if
((
P
[
i
].
Ti_endstep
==
All
.
Ti_Current
)
&&
(
P
[
i
].
Type
==
0
))
#else
if
(
P
[
i
].
Ti_endstep
==
All
.
Ti_Current
)
#endif
{
{
ndone
++
;
for
(
j
=
0
;
j
<
NTask
;
j
++
)
Exportflag
[
j
]
=
0
;
NDone
+=
synchronize_ngb_timestep_evaluate
(
i
,
0
);
for
(
j
=
0
;
j
<
NTask
;
j
++
)
{
if
(
Exportflag
[
j
])
{
SynchroinzeNgbTimestepDataIn
[
nexport
].
Pos
[
0
]
=
P
[
i
].
Pos
[
0
];
SynchroinzeNgbTimestepDataIn
[
nexport
].
Pos
[
1
]
=
P
[
i
].
Pos
[
1
];
SynchroinzeNgbTimestepDataIn
[
nexport
].
Pos
[
2
]
=
P
[
i
].
Pos
[
2
];
SynchroinzeNgbTimestepDataIn
[
nexport
].
Hsml
=
SphP
[
i
].
Hsml
;
SynchroinzeNgbTimestepDataIn
[
nexport
].
Ti_step
=
P
[
i
].
Ti_step
;
SynchroinzeNgbTimestepDataIn
[
nexport
].
Ti_endstep
=
P
[
i
].
Ti_endstep
;
SynchroinzeNgbTimestepDataIn
[
nexport
].
Index
=
i
;
SynchroinzeNgbTimestepDataIn
[
nexport
].
Task
=
j
;
#ifdef MULTIPHASE
SynchroinzeNgbTimestepDataIn
[
nexport
].
Phase
=
SphP
[
i
].
Phase
;
#endif
nexport
++
;
nsend_local
[
j
]
++
;
}
}
}
}
t1
=
second
();
timecomp
+=
timediff
(
t0
,
t1
);
qsort
(
SynchroinzeNgbTimestepDataIn
,
nexport
,
sizeof
(
struct
SynchroinzeNgbTimestepdata_in
),
synchronize_ngb_timestep_compare_key
);
for
(
j
=
1
,
noffset
[
0
]
=
0
;
j
<
NTask
;
j
++
)
noffset
[
j
]
=
noffset
[
j
-
1
]
+
nsend_local
[
j
-
1
];
t0
=
second
();
MPI_Allgather
(
nsend_local
,
NTask
,
MPI_INT
,
nsend
,
NTask
,
MPI_INT
,
MPI_COMM_WORLD
);
t1
=
second
();
timeimbalance
+=
timediff
(
t0
,
t1
);
/* now do the particles that need to be exported */
for
(
level
=
1
;
level
<
(
1
<<
PTask
);
level
++
)
{
t0
=
second
();
for
(
j
=
0
;
j
<
NTask
;
j
++
)
nbuffer
[
j
]
=
0
;
for
(
ngrp
=
level
;
ngrp
<
(
1
<<
PTask
);
ngrp
++
)
{
maxfill
=
0
;
for
(
j
=
0
;
j
<
NTask
;
j
++
)
{
if
((
j
^
ngrp
)
<
NTask
)
if
(
maxfill
<
nbuffer
[
j
]
+
nsend
[(
j
^
ngrp
)
*
NTask
+
j
])
maxfill
=
nbuffer
[
j
]
+
nsend
[(
j
^
ngrp
)
*
NTask
+
j
];
}
if
(
maxfill
>=
All
.
BunchSizeSynchronizeNgBTimestep
)
break
;
sendTask
=
ThisTask
;
recvTask
=
ThisTask
^
ngrp
;
if
(
recvTask
<
NTask
)
{
if
(
nsend
[
ThisTask
*
NTask
+
recvTask
]
>
0
||
nsend
[
recvTask
*
NTask
+
ThisTask
]
>
0
)
{
/* get the particles */
MPI_Sendrecv
(
&
SynchroinzeNgbTimestepDataIn
[
noffset
[
recvTask
]],
nsend_local
[
recvTask
]
*
sizeof
(
struct
SynchroinzeNgbTimestepdata_in
),
MPI_BYTE
,
recvTask
,
0
,
&
SynchroinzeNgbTimestepDataGet
[
nbuffer
[
ThisTask
]],
nsend
[
recvTask
*
NTask
+
ThisTask
]
*
sizeof
(
struct
SynchroinzeNgbTimestepdata_in
),
MPI_BYTE
,
recvTask
,
0
,
MPI_COMM_WORLD
,
&
status
);
}
}
for
(
j
=
0
;
j
<
NTask
;
j
++
)
if
((
j
^
ngrp
)
<
NTask
)
nbuffer
[
j
]
+=
nsend
[(
j
^
ngrp
)
*
NTask
+
j
];
}
t1
=
second
();
timecommsumm
+=
timediff
(
t0
,
t1
);
t0
=
second
();
for
(
j
=
0
;
j
<
nbuffer
[
ThisTask
];
j
++
)
NDone
+=
synchronize_ngb_timestep_evaluate
(
j
,
1
);
t1
=
second
();
timecomp
+=
timediff
(
t0
,
t1
);
/* do a block to explicitly measure imbalance */
t0
=
second
();
MPI_Barrier
(
MPI_COMM_WORLD
);
t1
=
second
();
timeimbalance
+=
timediff
(
t0
,
t1
);
level
=
ngrp
-
1
;
}
t0
=
second
();
MPI_Allgather
(
&
ndone
,
1
,
MPI_INT
,
ndonelist
,
1
,
MPI_INT
,
MPI_COMM_WORLD
);
for
(
j
=
0
;
j
<
NTask
;
j
++
)
ntotleft
-=
ndonelist
[
j
];
t1
=
second
();
timeimbalance
+=
timediff
(
t0
,
t1
);
}
t0
=
second
();
numlist
=
(
int
*
)
malloc
(
NTask
*
sizeof
(
int
)
*
NTask
);
MPI_Allgather
(
&
NDone
,
1
,
MPI_INT
,
numlist
,
1
,
MPI_INT
,
MPI_COMM_WORLD
);
for
(
i
=
0
,
NTotDone
=
0
;
i
<
NTask
;
i
++
)
NTotDone
+=
numlist
[
i
];
free
(
numlist
);
t1
=
second
();
timeimbalance
+=
timediff
(
t0
,
t1
);
if
(
ThisTask
==
0
)
{
fprintf
(
stdout
,
" %3d) ---> number of timestep shrinked gas neighbors: %6lld
\n
"
,
CptLimit
++
,
NTotDone
);
fflush
(
stdout
);
}
}
free
(
ndonelist
);
free
(
nsend
);
free
(
nsend_local
);
free
(
nbuffer
);
free
(
noffset
);
/* do final operations on results */
counter
=
0
;
for
(
i
=
0
;
i
<
N_gas
;
i
++
)
#ifdef SFR
if
((
P
[
i
].
Type
==
0
))
#endif
{
if
(
P
[
i
].
Old_Ti_endstep
!=
All
.
Ti_Current
)
/* the particle is inactive */
{
if
(
(
P
[
i
].
Old_Ti_endstep
!=
P
[
i
].
Ti_endstep
)
||
(
P
[
i
].
Old_Ti_begstep
!=
P
[
i
].
Ti_begstep
)
)
/* its timestep has been updated */
{
//printf("---------> %d %d %d %d\n",P[i].Old_Ti_endstep,P[i].Ti_endstep,P[i].Old_Ti_begstep,P[i].Ti_begstep);
/* need to extrapolate mid-step quantities */
counter
++
;
/* old mid step */
tstart
=
(
P
[
i
].
Old_Ti_begstep
+
P
[
i
].
Old_Ti_endstep
)
/
2
;
/* midpoint of old step */
tend
=
(
P
[
i
].
Ti_begstep
+
P
[
i
].
Ti_endstep
)
/
2
;
/* midpoint of new step */
/* now, do the kick */
kickback
(
i
,
tstart
,
tend
);
}
}
}
if
(
counter
!=
0
)
printf
(
"(%d) %d passive particles have been updated
\n
"
,
ThisTask
,
counter
);
if
(
ThisTask
==
0
)
printf
(
"synchronize ngb timestep done.
\n
"
);
}
int
synchronize_ngb_timestep_evaluate
(
int
target
,
int
mode
)
{
int
j
,
k
,
n
,
startnode
,
numngb_inbox
;
double
h
,
h2
;
double
r2
,
dx
,
dy
,
dz
;
int
phase
=
0
;
FLOAT
*
pos
;
int
ti_step_i
;
int
endstep_i
;
int
CptShrink
=
0
;
if
(
mode
==
0
)
{
pos
=
P
[
target
].
Pos
;
h
=
SphP
[
target
].
Hsml
;
ti_step_i
=
P
[
target
].
Ti_step
;
endstep_i
=
P
[
target
].
Ti_endstep
;
/* !!! */
#ifdef MULTIPHASE
phase
=
SphP
[
target
].
Phase
;
#endif
}
else
{
pos
=
SynchroinzeNgbTimestepDataGet
[
target
].
Pos
;
h
=
SynchroinzeNgbTimestepDataGet
[
target
].
Hsml
;
ti_step_i
=
SynchroinzeNgbTimestepDataGet
[
target
].
Ti_step
;
endstep_i
=
SynchroinzeNgbTimestepDataGet
[
target
].
Ti_endstep
;
/* !!! */
#ifdef MULTIPHASE
phase
=
SynchroinzeNgbTimestepDataGet
[
target
].
Phase
;
#endif
}
h2
=
h
*
h
;
startnode
=
All
.
MaxPart
;
do
{
numngb_inbox
=
ngb_treefind_variable
(
&
pos
[
0
],
h
,
phase
,
&
startnode
);
for
(
n
=
0
;
n
<
numngb_inbox
;
n
++
)
{
j
=
Ngblist
[
n
];
dx
=
P
[
j
].
Pos
[
0
]
-
pos
[
0
];
dy
=
P
[
j
].
Pos
[
1
]
-
pos
[
1
];
dz
=
P
[
j
].
Pos
[
2
]
-
pos
[
2
];
#ifdef PERIODIC
/* now find the closest image in the given box size */
if
(
dx
>
boxHalf_X
)
dx
-=
boxSize_X
;
if
(
dx
<
-
boxHalf_X
)
dx
+=
boxSize_X
;
if
(
dy
>
boxHalf_Y
)
dy
-=
boxSize_Y
;
if
(
dy
<
-
boxHalf_Y
)
dy
+=
boxSize_Y
;
if
(
dz
>
boxHalf_Z
)
dz
-=
boxSize_Z
;
if
(
dz
<
-
boxHalf_Z
)
dz
+=
boxSize_Z
;
#endif
r2
=
dx
*
dx
+
dy
*
dy
+
dz
*
dz
;
if
(
r2
<
h2
)
{
if
(
P
[
j
].
Ti_endstep
==
All
.
Ti_Current
)
/* the particle is active */
{
if
(
P
[
j
].
Ti_step
>
All
.
NgbFactorTimestep
*
ti_step_i
)
{
CptShrink
++
;
P
[
j
].
Ti_step
=
All
.
NgbFactorTimestep
*
ti_step_i
;
}
}
else
/* the particle is not active */
{
if
(
P
[
j
].
Ti_endstep
>
All
.
Ti_Current
+
All
.
NgbFactorTimestep
*
ti_step_i
)
{
CptShrink
++
;
P
[
j
].
Old_Ti_begstep
=
P
[
j
].
Ti_begstep
;
P
[
j
].
Old_Ti_endstep
=
P
[
j
].
Ti_endstep
;
P
[
j
].
Ti_step
=
All
.
NgbFactorTimestep
*
ti_step_i
;
#ifdef SYNCHRONIZATION
/* find Ti_endstep*/
for
(
k
=
0
;
P
[
j
].
Ti_begstep
+
k
*
P
[
j
].
Ti_step
<=
All
.
Ti_Current
;
k
++
);
P
[
j
].
Ti_endstep
=
P
[
j
].
Ti_begstep
+
k
*
P
[
j
].
Ti_step
;
P
[
j
].
Ti_begstep
=
P
[
j
].
Ti_endstep
-
P
[
j
].
Ti_step
;
#else
P
[
j
].
Ti_endstep
=
All
.
Ti_Current
+
P
[
j
].
Ti_step
;
P
[
j
].
Ti_begstep
=
P
[
j
].
Ti_endstep
-
P
[
j
].
Ti_step
;
#endif
}
}
}
}
}
while
(
startnode
>=
0
);
return
CptShrink
;
}
/*! This is a comparison kernel for a sort routine, which is used to group
* particles that are going to be exported to the same CPU.
*/
int
synchronize_ngb_timestep_compare_key
(
const
void
*
a
,
const
void
*
b
)
{
if
(((
struct
SynchroinzeNgbTimestepdata_in
*
)
a
)
->
Task
<
(((
struct
SynchroinzeNgbTimestepdata_in
*
)
b
)
->
Task
))
return
-
1
;
if
(((
struct
SynchroinzeNgbTimestepdata_in
*
)
a
)
->
Task
>
(((
struct
SynchroinzeNgbTimestepdata_in
*
)
b
)
->
Task
))
return
+
1
;
return
0
;
}
#endif
Event Timeline
Log In to Comment