Page MenuHomec4science

No OneTemporary

File Metadata

Created
Thu, Nov 28, 10:21
This file is larger than 256 KB, so syntax highlighting was skipped.
This document is not UTF8. It was detected as ISO-8859-1 (Latin 1) and converted to UTF8 for display.
diff --git a/src/allocate.c b/src/allocate.c
index f3c0fd9..b3d31e4 100644
--- a/src/allocate.c
+++ b/src/allocate.c
@@ -1,291 +1,308 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "allvars.h"
#include "proto.h"
/*! \file allocate.c
* \brief routines for allocating particle and tree storage
*/
/*! Allocates a number of small buffers and arrays, the largest one being
* the communication buffer. The communication buffer itself is mapped
* onto various tables used in the different parts of the force
* algorithms. We further allocate space for the top-level tree nodes, and
* auxiliary arrays for the domain decomposition algorithm.
*/
void allocate_commbuffers(void)
{
size_t bytes;
Exportflag = malloc(NTask * sizeof(char));
DomainStartList = malloc(NTask * sizeof(int));
DomainEndList = malloc(NTask * sizeof(int));
TopNodes = malloc(MAXTOPNODES * sizeof(struct topnode_data));
DomainWork = malloc(MAXTOPNODES * sizeof(double));
DomainCount = malloc(MAXTOPNODES * sizeof(int));
DomainCountSph = malloc(MAXTOPNODES * sizeof(int));
DomainTask = malloc(MAXTOPNODES * sizeof(int));
DomainNodeIndex = malloc(MAXTOPNODES * sizeof(int));
DomainTreeNodeLen = malloc(MAXTOPNODES * sizeof(FLOAT));
DomainHmax = malloc(MAXTOPNODES * sizeof(FLOAT));
DomainMoment = malloc(MAXTOPNODES * sizeof(struct DomainNODE));
if(!(CommBuffer = malloc(bytes = All.BufferSize * 1024 * 1024)))
{
printf("failed to allocate memory for `CommBuffer' (%g MB).\n", bytes / (1024.0 * 1024.0));
endrun(2);
}
All.BunchSizeForce =
(All.BufferSize * 1024 * 1024) / (sizeof(struct gravdata_index) + 2 * sizeof(struct gravdata_in));
if(All.BunchSizeForce & 1)
All.BunchSizeForce -= 1; /* make sure that All.BunchSizeForce is an even number
--> 8-byte alignment for 64bit processors */
GravDataIndexTable = (struct gravdata_index *) CommBuffer;
GravDataIn = (struct gravdata_in *) (GravDataIndexTable + All.BunchSizeForce);
GravDataGet = GravDataIn + All.BunchSizeForce;
GravDataOut = GravDataIn; /* this will overwrite the GravDataIn-Table */
GravDataResult = GravDataGet; /* this will overwrite the GravDataGet-Table */
All.BunchSizeDensity =
(All.BufferSize * 1024 * 1024) / (2 * sizeof(struct densdata_in) + 2 * sizeof(struct densdata_out));
DensDataIn = (struct densdata_in *) CommBuffer;
DensDataGet = DensDataIn + All.BunchSizeDensity;
DensDataResult = (struct densdata_out *) (DensDataGet + All.BunchSizeDensity);
DensDataPartialResult = DensDataResult + All.BunchSizeDensity;
All.BunchSizeHydro =
(All.BufferSize * 1024 * 1024) / (2 * sizeof(struct hydrodata_in) + 2 * sizeof(struct hydrodata_out));
HydroDataIn = (struct hydrodata_in *) CommBuffer;
HydroDataGet = HydroDataIn + All.BunchSizeHydro;
HydroDataResult = (struct hydrodata_out *) (HydroDataGet + All.BunchSizeHydro);
HydroDataPartialResult = HydroDataResult + All.BunchSizeHydro;
#ifdef PY_INTERFACE
All.BunchSizeSph =
(All.BufferSize * 1024 * 1024) / (2 * sizeof(struct sphdata_in) + 2 * sizeof(struct sphdata_out));
SphDataIn = (struct sphdata_in *) CommBuffer;
SphDataGet = SphDataIn + All.BunchSizeSph;
SphDataResult = (struct sphdata_out *) (SphDataGet + All.BunchSizeSph);
SphDataPartialResult = SphDataResult + All.BunchSizeSph;
All.BunchSizeDensitySph =
(All.BufferSize * 1024 * 1024) / (2 * sizeof(struct denssphdata_in) + 2 * sizeof(struct denssphdata_out));
DensSphDataIn = (struct denssphdata_in *) CommBuffer;
DensSphDataGet = DensSphDataIn + All.BunchSizeDensitySph;
DensSphDataResult = (struct denssphdata_out *) (DensSphDataGet + All.BunchSizeDensitySph);
DensSphDataPartialResult = DensSphDataResult + All.BunchSizeDensitySph;
#endif
#ifdef MULTIPHASE
All.BunchSizeSticky =
(All.BufferSize * 1024 * 1024) / (2 * sizeof(struct stickydata_in) + 2 * sizeof(struct stickydata_out));
StickyDataIn = (struct stickydata_in *) CommBuffer;
StickyDataGet = StickyDataIn + All.BunchSizeSticky;
StickyDataResult = (struct stickydata_out *) (StickyDataGet + All.BunchSizeSticky);
StickyDataPartialResult = StickyDataResult + All.BunchSizeSticky;
#endif
#ifdef CHIMIE
All.BunchSizeChimie =
(All.BufferSize * 1024 * 1024) / (2 * sizeof(struct chimiedata_in) + 2 * sizeof(struct chimiedata_out));
ChimieDataIn = (struct chimiedata_in *) CommBuffer;
ChimieDataGet = ChimieDataIn + All.BunchSizeChimie;
ChimieDataResult = (struct chimiedata_out *) (ChimieDataGet + All.BunchSizeChimie);
ChimieDataPartialResult = ChimieDataResult + All.BunchSizeChimie;
All.BunchSizeStarsDensity =
(All.BufferSize * 1024 * 1024) / (2 * sizeof(struct starsdensdata_in) + 2 * sizeof(struct starsdensdata_out));
StarsDensDataIn = (struct starsdensdata_in *) CommBuffer;
StarsDensDataGet = StarsDensDataIn + All.BunchSizeStarsDensity;
StarsDensDataResult = (struct starsdensdata_out *) (StarsDensDataGet + All.BunchSizeStarsDensity);
StarsDensDataPartialResult = StarsDensDataResult + All.BunchSizeStarsDensity;
#endif
#ifdef DISSIPATION_FORCES
All.BunchSizeDissipationForces =
(All.BufferSize * 1024 * 1024) / (2 * sizeof(struct dissipationforcesdata_in) + 2 * sizeof(struct dissipationforcesdata_out));
DissipationForcesDataIn = (struct dissipationforcesdata_in *) CommBuffer;
DissipationForcesDataGet = DissipationForcesDataIn + All.BunchSizeDissipationForces;
DissipationForcesDataResult = (struct dissipationforcesdata_out *) (DissipationForcesDataGet + All.BunchSizeDissipationForces);
DissipationForcesDataPartialResult = DissipationForcesDataResult + All.BunchSizeDissipationForces;
#endif
#ifdef FOF
All.BunchSizeFOF =
(All.BufferSize * 1024 * 1024) / (2 * sizeof(struct FOFdata_in) + 2 * sizeof(struct FOFdata_out));
FOFDataIn = (struct FOFdata_in *) CommBuffer;
FOFDataGet = FOFDataIn + All.BunchSizeFOF;
FOFDataResult = (struct FOFdata_out *) (FOFDataGet + All.BunchSizeFOF);
FOFDataPartialResult = FOFDataResult + All.BunchSizeFOF;
+
+
+ All.BunchSizeForceFOF =
+ (All.BufferSize * 1024 * 1024) / (sizeof(struct FOFgravdata_index) + 2 * sizeof(struct FOFgravdata_in));
+
+
+ if(All.BunchSizeForceFOF & 1)
+ All.BunchSizeForceFOF -= 1; /* make sure that All.BunchSizeForce is an even number
+ --> 8-byte alignment for 64bit processors */
+
+ FOFGravDataIndexTable = (struct FOFgravdata_index *) CommBuffer;
+ FOFGravDataIn = (struct FOFgravdata_in *) (FOFGravDataIndexTable + All.BunchSizeForceFOF);
+ FOFGravDataGet = FOFGravDataIn + All.BunchSizeForceFOF;
+ FOFGravDataOut = FOFGravDataIn; /* this will overwrite the FOFGravDataIn-Table */
+ FOFGravDataResult = FOFGravDataGet; /* this will overwrite the FOFGravDataGet-Table */
+
+
#endif
#ifdef STELLAR_PROP
All.BunchSizeDomain =
(All.BufferSize * 1024 * 1024) / (sizeof(struct particle_data) + sizeof(struct sph_particle_data) +
sizeof(struct st_particle_data) + sizeof(peanokey));
#else
All.BunchSizeDomain =
(All.BufferSize * 1024 * 1024) / (sizeof(struct particle_data) + sizeof(struct sph_particle_data) +
sizeof(peanokey));
#endif
if(All.BunchSizeDomain & 1)
All.BunchSizeDomain -= 1; /* make sure that All.BunchSizeDomain is even
--> 8-byte alignment of DomainKeyBuf for 64bit processors */
DomainPartBuf = (struct particle_data *) CommBuffer;
DomainSphBuf = (struct sph_particle_data *) (DomainPartBuf + All.BunchSizeDomain);
DomainKeyBuf = (peanokey *) (DomainSphBuf + All.BunchSizeDomain);
#ifdef STELLAR_PROP
DomainStBuf = (struct st_particle_data *) (DomainKeyBuf + All.BunchSizeDomain);
#endif
#ifdef SYNCHRONIZE_NGB_TIMESTEP
All.BunchSizeSynchronizeNgBTimestep =
(All.BufferSize * 1024 * 1024) / (2 * sizeof(struct SynchroinzeNgbTimestepdata_in));
SynchroinzeNgbTimestepDataIn = (struct SynchroinzeNgbTimestepdata_in *) CommBuffer;
SynchroinzeNgbTimestepDataGet = SynchroinzeNgbTimestepDataIn + All.BunchSizeSynchronizeNgBTimestep;
#endif
#ifdef TESSEL
All.BunchSizeGhost =
(All.BufferSize * 1024 * 1024) / (2 * sizeof(struct ghostdata_in) + 2 * sizeof(struct ghostdata_out));
#endif
if(ThisTask == 0)
{
printf("\nAllocated %d MByte communication buffer per processor.\n\n", All.BufferSize);
printf("Communication buffer has room for %d particles in gravity computation\n", All.BunchSizeForce);
printf("Communication buffer has room for %d particles in density computation\n", All.BunchSizeDensity);
printf("Communication buffer has room for %d particles in hydro computation\n", All.BunchSizeHydro);
printf("Communication buffer has room for %d particles in domain decomposition\n", All.BunchSizeDomain);
printf("\n");
}
}
/*! This routine allocates memory for particle storage, both the
* collisionless and the SPH particles.
*/
void allocate_memory(void)
{
size_t bytes;
double bytes_tot = 0;
if(All.MaxPart > 0)
{
if(!(P = malloc(bytes = All.MaxPart * sizeof(struct particle_data))))
{
printf("failed to allocate memory for `P' (%g MB).\n", bytes / (1024.0 * 1024.0));
endrun(1);
}
bytes_tot += bytes;
if(ThisTask == 0)
printf("\nAllocated %g MByte for particle storage. %d\n\n", bytes_tot / (1024.0 * 1024.0), sizeof(struct particle_data));
}
if(All.MaxPartSph > 0)
{
bytes_tot = 0;
if(!(SphP = malloc(bytes = All.MaxPartSph * sizeof(struct sph_particle_data))))
{
printf("failed to allocate memory for `SphP' (%g MB) %d.\n", bytes / (1024.0 * 1024.0), sizeof(struct sph_particle_data));
endrun(1);
}
bytes_tot += bytes;
if(ThisTask == 0)
printf("Allocated %g MByte for storage of SPH data. %d\n", bytes_tot / (1024.0 * 1024.0), sizeof(struct sph_particle_data));
}
#ifdef STELLAR_PROP
if(All.MaxPartStars > 0)
{
bytes_tot = 0;
if(!(StP = malloc(bytes = All.MaxPartStars * sizeof(struct st_particle_data))))
{
printf("failed to allocate memory for `StP' (%g MB) %d.\n", bytes / (1024.0 * 1024.0),sizeof(struct st_particle_data));
endrun(1);
}
bytes_tot += bytes;
if(ThisTask == 0)
printf("\nAllocated %g MByte for star properties storage. %d\n\n", bytes_tot / (1024.0 * 1024.0), sizeof(struct st_particle_data));
}
#endif
}
/*! This routine frees the memory for the particle storage. Note: We don't
* actually bother to call it in the code... When the program terminats,
* the memory will be automatically freed by the operating system.
*/
void free_memory(void)
{
#ifdef GAS_ACCRETION
if(N_gas_acc > 0)
free(SphAcc);
if(NumPart_acc > 0)
free(Acc);
#endif
#ifdef HOT_HALO
if(NumPart_HaloAcc > 0)
free(HaloAcc);
#endif
#ifdef STELLAR_PROP
if(All.MaxPartStars > 0)
free(StP);
#endif
if(All.MaxPartSph > 0)
free(SphP);
if(All.MaxPart > 0)
free(P);
#ifdef COOLING_FCT_FROM_HDF5
freeMemory();
#endif
}
diff --git a/src/allvars.c b/src/allvars.c
index e4308dc..367ed3e 100644
--- a/src/allvars.c
+++ b/src/allvars.c
@@ -1,563 +1,578 @@
/*! \file allvars.c
* \brief provides instances of all global variables.
*/
#include <stdio.h>
#include <gsl/gsl_rng.h>
#include "tags.h"
#include "allvars.h"
#ifdef CHIMIE
int FE=0;
int METALS=0;
#endif
int SetMinTimeStepForActives=0;
int ThisTask; /*!< the rank of the local processor */
int NTask; /*!< number of processors */
int PTask; /*!< smallest integer such that NTask <= 2^PTask */
int NumPart; /*!< number of particles on the LOCAL processor */
int N_gas; /*!< number of gas particles on the LOCAL processor */
#if defined(SFR) || defined(STELLAR_PROP)
int N_stars; /*!< number of stars particle on the LOCAL processor */
#endif
#ifdef MULTIPHASE
int N_sph;
int N_sticky;
int N_stickyflaged;
int N_dark;
int NumColPotLocal; /*!< local number of potentially collisional particles */
int NumColPot; /*!< total number of potentially collisional particles */
int NumColLocal; /*!< local number of collisions */
int NumCol; /*!< total number of collisions */
int NumNoColLocal;
int NumNoCol;
#endif
#ifdef GAS_ACCRETION
int NumPart_acc;
int N_gas_acc;
#ifdef STELLAR_PROP
int N_stars_acc;
#endif
#endif
#ifdef HOT_HALO
int NumPart_HaloAcc;
#endif
long long Ntype[6]; /*!< total number of particles of each type */
int NtypeLocal[6]; /*!< local number of particles of each type */
int NumForceUpdate; /*!< number of active particles on local processor in current timestep */
int NumSphUpdate; /*!< number of active SPH particles on local processor in current timestep */
#ifdef CHIMIE
int NumStUpdate;
#endif
#ifdef TESSEL
int NumPTUpdate;
#endif
double CPUThisRun; /*!< Sums the CPU time for the process (current submission only) */
#ifdef SPLIT_DOMAIN_USING_TIME
double CPU_Gravity;
#endif
int RestartFlag; /*!< taken from command line used to start code. 0 is normal start-up from
initial conditions, 1 is resuming a run from a set of restart files, while 2
marks a restart from a snapshot file. */
char *Exportflag; /*!< Buffer used for flagging whether a particle needs to be exported to another process */
int *Ngblist; /*!< Buffer to hold indices of neighbours retrieved by the neighbour search routines */
int TreeReconstructFlag; /*!< Signals that a new tree needs to be constructed */
#ifdef SFR
int RearrangeParticlesFlag;/*!< Signals that particles must be rearanged */
#endif
int Flag_FullStep; /*!< This flag signals that the current step involves all particles */
gsl_rng *random_generator; /*!< the employed random number generator of the GSL library */
double RndTable[RNDTABLE]; /*!< Hold a table with random numbers, refreshed every timestep */
#ifdef SFR
double StarFormationRndTable[RNDTABLE]; /*!< Hold a table with random numbers, refreshed every timestep */
#endif
#ifdef FEEDBACK_WIND
double FeedbackWindRndTable[RNDTABLE]; /*!< Hold a table with random numbers, refreshed every timestep */
#endif
#ifdef CHIMIE
double ChimieRndTable[RNDTABLE]; /*!< Hold a table with random numbers, refreshed every timestep */
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
double ChimieKineticFeedbackRndTable[RNDTABLE]; /*!< Hold a table with random numbers, refreshed every timestep */
#endif
#ifdef GAS_ACCRETION
double gasAccretionRndTable[RNDTABLE]; /*!< Hold a table with random numbers, refreshed every timestep */
#endif
#ifdef HOT_HALO
double HaloRndTable[RNDTABLE]; /*!< Hold a table with random numbers, refreshed every timestep */
#endif
#ifdef AB_TURB
//Ornstein-Uhlenbeck variables
double StOUVar;
double* StOUPhases;
gsl_rng* StRng;
//forcing field in fourie space
double* StAmpl;
double* StAka; //phases (real part)
double* StAkb; //phases (imag part)
double* StMode;
int StNModes;
//integertime StTPrev; (yr : ask ?)
int StTPrev;
double StSolWeightNorm;
#endif
#ifdef PY_INTERFACE
int NumPartQ;
int N_gasQ;
long long NtypeQ[6]; /*!< total number of particles of each type */
int NtypeLocalQ[6]; /*!< local number of particles of each type */
double DomainCornerQ[3]; /*!< gives the lower left corner of simulation volume */
double DomainCenterQ[3]; /*!< gives the center of simulation volume */
double DomainLenQ; /*!< gives the (maximum) side-length of simulation volume */
double DomainFacQ; /*!< factor used for converting particle coordinates to a Peano-Hilbert mesh covering the simulation volume */
int DomainMyStartQ; /*!< first domain mesh cell that resides on the local processor */
int DomainMyLastQ; /*!< last domain mesh cell that resides on the local processor */
int *DomainStartListQ; /*!< a table that lists the first domain mesh cell for all processors */
int *DomainEndListQ; /*!< a table that lists the last domain mesh cell for all processors */
double *DomainWorkQ; /*!< a table that gives the total "work" due to the particles stored by each processor */
int *DomainCountQ; /*!< a table that gives the total number of particles held by each processor */
int *DomainCountSphQ; /*!< a table that gives the total number of SPH particles held by each processor */
int *DomainTaskQ; /*!< this table gives for each leaf of the top-level tree the processor it was assigned to */
peanokey *DomainKeyBufQ; /*!< this points to a buffer used during the exchange of particle data */
int NTopnodesQ; /*!< total number of nodes in top-level tree */
int NTopleavesQ; /*!< number of leaves in top-level tree. Each leaf can be assigned to a different processor */
void *CommBufferQ; /*!< points to communication buffer, which is used in the domain decomposition, the
parallel tree-force computation, the SPH routines, etc. */
int NTopnodesQ; /*!< total number of nodes in top-level tree */
int NTopleavesQ; /*!< number of leaves in top-level tree. Each leaf can be assigned to a different processor */
#endif
double DomainCorner[3]; /*!< gives the lower left corner of simulation volume */
double DomainCenter[3]; /*!< gives the center of simulation volume */
double DomainLen; /*!< gives the (maximum) side-length of simulation volume */
double DomainFac; /*!< factor used for converting particle coordinates to a Peano-Hilbert mesh covering the simulation volume */
int DomainMyStart; /*!< first domain mesh cell that resides on the local processor */
int DomainMyLast; /*!< last domain mesh cell that resides on the local processor */
int *DomainStartList; /*!< a table that lists the first domain mesh cell for all processors */
int *DomainEndList; /*!< a table that lists the last domain mesh cell for all processors */
double *DomainWork; /*!< a table that gives the total "work" due to the particles stored by each processor */
int *DomainCount; /*!< a table that gives the total number of particles held by each processor */
int *DomainCountSph; /*!< a table that gives the total number of SPH particles held by each processor */
int *DomainTask; /*!< this table gives for each leaf of the top-level tree the processor it was assigned to */
int *DomainNodeIndex; /*!< this table gives for each leaf of the top-level tree the corresponding node of the gravitational tree */
FLOAT *DomainTreeNodeLen; /*!< this table gives for each leaf of the top-level tree the side-length of the corresponding node of the gravitational tree */
FLOAT *DomainHmax; /*!< this table gives for each leaf of the top-level tree the maximum SPH smoothing length among the particles of the corresponding node of the gravitational tree */
struct DomainNODE
*DomainMoment; /*!< this table stores for each node of the top-level tree corresponding node data from the gravitational tree */
peanokey *DomainKeyBuf; /*!< this points to a buffer used during the exchange of particle data */
peanokey *Key; /*!< a table used for storing Peano-Hilbert keys for particles */
peanokey *KeySorted; /*!< holds a sorted table of Peano-Hilbert keys for all particles, used to construct top-level tree */
int NTopnodes; /*!< total number of nodes in top-level tree */
int NTopleaves; /*!< number of leaves in top-level tree. Each leaf can be assigned to a different processor */
struct topnode_data
*TopNodes; /*!< points to the root node of the top-level tree */
#ifdef PY_INTERFACE
struct topnode_data
*TopNodesQ; /*!< points to the root node of the top-level tree */
#endif
double TimeOfLastTreeConstruction; /*!< holds what it says, only used in connection with FORCETEST */
/* variables for input/output, usually only used on process 0 */
char ParameterFile[MAXLEN_FILENAME]; /*!< file name of parameterfile used for starting the simulation */
FILE *FdInfo; /*!< file handle for info.txt log-file. */
FILE *FdLog ; /*!< file handle for log.txt log-file. */
FILE *FdEnergy; /*!< file handle for energy.txt log-file. */
#ifdef SYSTEMSTATISTICS
FILE *FdSystem;
#endif
FILE *FdTimings; /*!< file handle for timings.txt log-file. */
FILE *FdCPU; /*!< file handle for cpu.txt log-file. */
#ifdef FORCETEST
FILE *FdForceTest; /*!< file handle for forcetest.txt log-file. */
#endif
#ifdef SFR
FILE *FdSfr; /*!< file handle for sfr.txt log-file. */
#endif
#ifdef CHIMIE
FILE *FdChimie; /*!< file handle for chimie log-file. */
#ifdef CHIMIE_STATS
FILE *FdChimieStatsSNs; /*!< file handle for chimie stats-file. */
FILE *FdChimieStatsGas; /*!< file handle for chimie stats-file. */
#endif
+#ifdef FOF
+FILE *FdFOF_Chimie; /*!< file handle for fof chimie log-file. */
+#endif
#endif
#ifdef MULTIPHASE
FILE *FdPhase; /*!< file handle for phase.txt log-file. */
FILE *FdSticky; /*!< file handle for sticky.txt log-file. */
#endif
#ifdef AGN_ACCRETION
FILE *FdAccretion; /*!< file handle for accretion.txt log-file. */
#endif
#ifdef BONDI_ACCRETION
FILE *FdBondi; /*!< file handle for bondi.txt log-file. */
#endif
#ifdef BUBBLES
FILE *FdBubble; /*!< file handle for bubble.txt log-file. */
#endif
#ifdef GAS_ACCRETION
FILE *FdGasAccretion; /*!< file handle for gas_accretion.txt log-file. */
#endif
#ifdef PERIODICOUTER
FILE *FdTrace; /*!< file handle for trace.txt log-file. */
#endif
double DriftTable[DRIFT_TABLE_LENGTH]; /*!< table for the cosmological drift factors */
double GravKickTable[DRIFT_TABLE_LENGTH]; /*!< table for the cosmological kick factor for gravitational forces */
double HydroKickTable[DRIFT_TABLE_LENGTH]; /*!< table for the cosmological kick factor for hydrodynmical forces */
#ifdef COSMICTIME
double CosmicTimeTable[COSMICTIME_TABLE_LENGTH]; /*!< table for the computation of cosmic time */
double FullCosmicTimeTable[COSMICTIME_TABLE_LENGTH]; /*!< table for the computation of cosmic time */
double FullCosmicTimeTableInv[COSMICTIME_TABLE_LENGTH]; /*!< table for the computation of cosmic time */
#endif
void *CommBuffer; /*!< points to communication buffer, which is used in the domain decomposition, the
parallel tree-force computation, the SPH routines, etc. */
/*! This structure contains data which is the SAME for all tasks (mostly code parameters read from the
* parameter file). Holding this data in a structure is convenient for writing/reading the restart file, and
* it allows the introduction of new global variables in a simple way. The only thing to do is to introduce
* them into this structure.
*/
struct global_data_all_processes
All;
/*! This structure holds all the information that is
* stored for each particle of the simulation.
*/
struct particle_data
*P, /*!< holds particle data on local processor */
*DomainPartBuf; /*!< buffer for particle data used in domain decomposition */
#ifdef PY_INTERFACE
struct particle_data
*Q, /*!< holds particle data on local processor */
*DomainPartBufQ; /*!< buffer for particle data used in domain decomposition */
#endif
/* the following struture holds data that is stored for each SPH particle in addition to the collisionless
* variables.
*/
struct sph_particle_data
*SphP, /*!< holds SPH particle data on local processor */
*DomainSphBuf; /*!< buffer for SPH particle data in domain decomposition */
#ifdef FOF
struct fof_particles_in
*FoF_P,*FoF_P_local;
struct fof_groups_data
*Groups,*GroupsGet,*GroupsRecv;
int *Tot_HeadID_list;
int Tot_Ngroups;
int Tot_Ntgroups;
int Tot_Npgroups;
int Tot_Ntsfrgroups;
int Ngroups; /* true and pseudo groups */
int Ntgroups; /* true groups */
int Npgroups; /* pseudo groups */
int Ntsfrgroups; /* true groups that forms stars */
int Nsfrgroups; /* local number of groups flagged for sfr */
int Tot_Nsfrgroups; /* total number of groups flagged for sfr */
#endif
#ifdef GAS_ACCRETION
struct acc_particle_data
*Acc;
struct gas_acc_particle_data
*SphAcc;
#endif
#ifdef HOT_HALO
struct haloacc_pos_data
*HaloAcc;
#endif
#ifdef TRACE_ACC
struct pot_index
*PotInd;
#endif
#ifdef TRACE_ACC
struct pot_index
*PotInd;
#endif
#ifdef PY_INTERFACE
struct sph_particle_data
*SphQ, /*!< holds SPH particle data on local processor */
*DomainSphBufQ; /*!< buffer for SPH particle data in domain decomposition */
#endif
#ifdef STELLAR_PROP
/* the following struture holds data that is stored for each SPH particle in addition to the collisionless
* variables.
*/
struct st_particle_data
*StP, /*!< holds ST particle data on local processor */
*DomainStBuf; /*!< buffer for ST particle data in domain decomposition */
#endif
/* Variables for Tree
*/
int MaxNodes; /*!< maximum allowed number of internal nodes */
int Numnodestree; /*!< number of (internal) nodes in each tree */
struct NODE
*Nodes_base, /*!< points to the actual memory allocted for the nodes */
*Nodes; /*!< this is a pointer used to access the nodes which is shifted such that Nodes[All.MaxPart]
gives the first allocated node */
int *Nextnode; /*!< gives next node in tree walk */
int *Father; /*!< gives parent node in tree */
struct extNODE /*!< this structure holds additional tree-node information which is not needed in the actual gravity computation */
*Extnodes_base, /*!< points to the actual memory allocted for the extended node information */
*Extnodes; /*!< provides shifted access to extended node information, parallel to Nodes/Nodes_base */
/*! Header for the standard file format.
*/
struct io_header
header; /*!< holds header for snapshot files */
#ifdef CHIMIE_EXTRAHEADER
/*! Header for the chimie part.
*/
struct io_chimie_extraheader
chimie_extraheader;
#endif
char Tab_IO_Labels[IO_NBLOCKS][4]; /*<! This table holds four-byte character tags used for fileformat 2 */
/* global state of system, used for global statistics
*/
struct state_of_system
SysState; /*<! Structure for storing some global statistics about the simulation. */
/*! This structure contains data related to the energy budget.
These values are different for each task. It need to be stored
in the restart flag.
*/
struct local_state_of_system
LocalSysState; /*<! Structure for storing some local statistics about the simulation. */
/* Various structures for communication
*/
struct gravdata_in
*GravDataIn, /*!< holds particle data to be exported to other processors */
*GravDataGet, /*!< holds particle data imported from other processors */
*GravDataResult, /*!< holds the partial results computed for imported particles. Note: We use GravDataResult = GravDataGet, such that the result replaces the imported data */
*GravDataOut; /*!< holds partial results received from other processors. This will overwrite the GravDataIn array */
struct gravdata_index
*GravDataIndexTable; /*!< the particles to be exported are grouped by task-number. This table allows the results to be disentangled again and to be assigned to the correct particle */
struct densdata_in
*DensDataIn, /*!< holds particle data for SPH density computation to be exported to other processors */
*DensDataGet; /*!< holds imported particle data for SPH density computation */
struct densdata_out
*DensDataResult, /*!< stores the locally computed SPH density results for imported particles */
*DensDataPartialResult; /*!< imported partial SPH density results from other processors */
struct hydrodata_in
*HydroDataIn, /*!< holds particle data for SPH hydro-force computation to be exported to other processors */
*HydroDataGet; /*!< holds imported particle data for SPH hydro-force computation */
struct hydrodata_out
*HydroDataResult, /*!< stores the locally computed SPH hydro results for imported particles */
*HydroDataPartialResult; /*!< imported partial SPH hydro-force results from other processors */
#ifdef MULTIPHASE
struct stickydata_in
*StickyDataIn,
*StickyDataGet;
struct stickydata_out
*StickyDataResult,
*StickyDataPartialResult;
struct Sticky_index *StickyIndex;
#endif
#ifdef CHIMIE
struct chimiedata_in
*ChimieDataIn, /*!< holds particle data for Chimie computation to be exported to other processors */
*ChimieDataGet; /*!< holds imported particle data for Chimie computation */
struct chimiedata_out
*ChimieDataResult, /*!< stores the locally computed Chimie results for imported particles */
*ChimieDataPartialResult; /*!< imported partial Chimie results from other processors */
struct starsdensdata_in
*StarsDensDataIn, /*!< holds particle data for SPH density computation to be exported to other processors */
*StarsDensDataGet; /*!< holds imported particle data for SPH density computation */
struct starsdensdata_out
*StarsDensDataResult, /*!< stores the locally computed SPH density results for imported particles */
*StarsDensDataPartialResult; /*!< imported partial SPH density results from other processors */
#endif
#ifdef DISSIPATION_FORCES
struct dissipationforcesdata_in
*DissipationForcesDataIn, /*!< holds particle data for SPH hydro-force computation to be exported to other processors */
*DissipationForcesDataGet; /*!< holds imported particle data for SPH hydro-force computation */
struct dissipationforcesdata_out
*DissipationForcesDataResult, /*!< stores the locally computed SPH hydro results for imported particles */
*DissipationForcesDataPartialResult; /*!< imported partial SPH hydro-force results from other processors */
#endif /* DISSIPATION_FORCES */
#ifdef FOF
struct FOFdata_in
*FOFDataIn, /*!< holds particle data for SPH hydro-force computation to be exported to other processors */
*FOFDataGet; /*!< holds imported particle data for SPH hydro-force computation */
struct FOFdata_out
*FOFDataResult, /*!< stores the locally computed SPH hydro results for imported particles */
*FOFDataPartialResult; /*!< imported partial SPH hydro-force results from other processors */
+
+struct FOFgravdata_in
+ *FOFGravDataIn, /*!< holds particle data to be exported to other processors */
+ *FOFGravDataGet, /*!< holds particle data imported from other processors */
+ *FOFGravDataResult, /*!< holds the partial results computed for imported particles. Note: We use GravDataResult = GravDataGet, such that the result replaces the imported data */
+ *FOFGravDataOut; /*!< holds partial results received from other processors. This will overwrite the GravDataIn array */
+
+struct FOFgravdata_index
+ *FOFGravDataIndexTable;
+
#endif /* FOF */
+
+
#ifdef TESSEL
struct ghostdata_in
*GhostDataIn, /*!< holds particle data for SPH density computation to be exported to other processors */
*GhostDataGet; /*!< holds imported particle data for SPH density computation */
struct ghostdata_out
*GhostDataResult, /*!< stores the locally computed SPH density results for imported particles */
*GhostDataPartialResult; /*!< imported partial SPH density results from other processors */
//struct ghost_particle_data
// *gP;
int NumgPart;
#endif /* TESSEL */
#ifdef SYNCHRONIZE_NGB_TIMESTEP
struct SynchroinzeNgbTimestepdata_in
*SynchroinzeNgbTimestepDataIn,
*SynchroinzeNgbTimestepDataGet;
#endif
#ifdef PY_INTERFACE
struct sphdata_in
*SphDataIn,
*SphDataGet;
struct sphdata_out
*SphDataResult,
*SphDataPartialResult;
struct denssphdata_in
*DensSphDataIn, /*!< holds particle data for SPH density computation to be exported to other processors */
*DensSphDataGet; /*!< holds imported particle data for SPH density computation */
struct denssphdata_out
*DensSphDataResult, /*!< stores the locally computed SPH density results for imported particles */
*DensSphDataPartialResult; /*!< imported partial SPH density results from other processors */
#endif
diff --git a/src/allvars.h b/src/allvars.h
index ba13529..515efd6 100644
--- a/src/allvars.h
+++ b/src/allvars.h
@@ -1,2586 +1,2652 @@
/*! \file allvars.h
* \brief declares global variables.
*
* This file declares all global variables. Further variables should be added here, and declared as
* 'extern'. The actual existence of these variables is provided by the file 'allvars.c'. To produce
* 'allvars.c' from 'allvars.h', do the following:
*
* - Erase all #define's, typedef's, and enum's
* - add #include "allvars.h", delete the #ifndef ALLVARS_H conditional
* - delete all keywords 'extern'
* - delete all struct definitions enclosed in {...}, e.g.
* "extern struct global_data_all_processes {....} All;"
* becomes "struct global_data_all_processes All;"
*/
#ifndef ALLVARS_H
#define ALLVARS_H
#include <stdio.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_spline.h>
#include <gsl/gsl_integration.h>
#include "tags.h"
#define GADGETVERSION "2.0" /*!< code version string */
#define TIMEBASE (1<<28) /*!< The simulated timespan is mapped onto the integer interval [0,TIMESPAN],
* where TIMESPAN needs to be a power of 2. Note that (1<<28) corresponds to 2^29
*/
#define MAXTOPNODES 200000 /*!< Maximum number of nodes in the top-level tree used for domain decomposition */
typedef long long peanokey; /*!< defines the variable type used for Peano-Hilbert keys */
#define BITS_PER_DIMENSION 18 /*!< Bits per dimension available for Peano-Hilbert order.
Note: If peanokey is defined as type int, the allowed maximum is 10.
If 64-bit integers are used, the maximum is 21 */
#define PEANOCELLS (((peanokey)1)<<(3*BITS_PER_DIMENSION)) /*!< The number of different Peano-Hilbert cells */
#define RNDTABLE 3000 /*!< gives the length of a table with random numbers, refreshed at every timestep.
This is used to allow application of random numbers to a specific particle
in a way that is independent of the number of processors used. */
#define MAX_REAL_NUMBER 1e37
#define MIN_REAL_NUMBER 1e-37
#define MAXLEN_FILENAME 100 /*!< Maximum number of characters for filenames (including the full path) */
#ifdef ISOTHERM_EQS
#define GAMMA (1.0) /*!< index for isothermal gas */
#else
#define GAMMA (5.0/3) /*!< adiabatic index of simulated gas */
#endif
#define GAMMA_MINUS1 (GAMMA-1)
#define HYDROGEN_MASSFRAC 0.76 /*!< mass fraction of hydrogen, relevant only for radiative cooling */
/* Some physical constants in cgs units */
#define GRAVITY 6.672e-8 /*!< Gravitational constant (in cgs units) */
#define SOLAR_MASS 1.989e33
#define SOLAR_LUM 3.826e33
#define RAD_CONST 7.565e-15
#define AVOGADRO 6.0222e23
#define BOLTZMANN 1.3806e-16
#define GAS_CONST 8.31425e7
#define C 2.9979e10
#define PLANCK 6.6262e-27
#define CM_PER_MPC 3.085678e24
#define PROTONMASS 1.6726e-24
#define ELECTRONMASS 9.10953e-28
#define THOMPSON 6.65245e-25
#define ELECTRONCHARGE 4.8032e-10
#define HUBBLE 3.2407789e-18 /* in h/sec */
#define YEAR_IN_SECOND 31536000.0 /* year in sec */
#define FEH_SOLAR 0.00181 /* used only if cooling with metal is on and chimie is off */
#define KPC_IN_CM 3.085678e+21
#define PI 3.1415926535897931
#define TWOPI 6.2831853071795862
/* Some conversion factors */
#define SEC_PER_MEGAYEAR 3.155e13
#define SEC_PER_YEAR 3.155e7
#ifndef ASMTH
#define ASMTH 1.25 /*!< ASMTH gives the scale of the short-range/long-range force split in units of FFT-mesh cells */
#endif
#ifndef RCUT
#define RCUT 4.5 /*!< RCUT gives the maximum distance (in units of the scale used for the force split) out to
which short-range forces are evaluated in the short-range tree walk. */
#endif
#define MAX_NGB 20000 /*!< defines maximum length of neighbour list */
#define MAXLEN_OUTPUTLIST 10000 /*!< maxmimum number of entries in list of snapshot output times */
#define DRIFT_TABLE_LENGTH 1000 /*!< length of the lookup table used to hold the drift and kick factors */
#ifdef COSMICTIME
#define COSMICTIME_TABLE_LENGTH 1000 /*!< length of the lookup table used for the cosmic time computation */
#endif
#define MAXITER 1000 /*!< maxmimum number of steps for SPH neighbour iteration */
#ifdef DOUBLEPRECISION /*!< If defined, the variable type FLOAT is set to "double", otherwise to FLOAT */
#define FLOAT double
#else
#define FLOAT float
#endif
#ifndef TWODIMS
#define NUMDIMS 3 /*!< For 3D-normalized kernel */
#define KERNEL_COEFF_1 2.546479089470 /*!< Coefficients for SPH spline kernel and its derivative */
#define KERNEL_COEFF_2 15.278874536822
#define KERNEL_COEFF_3 45.836623610466
#define KERNEL_COEFF_4 30.557749073644
#define KERNEL_COEFF_5 5.092958178941
#define KERNEL_COEFF_6 (-15.278874536822)
#define NORM_COEFF 4.188790204786 /*!< Coefficient for kernel normalization. Note: 4.0/3 * PI = 4.188790204786 */
#else
#define NUMDIMS 2 /*!< For 2D-normalized kernel */
#define KERNEL_COEFF_1 (5.0/7*2.546479089470) /*!< Coefficients for SPH spline kernel and its derivative */
#define KERNEL_COEFF_2 (5.0/7*15.278874536822)
#define KERNEL_COEFF_3 (5.0/7*45.836623610466)
#define KERNEL_COEFF_4 (5.0/7*30.557749073644)
#define KERNEL_COEFF_5 (5.0/7*5.092958178941)
#define KERNEL_COEFF_6 (5.0/7*(-15.278874536822))
#define NORM_COEFF M_PI /*!< Coefficient for kernel normalization. */
#endif
#ifdef MULTIPHASE
#define GAS_SPH 0
#define GAS_STICKY 1
#define GAS_DARK 2
#endif
#if defined(SFR) || defined(STELLAR_PROP)
#define ST 1
#endif
#ifdef CHIMIE
#define NELEMENTS 10
#define MAXNELEMENTS 64
#endif
#ifdef COOLING
#define COOLING_NMETALICITIES 9
#define COOLING_NTEMPERATURES 171
#endif
#ifdef COMPUTE_VELOCITY_DISPERSION
#define VELOCITY_DISPERSION_SIZE 3
#endif
#ifdef TRACE_ACC
#define NUMTRACEAVG 64
#endif
#ifdef CHIMIE
extern int FE;
extern int METALS;
#endif
extern int SetMinTimeStepForActives;
extern int ThisTask; /*!< the rank of the local processor */
extern int NTask; /*!< number of processors */
extern int PTask; /*!< smallest integer such that NTask <= 2^PTask */
extern int NumPart; /*!< number of particles on the LOCAL processor */
extern int N_gas; /*!< number of gas particles on the LOCAL processor */
#if defined(SFR) || defined(STELLAR_PROP)
extern int N_stars; /*!< number of stars particle on the LOCAL processor */
#endif
#ifdef MULTIPHASE
extern int N_sph;
extern int N_sticky;
extern int N_stickyflaged;
extern int N_dark;
extern int NumColPotLocal; /*!< local number of potentially collisional particles */
extern int NumColPot; /*!< total number of potentially collisional particles */
extern int NumColLocal; /*!< local number of collisions */
extern int NumCol; /*!< total number of collisions */
extern int NumNoColLocal;
extern int NumNoCol;
#endif
#ifdef GAS_ACCRETION
extern int NumPart_acc;
extern int N_gas_acc;
#ifdef STELLAR_PROP
extern int N_stars_acc;
#endif
#endif
#ifdef HOT_HALO
extern int NumPart_HaloAcc;
#endif
extern long long Ntype[6]; /*!< total number of particles of each type */
extern int NtypeLocal[6]; /*!< local number of particles of each type */
extern int NumForceUpdate; /*!< number of active particles on local processor in current timestep */
extern int NumSphUpdate; /*!< number of active SPH particles on local processor in current timestep */
#ifdef CHIMIE
extern int NumStUpdate;
#endif
#ifdef TESSEL
extern int NumPTUpdate;
#endif
extern double CPUThisRun; /*!< Sums the CPU time for the process (current submission only) */
#ifdef SPLIT_DOMAIN_USING_TIME
extern double CPU_Gravity;
#endif
extern int RestartFlag; /*!< taken from command line used to start code. 0 is normal start-up from
initial conditions, 1 is resuming a run from a set of restart files, while 2
marks a restart from a snapshot file. */
extern char *Exportflag; /*!< Buffer used for flagging whether a particle needs to be exported to another process */
extern int *Ngblist; /*!< Buffer to hold indices of neighbours retrieved by the neighbour search routines */
extern int TreeReconstructFlag; /*!< Signals that a new tree needs to be constructed */
#ifdef SFR
extern int RearrangeParticlesFlag;/*!< Signals that particles must be rearanged */
#endif
extern int Flag_FullStep; /*!< This flag signals that the current step involves all particles */
extern gsl_rng *random_generator; /*!< the employed random number generator of the GSL library */
extern double RndTable[RNDTABLE]; /*!< Hold a table with random numbers, refreshed every timestep */
#ifdef SFR
extern double StarFormationRndTable[RNDTABLE]; /*!< Hold a table with random numbers, refreshed every timestep */
#endif
#ifdef FEEDBACK_WIND
extern double FeedbackWindRndTable[RNDTABLE]; /*!< Hold a table with random numbers, refreshed every timestep */
#endif
#ifdef CHIMIE
extern double ChimieRndTable[RNDTABLE]; /*!< Hold a table with random numbers, refreshed every timestep */
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
extern double ChimieKineticFeedbackRndTable[RNDTABLE]; /*!< Hold a table with random numbers, refreshed every timestep */
#endif
#ifdef GAS_ACCRETION
extern double gasAccretionRndTable[RNDTABLE]; /*!< Hold a table with random numbers, refreshed every timestep */
#endif
#ifdef HOT_HALO
extern double HaloRndTable[RNDTABLE]; /*!< Hold a table with random numbers, refreshed every timestep */
#endif
#ifdef AB_TURB
//Ornstein-Uhlenbeck variables
extern double StOUVar;
extern double* StOUPhases;
extern gsl_rng* StRng;
//forcing field in fourie space
extern double* StAmpl;
extern double* StAka; //phases (real part)
extern double* StAkb; //phases (imag part)
extern double* StMode;
extern int StNModes;
//integertime StTPrev; (yr : ask ?)
extern int StTPrev;
extern double StSolWeightNorm;
#endif
#ifdef PY_INTERFACE
extern int NumPartQ;
extern int N_gasQ;
extern long long NtypeQ[6]; /*!< total number of particles of each type */
extern int NtypeLocalQ[6]; /*!< local number of particles of each type */
extern double DomainCornerQ[3]; /*!< gives the lower left corner of simulation volume */
extern double DomainCenterQ[3]; /*!< gives the center of simulation volume */
extern double DomainLenQ; /*!< gives the (maximum) side-length of simulation volume */
extern double DomainFacQ; /*!< factor used for converting particle coordinates to a Peano-Hilbert mesh covering the simulation volume */
extern int DomainMyStartQ; /*!< first domain mesh cell that resides on the local processor */
extern int DomainMyLastQ; /*!< last domain mesh cell that resides on the local processor */
extern int *DomainStartListQ; /*!< a table that lists the first domain mesh cell for all processors */
extern int *DomainEndListQ; /*!< a table that lists the last domain mesh cell for all processors */
extern double *DomainWorkQ; /*!< a table that gives the total "work" due to the particles stored by each processor */
extern int *DomainCountQ; /*!< a table that gives the total number of particles held by each processor */
extern int *DomainCountSphQ; /*!< a table that gives the total number of SPH particles held by each processor */
extern int *DomainTaskQ; /*!< this table gives for each leaf of the top-level tree the processor it was assigned to */
extern peanokey *DomainKeyBufQ; /*!< this points to a buffer used during the exchange of particle data */
extern int NTopnodesQ; /*!< total number of nodes in top-level tree */
extern int NTopleavesQ; /*!< number of leaves in top-level tree. Each leaf can be assigned to a different processor */
extern void *CommBufferQ; /*!< points to communication buffer, which is used in the domain decomposition, the
parallel tree-force computation, the SPH routines, etc. */
#endif
extern double DomainCorner[3]; /*!< gives the lower left corner of simulation volume */
extern double DomainCenter[3]; /*!< gives the center of simulation volume */
extern double DomainLen; /*!< gives the (maximum) side-length of simulation volume */
extern double DomainFac; /*!< factor used for converting particle coordinates to a Peano-Hilbert mesh covering the simulation volume */
extern int DomainMyStart; /*!< first domain mesh cell that resides on the local processor */
extern int DomainMyLast; /*!< last domain mesh cell that resides on the local processor */
extern int *DomainStartList; /*!< a table that lists the first domain mesh cell for all processors */
extern int *DomainEndList; /*!< a table that lists the last domain mesh cell for all processors */
extern double *DomainWork; /*!< a table that gives the total "work" due to the particles stored by each processor */
extern int *DomainCount; /*!< a table that gives the total number of particles held by each processor */
extern int *DomainCountSph; /*!< a table that gives the total number of SPH particles held by each processor */
extern int *DomainTask; /*!< this table gives for each leaf of the top-level tree the processor it was assigned to */
extern int *DomainNodeIndex; /*!< this table gives for each leaf of the top-level tree the corresponding node of the gravitational tree */
extern FLOAT *DomainTreeNodeLen; /*!< this table gives for each leaf of the top-level tree the side-length of the corresponding node of the gravitational tree */
extern FLOAT *DomainHmax; /*!< this table gives for each leaf of the top-level tree the maximum SPH smoothing length among the particles of the corresponding node of the gravitational tree */
extern struct DomainNODE
{
FLOAT s[3]; /*!< center-of-mass coordinates */
FLOAT vs[3]; /*!< center-of-mass velocities */
FLOAT mass; /*!< mass of node */
#ifdef STELLAR_FLUX
FLOAT starlum; /*!< star luminosity of node */
#endif
#ifdef UNEQUALSOFTENINGS
#ifndef ADAPTIVE_GRAVSOFT_FORGAS
int bitflags; /*!< this bit-field encodes the particle type with the largest softening among the particles of the nodes, and whether there are particles with different softening in the node */
#else
FLOAT maxsoft; /*!< hold the maximum gravitational softening of particles in the
node if the ADAPTIVE_GRAVSOFT_FORGAS option is selected */
#endif
#endif
}
*DomainMoment; /*!< this table stores for each node of the top-level tree corresponding node data from the gravitational tree */
extern peanokey *DomainKeyBuf; /*!< this points to a buffer used during the exchange of particle data */
extern peanokey *Key; /*!< a table used for storing Peano-Hilbert keys for particles */
extern peanokey *KeySorted; /*!< holds a sorted table of Peano-Hilbert keys for all particles, used to construct top-level tree */
extern int NTopnodes; /*!< total number of nodes in top-level tree */
extern int NTopleaves; /*!< number of leaves in top-level tree. Each leaf can be assigned to a different processor */
extern struct topnode_data
{
int Daughter; /*!< index of first daughter cell (out of 8) of top-level node */
int Pstart; /*!< for the present top-level node, this gives the index of the first node in the concatenated list of topnodes collected from all processors */
int Blocks; /*!< for the present top-level node, this gives the number of corresponding nodes in the concatenated list of topnodes collected from all processors */
int Leaf; /*!< if the node is a leaf, this gives its number when all leaves are traversed in Peano-Hilbert order */
peanokey Size; /*!< number of Peano-Hilbert mesh-cells represented by top-level node */
peanokey StartKey; /*!< first Peano-Hilbert key in top-level node */
long long Count; /*!< counts the number of particles in this top-level node */
}
#ifdef PY_INTERFACE
*TopNodesQ,
#endif
*TopNodes; /*!< points to the root node of the top-level tree */
extern double TimeOfLastTreeConstruction; /*!< holds what it says, only used in connection with FORCETEST */
/* variables for input/output, usually only used on process 0 */
extern char ParameterFile[MAXLEN_FILENAME]; /*!< file name of parameterfile used for starting the simulation */
extern FILE *FdInfo; /*!< file handle for info.txt log-file. */
extern FILE *FdLog; /*!< file handle for log.txt log-file. */
extern FILE *FdEnergy; /*!< file handle for energy.txt log-file. */
#ifdef SYSTEMSTATISTICS
extern FILE *FdSystem;
#endif
extern FILE *FdTimings; /*!< file handle for timings.txt log-file. */
extern FILE *FdCPU; /*!< file handle for cpu.txt log-file. */
#ifdef FORCETEST
extern FILE *FdForceTest; /*!< file handle for forcetest.txt log-file. */
#endif
#ifdef SFR
extern FILE *FdSfr; /*!< file handle for sfr.txt log-file. */
#endif
#ifdef CHIMIE
extern FILE *FdChimie; /*!< file handle for chimie log-file. */
#ifdef CHIMIE_STATS
extern FILE *FdChimieStatsSNs; /*!< file handle for chimie stats-file. */
extern FILE *FdChimieStatsGas; /*!< file handle for chimie stats-file. */
#endif
+#ifdef FOF
+extern FILE *FdFOF_Chimie; /*!< file handle for fof chimie log-file. */
+#endif
#endif
#ifdef MULTIPHASE
extern FILE *FdPhase; /*!< file handle for pase.txt log-file. */
extern FILE *FdSticky; /*!< file handle for sticky.txt log-file. */
#endif
#ifdef AGN_ACCRETION
extern FILE *FdAccretion; /*!< file handle for accretion.txt log-file. */
#endif
#ifdef BONDI_ACCRETION
extern FILE *FdBondi; /*!< file handle for bondi.txt log-file. */
#endif
#ifdef BUBBLES
extern FILE *FdBubble; /*!< file handle for bubble.txt log-file. */
#endif
#ifdef GAS_ACCRETION
extern FILE *FdGasAccretion; /*!< file handle for gas_accretion.txt log-file. */
#endif
#ifdef PERIODICOUTER
extern FILE *FdTrace; /*!< file handle for trace.txt log-file. */
#endif
extern double DriftTable[DRIFT_TABLE_LENGTH]; /*!< table for the cosmological drift factors */
extern double GravKickTable[DRIFT_TABLE_LENGTH]; /*!< table for the cosmological kick factor for gravitational forces */
extern double HydroKickTable[DRIFT_TABLE_LENGTH]; /*!< table for the cosmological kick factor for hydrodynmical forces */
#ifdef COSMICTIME
extern double CosmicTimeTable[COSMICTIME_TABLE_LENGTH]; /*!< table for the computation of cosmic time */
extern double FullCosmicTimeTable[COSMICTIME_TABLE_LENGTH]; /*!< table for the computation of cosmic time */
extern double FullCosmicTimeTableInv[COSMICTIME_TABLE_LENGTH]; /*!< table for the computation of cosmic time */
#endif
extern void *CommBuffer; /*!< points to communication buffer, which is used in the domain decomposition, the
parallel tree-force computation, the SPH routines, etc. */
/*! This structure contains data which is the SAME for all tasks (mostly code parameters read from the
* parameter file). Holding this data in a structure is convenient for writing/reading the restart file, and
* it allows the introduction of new global variables in a simple way. The only thing to do is to introduce
* them into this structure.
*/
extern struct global_data_all_processes
{
long long TotNumPart; /*!< total particle numbers (global value) */
long long TotN_gas; /*!< total gas particle number (global value) */
#ifdef GAS_ACCRETION
long long TotNumPart_acc;
long long TotN_gas_acc;
#endif
#ifdef HOT_HALO
long long TotNumPart_HaloAcc;
#endif
#ifdef PY_INTERFACE
long long TotNumPartQ; /*!< total particle numbers (global value) */
long long TotN_gasQ; /*!< total gas particle number (global value) */
int MaxPartQ; /*!< This gives the maxmimum number of particles that can be stored on one processor. */
int MaxPartSphQ; /*!< This gives the maxmimum number of SPH particles that can be stored on one processor. */
int BunchSizeSph;
int BunchSizeDensitySph;
double ForceSofteningQ;
#endif
#if defined(SFR) || defined(STELLAR_PROP)
long long TotN_stars; /*!< total stars particle number (global value) */
#endif
#ifdef MULTIPHASE
long long TotN_sph; /*!< total sph particle number (global value) */
long long TotN_sticky; /*!< total sticky particle number (global value) */
long long TotN_stickyflaged; /*!< total sticky flaged particle number (global value) */
long long TotN_stickyactive; /*!< total sticky active particle number (global value) */
long long TotN_dark; /*!< total dark particle number (global value) */
#endif
int MaxPart; /*!< This gives the maxmimum number of particles that can be stored on one processor. */
int MaxPartSph; /*!< This gives the maxmimum number of SPH particles that can be stored on one processor. */
#ifdef TESSEL
int MaxgPart;
#endif
#ifdef STELLAR_PROP
int MaxPartStars; /*!< This gives the maxmimum number of Star particles that can be stored on one processor. */
#endif
double BoxSize; /*!< Boxsize in case periodic boundary conditions are used */
int ICFormat; /*!< selects different versions of IC file-format */
int SnapFormat; /*!< selects different versions of snapshot file-formats */
int NumFilesPerSnapshot; /*!< number of files in multi-file snapshot dumps */
int NumFilesWrittenInParallel;/*!< maximum number of files that may be written simultaneously when
writing/reading restart-files, or when writing snapshot files */
int BufferSize; /*!< size of communication buffer in MB */
int BunchSizeForce; /*!< number of particles fitting into the buffer in the parallel tree-force algorithm */
int BunchSizeDensity; /*!< number of particles fitting into the communication buffer in the density computation */
int BunchSizeHydro; /*!< number of particles fitting into the communication buffer in the SPH hydrodynamical force computation */
int BunchSizeDomain; /*!< number of particles fitting into the communication buffer in the domain decomposition */
#ifdef MULTIPHASE
int BunchSizeSticky; /*!< number of particles fitting into the communication buffer in the Chimie computation */
#endif
#ifdef CHIMIE
int BunchSizeChimie; /*!< number of particles fitting into the communication buffer in the Chimie computation */
int BunchSizeStarsDensity; /*!< number of particles fitting into the communication buffer in the star density computation */
#endif
#ifdef SYNCHRONIZE_NGB_TIMESTEP
int BunchSizeSynchronizeNgBTimestep;
#endif
#ifdef DISSIPATION_FORCES
int BunchSizeDissipationForces;
#endif
#ifdef FOF
int BunchSizeFOF;
+ int BunchSizeForceFOF;
#endif
#ifdef TESSEL
int BunchSizeGhost;
#endif
double PartAllocFactor; /*!< in order to maintain work-load balance, the particle load will usually
NOT be balanced. Each processor allocates memory for PartAllocFactor times
the average number of particles to allow for that */
double TreeAllocFactor; /*!< Each processor allocates a number of nodes which is TreeAllocFactor times
the maximum(!) number of particles. Note: A typical local tree for N
particles needs usually about ~0.65*N nodes. */
#ifdef SFR
double StarsAllocFactor; /*!< Estimated fraction of gas particles that will form stars during the simulation
This allow to reduce the memory stored for stellar particles */
#endif
/* some SPH parameters */
double DesNumNgb; /*!< Desired number of SPH neighbours */
double MaxNumNgbDeviation; /*!< Maximum allowed deviation neighbour number */
double ArtBulkViscConst; /*!< Sets the parameter \f$\alpha\f$ of the artificial viscosity */
#ifdef ART_CONDUCTIVITY
double ArtCondConst; /*!< Sets the parameter \f$\alpha\f$ of the artificial conductivity */
double ArtCondThreshold;
#endif
double InitGasTemp; /*!< may be used to set the temperature in the IC's */
double MinGasTemp; /*!< may be used to set a floor for the gas temperature */
double MinEgySpec; /*!< the minimum allowed temperature expressed as energy per unit mass */
/* Usefull constants */
double Boltzmann;
double ProtonMass;
double mumh;
#ifdef COOLING
/* Cooling parameters */
double *logT;
double *logL;
gsl_interp_accel *acc_cooling_spline;
gsl_spline *cooling_spline;
double CoolingType;
#ifdef PYCOOL
char * CoolingFile;
#else
char CoolingFile[MAXLEN_FILENAME]; /*!< cooling file */
#endif
double CutofCoolingTemperature;
/*
new metal dependent cooling
*/
double CoolingParameters_zmin;
double CoolingParameters_zmax;
double CoolingParameters_slz;
double CoolingParameters_tmin;
double CoolingParameters_tmax;
double CoolingParameters_slt;
double CoolingParameters_FeHSolar;
double CoolingParameters_ZHSolar;
double CoolingParameters_cooling_data_max;
double CoolingParameters_cooling_data[COOLING_NMETALICITIES][COOLING_NTEMPERATURES];
int CoolingParameters_p;
int CoolingParameters_q;
#ifdef COOLING_WIERSMA
char CoolingDirectory[MAXLEN_FILENAME]; /*!< cooling directory */
#endif
#ifdef COOLING_GRACKLE
char GrackleCloudyTable[MAXLEN_FILENAME]; /*!< cooling cloudy table */
int GrackleUVbackground;
double GrackleRedshift;
#ifdef COOLING_GRACKLE_H_SSHIELDING
double GrackleHSShieldingDensityThreshold; /*!< Hydrogen self-shielding density threshold */
#endif
#endif
#ifdef COOLING_FCT_FROM_HDF5
// cooling tables loaded from HDF5 files
// (dimensions depend on the presence of nHe)
float*** COOLING_TABLES_METAL_FREE;
float** COOLING_TABLES_TOTAL_METAL;
float*** ELECTRON_DENSITY_OVER_N_H_TABLES;
float** ELECTRON_DENSITY_OVER_N_H_TABLES_SOLAR;
float* HYDROGEN_TABLES;
float* TEMPERATURE_TABLES;
float* HELIUM_ABOUNDANCE_TABLES;
//corresponding sizes
int SIZE_HYDROGEN_TABLES;
int SIZE_TEMPERATURE_TABLES;
int SIZE_HELIUM_ABOUNDANCE_TABLES;
// current redshift value determining the cooling file
// from which the data is interpolated
float CURRENT_TABLE_REDSHIFT;
#endif
#endif
#ifdef CHIMIE
int ChimieNumberOfParameterFiles;
#ifdef PYCHEM
char * ChimieParameterFile;
#else
char ChimieParameterFile[MAXLEN_FILENAME]; /*!< chimie parameter file */
#endif
double ChimieSupernovaEnergy;
double ChimieKineticFeedbackFraction;
double ChimieWindSpeed;
double ChimieWindTime;
double ChimieSNIaThermalTime;
double ChimieSNIIThermalTime;
double ChimieMaxSizeTimestep;
#ifdef CHIMIE_TIMEBET
double ChimieTimeBetChimie; /*!< simulation time interval between computations of Chimie */
double ChimieTimeLastChimie; /*!< simulation time when the Chimie was computed the last time */
double ChimieTi_begstep; /*!< start of chimie step */
#endif
#ifdef CHIMIE_ONE_SN_ONLY /*!< explode only one sn>*/
int ChimieOneSN;
double ChimieOneSNMass;
#endif
#if CHIMIE_EJECTA_RADIUS == 1
double ChimieEjectaRadius;
#endif
#endif
#if defined (CHIMIE) || defined (COOLING)
double InitGasMetallicity; /*!< initial gas metallicity>*/
double GasMetal; /*!< gas metal fraction, used when CHIMIE is disabled >*/
#endif
#if !defined (HEATING_PE)
double HeatingPeElectronFraction;
#endif
#if !defined (HEATING_PE) || defined (STELLAR_FLUX) || defined (EXTERNAL_FLUX)
double HeatingPeSolarEnergyDensity;
#endif
#if !defined (HEATING_PE) || defined (STELLAR_FLUX)
double HeatingPeLMRatioGas;
double HeatingPeLMRatioHalo;
double HeatingPeLMRatioDisk;
double HeatingPeLMRatioBulge;
double HeatingPeLMRatioStars;
double HeatingPeLMRatioBndry;
double HeatingPeLMRatio[6];
#endif
#ifdef EXTERNAL_FLUX
double HeatingExternalFLuxEnergyDensity;
#endif
#ifdef MULTIPHASE
double CriticalTemperature;
double CriticalEgySpec;
double CriticalNonCollisionalTemperature;
double CriticalNonCollisionalEgySpec;
#ifdef COLDGAS_CYCLE
double ColdGasCycleTransitionTime;
double ColdGasCycleTransitionParameter;
#endif
#endif
#ifdef MULTIPHASE
/* some STICKY parameters */
int StickyUseGridForCollisions;
double StickyTime; /*!< Cooling time of sticky particle collision */
double StickyCollisionTime;
double StickyLastCollisionTime;
double StickyIdleTime;
double StickyMinVelocity;
double StickyMaxVelocity;
int StickyGridNx;
int StickyGridNy;
int StickyGridNz;
double StickyGridXmin;
double StickyGridXmax;
double StickyGridYmin;
double StickyGridYmax;
double StickyGridZmin;
double StickyGridZmax;
double StickyLambda;
double StickyDensity;
double StickyDensityPower;
double StickyBetaR;
double StickyBetaT;
double StickyRsphFact; /*!< Fraction of the sph radius used in sticky particle */
#endif
#ifdef JEANS_PRESSURE_FLOOR
double JeansMassFactor;
#endif
#ifdef OUTERPOTENTIAL
#ifdef NFW
double HaloConcentration;
double HaloMass;
double GasMassFraction;
double NFWPotentialCte;
double Rs;
#endif
#ifdef PLUMMER
double PlummerMass;
double PlummerSoftenning;
double PlummerPotentialCte;
#endif
#ifdef HOMOSPHERE
double HomosphereMass;
double HomosphereMaxRadius;
double HomospherePotentialCte;
#endif
#ifdef MIYAMOTONAGAI
double MiyamotoNagaiMass;
double MiyamotoNagaiHr;
double MiyamotoNagaiHz;
double MiyamotoNagaiPotentialCte;
#endif
#ifdef PISOTHERM
double Rho0;
double Rc;
double PisothermPotentialCte;
double GasMassFraction;
double PotentialInf;
gsl_function PotentialF;
gsl_integration_workspace *Potentialw;
#endif
#ifdef CORIOLIS
double CoriolisOmegaX;
double CoriolisOmegaY;
double CoriolisOmegaZ;
double CoriolisOmegaX0;
double CoriolisOmegaY0;
double CoriolisOmegaZ0;
#endif
#endif
#ifdef SFR
int StarFormationNStarsFromGas;
double StarFormationStarMass;
double StarFormationMgMsFraction;
int StarFormationType;
double StarFormationCstar;
double StarFormationTime;
double StarFormationDensity;
double StarFormationTemperature;
double ThresholdDensity;
#ifndef LONGIDS
unsigned int MaxID; /* max value of ID, this is used to set id of new stars */
#else
unsigned long long MaxID; /* max value of ID, this is used to set id of new stars */
#endif
#ifdef SFR_USE_JEANS
double StarformationSofteningMaxPhys;
double StarformationSoftening;
double StarformationJeansMassFactor;
#endif
#endif /* SFR */
#ifdef FOF
double FoF_ThresholdDensity; /* threshold density : particles with density below FoF_ThresholdDensity are excluded from the FoF */
double FoF_MinHeadDensity; /* keep only heads with density higher than this value */
double FoF_Density;
double FoF_ThresholdDensityFactor;
double FoF_MinHeadDensityFactor;
int FoF_MinGroupMembers; /* minimum members required to form stars */
double FoF_MinGroupMass; /* minimum mass required to form stars (in solar mass) */
double FoF_VirialFractionThreshold; /* virial fraction value, below which a group is assumed to be bound */
double FoF_HsmlSearchRadiusFactor; /* friends are search in a radius given by hsml time this factor */
double FoF_HsmlMaxDistFactor; /* a particle may be linked to a head only if ``r < Hsml*FoF_HsmlMaxDistFactor``*/
int FoF_StarFormationType; /*!< allow to tune the sfr in FOF */
double FoF_TimeBetFoF; /*!< simulation time interval between computations of FoF */
double FoF_TimeLastFoF; /*!< simulation time when the FoF was computed the last time */
- int FoF_SnapshotFileCount; /*!< number of snapshot that is written next */
- char FoF_SnapshotFileBase[MAXLEN_FILENAME]; /*!< basename to construct the names of snapshotf files */
+ int FoF_SnapshotFileCount_Accepted; /*!< number of snapshot that is written next */
+ int FoF_SnapshotFileCount_Rejected; /*!< number of snapshot that is written next */
+ int FoF_IMFSnapshotFileCount; /*!< number of snapshot that is written next */
+
+ char FoF_SnapshotFileBase[MAXLEN_FILENAME]; /*!< basename to construct the names of fof snapshot files */
+ char FoF_IMFSnapshotFileBase[MAXLEN_FILENAME]; /*!< basename to construct the names of imf snapshot files */
+
+#ifdef CHIMIE
+ char FoF_ChimieFile[MAXLEN_FILENAME];
#endif
+#endif // FOF
+
#ifdef FEEDBACK
double SupernovaTime;
#endif
#ifdef FEEDBACK_WIND
double SupernovaWindEgySpecPerMassUnit;
double SupernovaWindFractionInEgyKin;
double SupernovaWindParameter;
double SupernovaWindSpeed;
double SupernovaWindIntAccuracy;
#endif
#ifdef AGN_ACCRETION
double TimeBetAccretion;
double AccretionRadius;
double AGNFactor;
double MinMTotInRa;
double TimeLastAccretion;
double LastMTotInRa;
double MTotInRa;
double dMTotInRa;
#endif
#ifdef BUBBLES
char BubblesInitFile[MAXLEN_FILENAME]; /*!< bubble file */
double *BubblesTime;
double *BubblesD;
double *BubblesR;
double *BubblesE;
double *BubblesA;
double *BubblesB;
int BubblesIndex;
double BubblesAlpha;
double BubblesBeta;
double BubblesDelta;
double BubblesRadiusFactor;
double EnergyBubbles;
#endif
#ifdef AGN_HEATING
double AGNHeatingPower;
double AGNHeatingRmax;
#endif
#ifdef BONDI_ACCRETION
double BondiEfficiency;
double BondiBlackHoleMass;
double BondiHsmlFactor;
double BondiPower;
double BondiTimeBet;
double BondiTimeLast;
#endif
#if defined (AGN_ACCRETION) || defined (BONDI_ACCRETION)
double LightSpeed;
#endif
#if defined(ART_VISCO_MM)|| defined(ART_VISCO_RO) || defined(ART_VISCO_CD)
double ArtBulkViscConstMin;
double ArtBulkViscConstMax;
double ArtBulkViscConstL;
#endif
#ifdef METAL_DIFFUSION
double MetalDiffusionConst;
#endif
#ifdef AB_TURB
double StDecay;
double StEnergy;
double StDtFreq;
double StKmin;
double StKmax;
double StSolWeight;
double StAmplFac;
int StSpectForm;
int StSeed;
#endif
#ifdef GAS_ACCRETION
double AccretionParticleMass[6];
#endif
#ifdef SYNCHRONIZE_NGB_TIMESTEP
int NgbFactorTimestep;
#endif
/* some force counters */
long long TotNumOfForces; /*!< counts total number of force computations */
long long NumForcesSinceLastDomainDecomp; /*!< count particle updates since last domain decomposition */
/* system of units */
double G; /*!< Gravity-constant in internal units */
double UnitTime_in_s; /*!< factor to convert internal time unit to seconds/h */
double UnitMass_in_g; /*!< factor to convert internal mass unit to grams/h */
double UnitVelocity_in_cm_per_s; /*!< factor to convert intqernal velocity unit to cm/sec */
double UnitLength_in_cm; /*!< factor to convert internal length unit to cm/h */
double UnitPressure_in_cgs; /*!< factor to convert internal pressure unit to cgs units (little 'h' still around!) */
double UnitDensity_in_cgs; /*!< factor to convert internal length unit to g/cm^3*h^2 */
double UnitCoolingRate_in_cgs; /*!< factor to convert internal cooling rate to cgs units */
double UnitEnergy_in_cgs; /*!< factor to convert internal energy to cgs units */
double UnitTime_in_Megayears; /*!< factor to convert internal time to megayears/h */
double GravityConstantInternal; /*!< If set to zero in the parameterfile, the internal value of the
gravitational constant is set to the Newtonian value based on the system of
units specified. Otherwise the value provided is taken as internal gravity constant G. */
/* Cosmological parameters */
double Hubble; /*!< Hubble-constant in internal units */
double Omega0; /*!< matter density in units of the critical density (at z=0)*/
double OmegaLambda; /*!< vaccum energy density relative to crictical density (at z=0) */
double OmegaBaryon; /*!< baryon density in units of the critical density (at z=0)*/
double HubbleParam; /*!< little `h', i.e. Hubble constant in units of 100 km/s/Mpc. Only needed to get absolute physical values for cooling physics */
#ifdef HUBBLE_PARAM_WHEN_NOT_IN_UNITS
double HubbleParamNIU; /*!< little `h', i.e. Hubble constant in units of 100 km/s/Mpc. Only needed to get redshift when physical units are used */
#endif
/* Code options */
int ComovingIntegrationOn; /*!< flags that comoving integration is enabled */
int PeriodicBoundariesOn; /*!< flags that periodic boundaries are enabled */
int ResubmitOn; /*!< flags that automatic resubmission of job to queue system is enabled */
int TypeOfOpeningCriterion; /*!< determines tree cell-opening criterion: 0 for Barnes-Hut, 1 for relative criterion */
int TypeOfTimestepCriterion; /*!< gives type of timestep criterion (only 0 supported right now - unlike gadget-1.1) */
int OutputListOn; /*!< flags that output times are listed in a specified file */
/* Parameters determining output frequency */
int SnapshotFileCount; /*!< number of snapshot that is written next */
double TimeBetSnapshot; /*!< simulation time interval between snapshot files */
double TimeOfFirstSnapshot; /*!< simulation time of first snapshot files */
double CpuTimeBetRestartFile; /*!< cpu-time between regularly generated restart files */
double TimeLastRestartFile; /*!< cpu-time when last restart-file was written */
double TimeBetStatistics; /*!< simulation time interval between computations of energy statistics */
double TimeLastStatistics; /*!< simulation time when the energy statistics was computed the last time */
int NumCurrentTiStep; /*!< counts the number of system steps taken up to this point */
/* Current time of the simulation, global step, and end of simulation */
double Time; /*!< current time of the simulation */
double TimeBegin; /*!< time of initial conditions of the simulation */
double TimeStep; /*!< difference between current times of previous and current timestep */
double TimeMax; /*!< marks the point of time until the simulation is to be evolved */
/* variables for organizing discrete timeline */
double Timebase_interval; /*!< factor to convert from floating point time interval to integer timeline */
int Ti_Current; /*!< current time on integer timeline */
int Ti_nextoutput; /*!< next output time on integer timeline */
#ifdef FLEXSTEPS
int PresentMinStep; /*!< If FLEXSTEPS is used, particle timesteps are chosen as multiples of the present minimum timestep. */
int PresentMaxStep; /*!< If FLEXSTEPS is used, this is the maximum timestep in timeline units, rounded down to the next power 2 division */
#endif
#ifdef PMGRID
int PM_Ti_endstep; /*!< begin of present long-range timestep */
int PM_Ti_begstep; /*!< end of present long-range timestep */
#endif
/* Placement of PM grids */
#ifdef PMGRID
double Asmth[2]; /*!< Gives the scale of the long-range/short-range split (in mesh-cells), both for the coarse and the high-res mesh */
double Rcut[2]; /*!< Gives the maximum radius for which the short-range force is evaluated with the tree (in mesh-cells), both for the coarse and the high-res mesh */
double Corner[2][3]; /*!< lower left corner of coarse and high-res PM-mesh */
double UpperCorner[2][3]; /*!< upper right corner of coarse and high-res PM-mesh */
double Xmintot[2][3]; /*!< minimum particle coordinates both for coarse and high-res PM-mesh */
double Xmaxtot[2][3]; /*!< maximum particle coordinates both for coarse and high-res PM-mesh */
double TotalMeshSize[2]; /*!< total extension of coarse and high-res PM-mesh */
#endif
/* Variables that keep track of cumulative CPU consumption */
double TimeLimitCPU; /*!< CPU time limit as defined in parameterfile */
double CPU_TreeConstruction; /*!< time spent for constructing the gravitational tree */
double CPU_TreeWalk; /*!< actual time spent for pure tree-walks */
double CPU_Gravity; /*!< cumulative time used for gravity computation (tree-algorithm only) */
double CPU_Potential; /*!< time used for computing gravitational potentials */
double CPU_Domain; /*!< cumulative time spent for domain decomposition */
double CPU_Snapshot; /*!< time used for writing snapshot files */
double CPU_Total; /*!< cumulative time spent for domain decomposition */
double CPU_CommSum; /*!< accumulated time used for communication, and for collecting partial results, in tree-gravity */
double CPU_Imbalance; /*!< cumulative time lost accross all processors as work-load imbalance in gravitational tree */
double CPU_HydCompWalk; /*!< time used for actual SPH computations, including neighbour search */
double CPU_HydCommSumm; /*!< cumulative time used for communication in SPH, and for collecting partial results */
double CPU_HydImbalance; /*!< cumulative time lost due to work-load imbalance in SPH */
double CPU_Hydro; /*!< cumulative time spent for SPH related computations */
#ifdef SFR
double CPU_StarFormation; /*!< cumulative time spent for star formation computations */
#endif
#ifdef CHIMIE
double CPU_Chimie; /*!< cumulative time spent for chimie computations */
double CPU_ChimieDensCompWalk;
double CPU_ChimieDensCommSumm;
double CPU_ChimieDensImbalance;
double CPU_ChimieDensEnsureNgb;
double CPU_ChimieCompWalk;
double CPU_ChimieCommSumm;
double CPU_ChimieImbalance;
#endif
#ifdef MULTIPHASE
double CPU_Sticky; /*!< cumulative time spent for sticky computations */
#endif
double CPU_EnsureNgb; /*!< time needed to iterate on correct neighbour numbers */
double CPU_Predict; /*!< cumulative time to drift the system forward in time, including dynamic tree updates */
double CPU_TimeLine; /*!< time used for determining new timesteps, and for organizing the timestepping, including kicks of active particles */
double CPU_PM; /*!< time used for long-range gravitational force */
double CPU_Peano; /*!< time required to establish Peano-Hilbert order */
#ifdef DETAILED_CPU_DOMAIN
double CPU_Domain_findExtend;
double CPU_Domain_determineTopTree;
double CPU_Domain_sumCost;
double CPU_Domain_findSplit;
double CPU_Domain_shiftSplit;
double CPU_Domain_countToGo;
double CPU_Domain_exchange;
#endif
#ifdef DETAILED_CPU_GRAVITY
double CPU_Gravity_TreeWalk1;
double CPU_Gravity_TreeWalk2;
double CPU_Gravity_CommSum1;
double CPU_Gravity_CommSum2;
double CPU_Gravity_Imbalance1;
double CPU_Gravity_Imbalance2;
#endif
#ifdef COOLING
double CPU_Cooling;
#endif
#ifdef DETAILED_CPU
double CPU_Leapfrog;
double CPU_Physics;
double CPU_Residual;
double CPU_Accel;
double CPU_Begrun;
#endif
/* tree code opening criterion */
double ErrTolTheta; /*!< BH tree opening angle */
double ErrTolForceAcc; /*!< parameter for relative opening criterion in tree walk */
/* adjusts accuracy of time-integration */
double ErrTolIntAccuracy; /*!< accuracy tolerance parameter \f$ \eta \f$ for timestep criterion. The
timestep is \f$ \Delta t = \sqrt{\frac{2 \eta eps}{a}} \f$ */
double MinSizeTimestep; /*!< minimum allowed timestep. Normally, the simulation terminates if the
timestep determined by the timestep criteria falls below this limit. */
double MaxSizeTimestep; /*!< maximum allowed timestep */
double MaxRMSDisplacementFac; /*!< this determines a global timestep criterion for cosmological simulations
in comoving coordinates. To this end, the code computes the rms velocity
of all particles, and limits the timestep such that the rms displacement
is a fraction of the mean particle separation (determined from the
particle mass and the cosmological parameters). This parameter specifies
this fraction. */
double CourantFac; /*!< SPH-Courant factor */
/* frequency of tree reconstruction/domain decomposition */
double TreeDomainUpdateFrequency; /*!< controls frequency of domain decompositions */
/* Gravitational and hydrodynamical softening lengths (given in terms of an `equivalent' Plummer softening length).
* Five groups of particles are supported 0="gas", 1="halo", 2="disk", 3="bulge", 4="stars", 5="bndry"
*/
double MinGasHsmlFractional; /*!< minimum allowed SPH smoothing length in units of SPH gravitational softening length */
double MinGasHsml; /*!< minimum allowed SPH smoothing length */
double SofteningGas; /*!< comoving gravitational softening lengths for type 0 */
double SofteningHalo; /*!< comoving gravitational softening lengths for type 1 */
double SofteningDisk; /*!< comoving gravitational softening lengths for type 2 */
double SofteningBulge; /*!< comoving gravitational softening lengths for type 3 */
double SofteningStars; /*!< comoving gravitational softening lengths for type 4 */
double SofteningBndry; /*!< comoving gravitational softening lengths for type 5 */
double SofteningGasMaxPhys; /*!< maximum physical softening length for type 0 */
double SofteningHaloMaxPhys; /*!< maximum physical softening length for type 1 */
double SofteningDiskMaxPhys; /*!< maximum physical softening length for type 2 */
double SofteningBulgeMaxPhys; /*!< maximum physical softening length for type 3 */
double SofteningStarsMaxPhys; /*!< maximum physical softening length for type 4 */
double SofteningBndryMaxPhys; /*!< maximum physical softening length for type 5 */
double SofteningTable[6]; /*!< current (comoving) gravitational softening lengths for each particle type */
double ForceSoftening[6]; /*!< the same, but multiplied by a factor 2.8 - at that scale the force is Newtonian */
double MassTable[6]; /*!< Table with particle masses for particle types with equal mass.
If particle masses are all equal for one type, the corresponding entry in MassTable
is set to this value, allowing the size of the snapshot files to be reduced. */
/* some filenames */
char InitCondFile[MAXLEN_FILENAME]; /*!< filename of initial conditions */
char OutputDir[MAXLEN_FILENAME]; /*!< output directory of the code */
char SnapshotFileBase[MAXLEN_FILENAME]; /*!< basename to construct the names of snapshotf files */
char EnergyFile[MAXLEN_FILENAME]; /*!< name of file with energy statistics */
#ifdef SYSTEMSTATISTICS
char SystemFile[MAXLEN_FILENAME];
#endif
char CpuFile[MAXLEN_FILENAME]; /*!< name of file with cpu-time statistics */
char InfoFile[MAXLEN_FILENAME]; /*!< name of log-file with a list of the timesteps taken */
char LogFile[MAXLEN_FILENAME]; /*!< name of log-file with varied info */
#ifdef SFR
char SfrFile[MAXLEN_FILENAME]; /*!< name of file with sfr records */
#endif
#ifdef CHIMIE
char ChimieFile[MAXLEN_FILENAME]; /*!< name of file with chimie records */
#endif
#ifdef MULTIPHASE
char PhaseFile[MAXLEN_FILENAME]; /*!< name of file with phase records */
char StickyFile[MAXLEN_FILENAME]; /*!< name of file with sticky records */
#endif
#ifdef AGN_ACCRETION
char AccretionFile[MAXLEN_FILENAME]; /*!< name of file with accretion records */
#endif
#ifdef BONDI_ACCRETION
char BondiFile[MAXLEN_FILENAME]; /*!< name of file with bondi records */
#endif
#ifdef BUBBLES
char BubbleFile[MAXLEN_FILENAME]; /*!< name of file with bubble records */
#endif
#ifdef GAS_ACCRETION
char GasAccretionFile[MAXLEN_FILENAME]; /*!< name of file with sfr records */
#endif
char TimingsFile[MAXLEN_FILENAME]; /*!< name of file with performance metrics of gravitational tree algorithm */
char RestartFile[MAXLEN_FILENAME]; /*!< basename of restart-files */
char ResubmitCommand[MAXLEN_FILENAME]; /*!< name of script-file that will be executed for automatic restart */
char OutputListFilename[MAXLEN_FILENAME]; /*!< name of file with list of desired output times */
double OutputListTimes[MAXLEN_OUTPUTLIST]; /*!< table with desired output times */
int OutputListLength; /*!< number of output times stored in the table of desired output times */
#ifdef RANDOMSEED_AS_PARAMETER
int RandomSeed; /*!< initial random seed >*/
#endif
#ifdef PERIODICOUTER
char TraceFile[MAXLEN_FILENAME];
double TracePos[3]; //trace particle position
double TraceVel[3]; //trace particle velocity
double TraceAcc[3]; //trace particle acceleration
double TracePeriodPos[3]; //trace particle position in periodic box
FLOAT TraceAngOld[3];
FLOAT TraceTheta;
FLOAT TracePotential;
double TraceAngular[4]; //trace particle Angular velocity
double TraceQuat[4]; //Trace quaternion
double TraceQuatConj[4]; //Easiest to store conjugate here to save repetitive calculation
FLOAT QuatOrig[4]; //Need an arbitrary direction of 0 theta, define it when velocity is -y
int InertialV;
#ifdef TRACE_ACC
#ifndef LONGIDS
unsigned int TraceMinPot[NUMTRACEAVG]; //Get minimum potential particle originally
#else
unsigned long long TraceMinPot[NUMTRACEAVG];
#endif
#endif
#endif
#ifdef HOT_HALO
double HaloT; //Halo Temperature
double HaloPartMass; //Halo particle mass
double HaloScaleFactor; //Halo scale factor (the value at 0)
FLOAT Halocs; //Halo soundspeed
FLOAT HaloLast;
double HaloAccYBound;
#endif
#ifdef MERGE_SPLIT
double Dwarf_Split_Merge_Distance; //Distance to count as hsml for dwarf particles
int SplitThreshold;
int MergeThreshold;
int nZones;
int split_method;
double MinMassForParticleSplit[6];
double MaxMassForParticleMerger[6];
#ifndef LONGIDS
unsigned int MergeID; /*!< particle identifier */
#else
unsigned long long MergeID; /*!< particle identifier */
#endif
#endif
#if defined(CHIMIE) || defined(FOF)
double CMUtoMsol; /*!< convertion factor from Code Mass Unit to Solar Mass >*/
double MsoltoCMU; /*!< convertion factor from Solar Mass to Code Mass Unit >*/
#endif
#ifdef COMPUTE_PHYSICAL_UNITS
double CDUtoAtomPerCC; /*!< convertion factor from Code Density Unit to Atom per CC >*/
#endif
}
All; /*!< a container variable for global variables that are equal on all processors */
/*! This structure holds all the information that is
* stored for each particle of the simulation.
*/
extern struct particle_data
{
FLOAT Pos[3]; /*!< particle position at its current time */
FLOAT Mass; /*!< particle mass */
FLOAT Vel[3]; /*!< particle velocity at its current time */
FLOAT GravAccel[3]; /*!< particle acceleration due to gravity */
#ifdef PMGRID
FLOAT GravPM[3]; /*!< particle acceleration due to long-range PM gravity force*/
#endif
#ifdef FORCETEST
FLOAT GravAccelDirect[3]; /*!< particle acceleration when computed with direct summation */
#endif
FLOAT Potential; /*!< gravitational potential */
FLOAT OldAcc; /*!< magnitude of old gravitational force. Used in relative opening criterion */
#ifndef LONGIDS
unsigned int ID; /*!< particle identifier */
#else
unsigned long long ID; /*!< particle identifier */
#endif
int Type; /*!< flags particle type. 0=gas, 1=halo, 2=disk, 3=bulge, 4=stars, 5=bndry */
int Ti_endstep; /*!< marks start of current timestep of particle on integer timeline */
int Ti_begstep; /*!< marks end of current timestep of particle on integer timeline */
#ifdef SYNCHRONIZE_NGB_TIMESTEP
int Old_Ti_endstep; /*!< marks start of old current timestep of particle on integer timeline */
int Old_Ti_begstep; /*!< marks end of old current timestep of particle on integer timeline */
#endif
#ifdef FLEXSTEPS
int FlexStepGrp; /*!< a random 'offset' on the timeline to create a smooth groouping of particles */
#endif
float GravCost; /*!< weight factor used for balancing the work-load */
#ifdef PSEUDOSYMMETRIC
float AphysOld; /*!< magnitude of acceleration in last timestep. Used to make a first order
prediction of the change of acceleration expected in the future, thereby
allowing to guess whether a decrease/increase of the timestep should occur
in the timestep that is started. */
#endif
#ifdef PARTICLE_FLAG
float Flag;
#endif
#ifdef STELLAR_PROP
unsigned int StPIdx; /*!< index to the corresponding StP particle */
#endif
#ifdef TESSEL
int iT; /*!< index of a triangle to which the point belong to */
int IsDone;
int IsAdded; /*!< if the point has already be added in the tesselation */
int ivPoint; /*!< index of first voronoi point */
int nvPoints; /*!< number of voronoi points */
int iMedian;
int nMedians;
double Volume;
double Density;
double Pressure;
double Entropy;
double rSearch; /*!< radius in which particles must search for ngbs */
int iPref; /*!< for a ghost point, index of the reference point */
FLOAT tesselAccel[3];
#endif
# ifdef SYNCHRONIZE_NGB_TIMESTEP
int Ti_step;
#endif
#ifdef VANISHING_PARTICLES
int VanishingFlag;
#endif
#ifdef FOF_SFR
//int FoFidx; /* no longer used */
#endif
}
*P, /*!< holds particle data on local processor */
#ifdef PY_INTERFACE
*Q,
*DomainPartBufQ, /*!< buffer for particle data used in domain decomposition */
#endif
*DomainPartBuf; /*!< buffer for particle data used in domain decomposition */
/* the following struture holds data that is stored for each SPH particle in addition to the collisionless
* variables.
*/
extern struct sph_particle_data
{
FLOAT Entropy; /*!< current value of entropy (actually entropic function) of particle */
FLOAT Density; /*!< current baryonic mass density of particle */
FLOAT Hsml; /*!< current smoothing length */
FLOAT Left; /*!< lower bound in iterative smoothing length search */
FLOAT Right; /*!< upper bound in iterative smoothing length search */
FLOAT NumNgb; /*!< weighted number of neighbours found */
#ifdef AVOIDNUMNGBPROBLEM
FLOAT OldNumNgb;
#endif
FLOAT Pressure; /*!< current pressure */
FLOAT DtEntropy; /*!< rate of change of entropy */
#ifdef COOLING
//FLOAT EntropyRad; /*!< current value of entropy resulting from the cooling */
FLOAT DtEntropyRad; /*!< rate of change of entropy due to cooling */
FLOAT DtEnergyRad;
#endif
#ifdef STELLAR_FLUX
FLOAT EnergyFlux; /*!< current value of local energy flux - Sph particles */
#endif
#ifdef AGN_HEATING
FLOAT EgySpecAGNHeat; /*!< current value of specific energy radiated of particle - Sph particles */
FLOAT DtEgySpecAGNHeat; /*!< rate of change of specific radiated energy - Sph particles */
FLOAT DtEntropyAGNHeat;
#endif
#ifdef MULTIPHASE
FLOAT StickyTime;
int StickyFlag;
#ifdef COUNT_COLLISIONS
float StickyCollisionNumber;
#endif
#endif
#ifdef FEEDBACK
FLOAT EgySpecFeedback;
FLOAT DtEgySpecFeedback;
FLOAT EnergySN;
FLOAT EnergySNrem;
FLOAT TimeSN;
FLOAT FeedbackVel[3]; /*!< kick due to feedback force */
#endif
#ifdef FEEDBACK_WIND
FLOAT FeedbackWindVel[3]; /*!< kick due to feedback force */
#endif
FLOAT HydroAccel[3]; /*!< acceleration due to hydrodynamical force */
FLOAT VelPred[3]; /*!< predicted SPH particle velocity at the current time */
FLOAT DivVel; /*!< local velocity divergence */
FLOAT CurlVel; /*!< local velocity curl */
FLOAT Rot[3]; /*!< local velocity curl */
FLOAT DhsmlDensityFactor; /*!< correction factor needed in the equation of motion of the conservative entropy formulation of SPH */
FLOAT MaxSignalVel; /*!< maximum "signal velocity" occuring for this particle */
#ifdef MULTIPHASE
int Phase;
int StickyIndex;
int StickyNgb;
int StickyMaxID;
float StickyMaxFs;
FLOAT StickyNewVel[3];
#endif
#ifdef OUTPUTOPTVAR1
FLOAT OptVar1; /*!< optional variable 1 */
#endif
#ifdef OUTPUTOPTVAR2
FLOAT OptVar2; /*!< optional variable 2 */
#endif
#ifdef COMPUTE_VELOCITY_DISPERSION
FLOAT VelocityDispersion[VELOCITY_DISPERSION_SIZE]; /*!< velocity dispersion */
#endif
#ifdef CHIMIE
FLOAT Metal[NELEMENTS];
#ifdef CHIMIE_SMOOTH_METALS
FLOAT MassMetal[NELEMENTS]; /*!< old metal estimation (ratio of masses) */
FLOAT RhoMetal[NELEMENTS]; /*!< metal density of the particle */
#endif
FLOAT dMass; /*!< mass variation due to mass transfere */
#ifdef CHIMIE_THERMAL_FEEDBACK
FLOAT DeltaEgySpec;
FLOAT SNIaThermalTime; /*!< flag particles that got energy from SNIa */
FLOAT SNIIThermalTime; /*!< flag particles that got energy from SNII */
double NumberOfSNIa;
double NumberOfSNII;
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
FLOAT WindTime; /*!< flag particles that belongs to the wind */
unsigned int WindFlag; /*!< flag particles that will be part of the wind */
#endif
#endif /*CHIMIE*/
#ifdef ENTROPYPRED
FLOAT EntropyPred; /*!< predicted entropy at the current time */
#endif
#ifdef ART_CONDUCTIVITY
FLOAT EnergyIntPred;
FLOAT GradEnergyInt[3];
#endif
#ifdef AB_TURB
FLOAT TurbAccel[3];
#endif
#if defined(ART_VISCO_MM)|| defined(ART_VISCO_RO) || defined(ART_VISCO_CD)
double ArtBulkViscConst;
#ifdef ART_VISCO_CD
double DmatCD[3][3];
double TmatCD[3][3];
double DiVelAccurate;
double DiVelTemp;
double ArtBulkViscConstOld;
double R_CD;
FLOAT MaxSignalVelCD;
#endif
#endif
#ifdef GAS_ACCRETION
int ActiveFlag;
#endif
#ifdef DISSIPATION_FORCES
FLOAT EnergyDissipationForces;
FLOAT DtEnergyDissipationForces;
FLOAT DissipationForcesAccel[3];
#endif
#if PY_INTERFACE
FLOAT Observable;
FLOAT ObsMoment0;
FLOAT ObsMoment1;
FLOAT GradObservable[3];
#endif
# ifdef SYNCHRONIZE_NGB_TIMESTEP
int Ti_minNgbStep;
#endif
#if defined(TIMESTEP_UPDATE_FOR_FEEDBACK) && defined(CHIMIE_THERMAL_FEEDBACK)
FLOAT FeedbackUpdatedAccel[3]; /*!< acceleration after feedback injection */
FLOAT MaxSignalVelFeedbackUpdated;
#endif
#ifdef DENSITY_INDEPENDENT_SPH
FLOAT EgyWtDensity; /*!< 'effective' rho to use in hydro equations */
FLOAT EntVarPred; /*!< predicted entropy variable */
FLOAT DhsmlEgyDensityFactor; /*!< correction factor for density-independent entropy formulation */
#endif
#ifdef FOF
int FOF_CPUHead; /*!< cpu ID of the first particle of the chain */
int FOF_CPUTail; /*!< cpu ID of the last particle of the chain */
int FOF_CPUNext; /*!< cpu ID of the next particle of the chain */
int FOF_CPUPrev; /*!< cpu ID of the previous particle of the chain */
int FOF_Head; /*!< first particle of the chain */
int FOF_Tail; /*!< last particle of the chain */
int FOF_Next; /*!< next particle in the chain */
int FOF_Prev; /*!< previous particle in the chain */
- int FOF_gid; /*!< group id */
+ int FOF_gidx; /*!< local index of the group */
+ int FOF_gid; /*!< id of the group, set to the id of the head */
int FOF_Len; /*!< length of the chain */
int FOF_Done; /*!< the particle is done (used for pseudo heads) */
FLOAT FOF_DensMax;
FLOAT FOF_MassMax;
FLOAT FOF_MassMin;
FLOAT FOF_MassSSP;
FLOAT FOF_NStars;
+
+ FLOAT FOFPotential; /*!< potential due to fof group members only */
+
#ifdef CHIMIE_OPTIMAL_SAMPLING
FLOAT OptIMF_k;
FLOAT OptIMF_CurrentMass;
#endif
#endif
#if defined(COMPUTE_VELOCITY_DISP) || defined(METAL_DIFFUSION)
FLOAT RmsSpeed;
#endif
#ifdef METAL_DIFFUSION
FLOAT MetalDiffusionCoeff;
FLOAT MetalDiffusionA;
FLOAT MetalDiffusionB[NELEMENTS];
#endif
}
*SphP, /*!< holds SPH particle data on local processor */
#ifdef PY_INTERFACE
*SphQ,
*DomainSphBufQ, /*!< buffer for SPH particle data in domain decomposition */
#endif
*DomainSphBuf; /*!< buffer for SPH particle data in domain decomposition */
#ifdef FOF
extern struct fof_particles_in
{
FLOAT Mass;
FLOAT MassNew;
FLOAT MassMax;
FLOAT MassMin;
FLOAT MassSSP;
FLOAT k;
FLOAT Pos[3];
+#ifdef FOF_COMPUTE_GROUPS_VIRIAL_LOCALLY
+ FLOAT Vel[3];
+ FLOAT Density;
+ FLOAT EnergySpec;
+ FLOAT Potential;
+#ifdef ADAPTIVE_GRAVSOFT_FORGAS
+ FLOAT Hsml;
+#endif
+#endif
int NStars;
int ID;
int Index;
int Task;
}
*FoF_P,*FoF_P_local;
extern struct fof_groups_data
{
int Index; /*!< group index (used when the group is send) */
int Head; /*!< head index */
int HeadID; /*!< head id, -1 if the head is not local */
int LocalHead; /*!< index to local head */
int Task; /*!< task hosting the true head */
int N; /*!< number of members */
int Nlocal; /*!< number of local members */
float Mass; /*!< total mass */
float MassCenter[3]; /*!< mass center */
float DensityMax; /*!< density max */
float DensityMin; /*!< density min */
float PotentialMax; /*!< potential max */
float VirialFraction; /*!< virial fraction 2(T+U)/W */
float MV[3];
float MV2[3];
float RadiusMax;
float K;
float W;
float U;
float T;
float Density;
float HeadPos[3];
- float HeadPotential;
int SfrFlag;
}
*Groups,*GroupsGet,*GroupsRecv;
extern int *Tot_HeadID_list;
extern int Tot_Ngroups;
extern int Tot_Ntgroups;
extern int Tot_Npgroups;
extern int Tot_Ntsfrgroups;
extern int Ngroups; /* true and pseudo groups */
extern int Ntgroups; /* true groups */
extern int Npgroups; /* pseudo groups */
extern int Ntsfrgroups; /* true groups that forms stars */
extern int Nsfrgroups; /* local number of groups flagged for sfr */
extern int Tot_Nsfrgroups; /* total number of groups flagged for sfr */
#endif
#ifdef GAS_ACCRETION
extern struct acc_particle_data
{
FLOAT Pos[3];
FLOAT Vel[3];
FLOAT Mass;
FLOAT Time;
int Type;
int ID;
}
*Acc;
extern struct gas_acc_particle_data
{
FLOAT Entropy;
#ifdef CHIMIE
FLOAT Metal[NELEMENTS];
#endif
}
*SphAcc;
#endif
#ifdef HOT_HALO
extern struct haloacc_pos_data
{
FLOAT Pos[3];
FLOAT Vel[3];
FLOAT Mass;
FLOAT Time;
int Type;
int ID;
}
*HaloAcc;
#endif
#ifdef TRACE_ACC
extern struct pot_index
{
FLOAT Potential;
#ifndef LONGIDS
unsigned int ID;
#else
unsigned long long ID;
#endif
int index;
}
*PotInd;
#endif
#ifdef STELLAR_PROP
/* the following struture holds data that is stored for each SPH particle in addition to the collisionless
* variables.
*/
extern struct st_particle_data
{
#ifdef CHECK_ID_CORRESPONDENCE
unsigned int ID; /*!< particle identifier (must be the same as P[].ID) only used to check ID correspondance */
#endif
FLOAT FormationTime; /*!< star formation time of particle */
FLOAT InitialMass; /*!< initial stellar mass */
#ifndef LONGIDS
unsigned int IDProj; /*!< id of projenitor particle */
#else
unsigned long long IDProj; /*!< id of projenitor particle */
#endif
FLOAT Metal[NELEMENTS];
FLOAT Density; /*!< current baryonic mass density of particle */
FLOAT Y; /*!< elements weighting normalisation */
FLOAT Hsml; /*!< current smoothing length */
FLOAT Left; /*!< lower bound in iterative smoothing length search */
FLOAT Right; /*!< upper bound in iterative smoothing length search */
FLOAT NumNgb; /*!< weighted number of neighbours found */
unsigned int PIdx; /*!< index to the corresponding particle */
#ifdef AVOIDNUMNGBPROBLEM
FLOAT OldNumNgb;
#endif
FLOAT DhsmlDensityFactor; /*!< correction factor needed in the equation of motion of the conservative entropy formulation of SPH */
double TotalEjectedGasMass;
double TotalEjectedEltMass[NELEMENTS];
double TotalEjectedEgySpec;
double NumberOfSNIa;
double NumberOfSNII;
#ifdef CHIMIE_KINETIC_FEEDBACK
double NgbMass; /*!< mass of neighbours */
#endif
#ifdef CHIMIE
unsigned int Flag;
#endif
#ifdef CHIMIE_OPTIMAL_SAMPLING
float OptIMF_CurrentMass;
int OptIMF_N_WD;
float OptIMF_k; /*!< kroupa normalization */
float OptIMF_m_max; /*!< max mass of star in the "cluster">*/
#endif
#ifdef FOF_SFR
FLOAT MassMax; /*!< maximal stellar mass contained by the particle */
FLOAT MassMin; /*!< minimal stellar mass contained by the particle */
FLOAT MassSSP; /*!< mass of the total SSP */
int NStars; /*!< number of stars contained by the particle. If =-1, the particle represents a portion of the IMF */
#endif
#if CHIMIE_EJECTA_RADIUS == 2
FLOAT Pressure;
#endif
}
*StP, /*!< holds ST particle data on local processor */
*DomainStBuf; /*!< buffer for ST particle data in domain decomposition */
#endif
/* Variables for Tree
*/
extern int MaxNodes; /*!< maximum allowed number of internal nodes */
extern int Numnodestree; /*!< number of (internal) nodes in each tree */
extern struct NODE
{
FLOAT len; /*!< sidelength of treenode */
FLOAT center[3]; /*!< geometrical center of node */
#ifdef ADAPTIVE_GRAVSOFT_FORGAS
FLOAT maxsoft; /*!< hold the maximum gravitational softening of particles in the
node if the ADAPTIVE_GRAVSOFT_FORGAS option is selected */
#endif
#ifdef STELLAR_FLUX
FLOAT starlum ; /*!< star luminosity of node */
#endif
union
{
int suns[8]; /*!< temporary pointers to daughter nodes */
struct
{
FLOAT s[3]; /*!< center of mass of node */
FLOAT mass; /*!< mass of node */
int bitflags; /*!< a bit-field with various information on the node */
int sibling; /*!< this gives the next node in the walk in case the current node can be used */
int nextnode; /*!< this gives the next node in case the current node needs to be opened */
int father; /*!< this gives the parent node of each node (or -1 if we have the root node) */
}
d;
}
u;
}
*Nodes_base, /*!< points to the actual memory allocted for the nodes */
*Nodes; /*!< this is a pointer used to access the nodes which is shifted such that Nodes[All.MaxPart]
gives the first allocated node */
extern int *Nextnode; /*!< gives next node in tree walk */
extern int *Father; /*!< gives parent node in tree */
extern struct extNODE /*!< this structure holds additional tree-node information which is not needed in the actual gravity computation */
{
FLOAT hmax; /*!< maximum SPH smoothing length in node. Only used for gas particles */
FLOAT vs[3]; /*!< center-of-mass velocity */
}
*Extnodes_base, /*!< points to the actual memory allocted for the extended node information */
*Extnodes; /*!< provides shifted access to extended node information, parallel to Nodes/Nodes_base */
/*! Header for the standard file format.
*/
extern struct io_header
{
int npart[6]; /*!< number of particles of each type in this file */
double mass[6]; /*!< mass of particles of each type. If 0, then the masses are explicitly
stored in the mass-block of the snapshot file, otherwise they are omitted */
double time; /*!< time of snapshot file */
double redshift; /*!< redshift of snapshot file */
int flag_sfr; /*!< flags whether the simulation was including star formation */
int flag_feedback; /*!< flags whether feedback was included (obsolete) */
unsigned int npartTotal[6]; /*!< total number of particles of each type in this snapshot. This can be
different from npart if one is dealing with a multi-file snapshot. */
int flag_cooling; /*!< flags whether cooling was included */
int num_files; /*!< number of files in multi-file snapshot */
double BoxSize; /*!< box-size of simulation in case periodic boundaries were used */
double Omega0; /*!< matter density in units of critical density */
double OmegaLambda; /*!< cosmological constant parameter */
double HubbleParam; /*!< Hubble parameter in units of 100 km/sec/Mpc */
int flag_stellarage; /*!< flags whether the file contains formation times of star particles */
int flag_metals; /*!< flags whether the file contains metallicity values for gas and star particles */
unsigned int npartTotalHighWord[6]; /*!< High word of the total number of particles of each type */
int flag_entropy_instead_u; /*!< flags that IC-file contains entropy instead of u */
int flag_chimie_extraheader; /*!< flags that IC-file contains extra-header for chimie */
int flag_supernova_thermaltime; /*!< flags that IC-file contains supernova thermal time */
#ifdef MULTIPHASE
double critical_energy_spec;
#ifdef MESOMACHINE
char fill[34];
#else
char fill[44]; /* use 42 with regor... */
#endif
#else
char fill[52]; /*!< fills to 256 Bytes */
#endif
}
header; /*!< holds header for snapshot files */
#ifdef CHIMIE_EXTRAHEADER
/*! Header for the chimie part.
*/
extern struct io_chimie_extraheader
{
int nelts; /*!< number of chemical element followed */
float SolarMassAbundances[NELEMENTS];
char labels[256-4-4*(NELEMENTS)];
}
chimie_extraheader;
#endif
#define IO_NBLOCKS 26 /*!< total number of defined information blocks for snapshot files.
Must be equal to the number of entries in "enum iofields" */
enum iofields /*!< this enumeration lists the defined output blocks in snapshot files. Not all of them need to be present. */
{
IO_POS,
IO_VEL,
IO_ID,
IO_MASS,
IO_U,
IO_RHO,
IO_HSML,
IO_POT,
IO_ACCEL,
IO_DTENTR,
IO_TSTP,
IO_ERADSPH,
IO_ERADSTICKY,
IO_ERADFEEDBACK,
IO_ENERGYFLUX,
IO_METALS,
IO_SNII_THERMALTIME,
IO_SNIA_THERMALTIME,
IO_STAR_FORMATIONTIME,
IO_STAR_INITIAL_MASS,
IO_STAR_IDPROJ,
IO_STAR_RHO,
IO_STAR_HSML,
IO_STAR_METALS,
IO_OPTVAR1,
IO_OPTVAR2
};
extern char Tab_IO_Labels[IO_NBLOCKS][4]; /*<! This table holds four-byte character tags used for fileformat 2 */
/* global state of system, used for global statistics
*/
extern struct state_of_system
{
double Mass;
double EnergyKin;
double EnergyPot;
double EnergyInt;
#ifdef COOLING
double EnergyRadSph;
#endif
#ifdef AGN_HEATING
double EnergyAGNHeat;
#endif
#ifdef DISSIPATION_FORCES
double EnergyDissipationForces;
#endif
#ifdef MULTIPHASE
double EnergyRadSticky;
#endif
#ifdef FEEDBACK_WIND
double EnergyFeedbackWind;
#endif
#ifdef BUBBLES
double EnergyBubbles;
#endif
#ifdef CHIMIE_THERMAL_FEEDBACK
double EnergyThermalFeedback;
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
double EnergyKineticFeedback;
#endif
#ifdef INTEGRAL_CONSERVING_DISSIPATION
double EnergyICDissipation;
#endif
double EnergyTot;
double Momentum[4];
double AngMomentum[4];
double CenterOfMass[4];
double MassComp[6];
double EnergyKinComp[6];
double EnergyPotComp[6];
double EnergyIntComp[6];
#ifdef COOLING
double EnergyRadSphComp[6];
#endif
#ifdef AGN_HEATING
double EnergyAGNHeatComp[6];
#endif
#ifdef MULTIPHASE
double EnergyRadStickyComp[6];
#endif
#ifdef FEEDBACK_WIND
double EnergyFeedbackWindComp[6];
#endif
#ifdef BUBBLES
double EnergyBubblesComp[6];
#endif
#ifdef CHIMIE_THERMAL_FEEDBACK
double EnergyThermalFeedbackComp[6];
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
double EnergyKineticFeedbackComp[6];
#endif
double EnergyTotComp[6];
double MomentumComp[6][4];
double AngMomentumComp[6][4];
double CenterOfMassComp[6][4];
#ifdef DISSIPATION_FORCES
double EnergyDissipationForcesComp[6];
#endif
#ifdef INTEGRAL_CONSERVING_DISSIPATION
double EnergyICDissipationComp[6];
#endif
}
SysState; /*<! Structure for storing some global statistics about the simulation. */
/*! This structure contains data related to the energy budget.
These values are different for each task. It need to be stored
in the restart flag.
*/
extern struct local_state_of_system
{
double EnergyTest;
double EnergyInt1;
double EnergyInt2;
double EnergyKin1;
double EnergyKin2;
#ifdef COOLING
double RadiatedEnergy;
#endif
#ifdef SFR
double StarEnergyInt;
#ifdef FEEDBACK
double StarEnergyFeedback;
#endif
#endif
#ifdef CHIMIE_THERMAL_FEEDBACK
double EnergyThermalFeedback;
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
double EnergyKineticFeedback;
#endif
#ifdef MULTIPHASE
double EnergyRadSticky;
#endif
#ifdef FEEDBACK_WIND
double EnergyFeedbackWind;
#endif
#ifdef INTEGRAL_CONSERVING_DISSIPATION
double EnergyICDissipation;
#endif
}
LocalSysState; /*<! Structure for storing some local statistics about the simulation. */
/* Various structures for communication
*/
extern struct gravdata_in
{
union
{
FLOAT Pos[3];
FLOAT Acc[3];
FLOAT Potential;
}
u;
#if defined(UNEQUALSOFTENINGS) || defined(STELLAR_FLUX)
int Type;
#ifdef ADAPTIVE_GRAVSOFT_FORGAS
FLOAT Soft;
#endif
#endif
#ifdef STELLAR_FLUX
FLOAT EnergyFlux;
#endif
union
{
FLOAT OldAcc;
int Ninteractions;
}
w;
}
*GravDataIn, /*!< holds particle data to be exported to other processors */
*GravDataGet, /*!< holds particle data imported from other processors */
*GravDataResult, /*!< holds the partial results computed for imported particles. Note: We use GravDataResult = GravDataGet, such that the result replaces the imported data */
*GravDataOut; /*!< holds partial results received from other processors. This will overwrite the GravDataIn array */
extern struct gravdata_index
{
int Task;
int Index;
int SortIndex;
}
*GravDataIndexTable; /*!< the particles to be exported are grouped by task-number. This table allows the results to be disentangled again and to be assigned to the correct particle */
extern struct densdata_in
{
FLOAT Pos[3];
FLOAT Vel[3];
FLOAT Hsml;
#ifdef MULTIPHASE
int Phase;
#endif
int Index;
int Task;
#ifdef ART_CONDUCTIVITY
FLOAT EnergyIntPred;
#endif
#ifdef WITH_ID_IN_DENSITY
int ID;
#endif
}
*DensDataIn, /*!< holds particle data for SPH density computation to be exported to other processors */
*DensDataGet; /*!< holds imported particle data for SPH density computation */
extern struct densdata_out
{
FLOAT Rho;
FLOAT Div, Rot[3];
FLOAT DhsmlDensity;
FLOAT Ngb;
#ifdef ART_CONDUCTIVITY
FLOAT GradEnergyInt[3];
#endif
#ifdef DENSITY_INDEPENDENT_SPH
FLOAT EgyRho;
FLOAT DhsmlEgyDensity;
#endif
#ifdef CHIMIE_SMOOTH_METALS
FLOAT RhoMetal[NELEMENTS];
#endif
#if defined(COMPUTE_VELOCITY_DISP) || defined(METAL_DIFFUSION)
FLOAT RmsSpeed;
#endif
}
*DensDataResult, /*!< stores the locally computed SPH density results for imported particles */
*DensDataPartialResult; /*!< imported partial SPH density results from other processors */
extern struct hydrodata_in
{
FLOAT Pos[3];
FLOAT Vel[3];
FLOAT Hsml;
#ifdef FEEDBACK
FLOAT EnergySN;
#endif
#ifdef MULTIPHASE
int Phase;
FLOAT Entropy;
int StickyFlag;
#endif
FLOAT Mass;
FLOAT Density;
FLOAT Pressure;
FLOAT F1;
FLOAT DhsmlDensityFactor;
int Timestep;
int Task;
int Index;
#ifdef WITH_ID_IN_HYDRA
int ID;
#endif
#ifdef ART_CONDUCTIVITY
FLOAT NormGradEnergyInt;
#endif
#if defined(ART_VISCO_MM)|| defined(ART_VISCO_RO) || defined(ART_VISCO_CD)
double ArtBulkViscConst;
#endif
#ifdef DENSITY_INDEPENDENT_SPH
FLOAT EgyRho;
FLOAT EntVarPred;
#endif
#if defined(TIMESTEP_UPDATE_FOR_FEEDBACK) && defined(CHIMIE_THERMAL_FEEDBACK)
FLOAT PressureFeedbackUpdated;
FLOAT F1FeedbackUpdated;
#endif
#ifdef METAL_DIFFUSION
FLOAT MetalDiffusionCoeff;
#endif
}
*HydroDataIn, /*!< holds particle data for SPH hydro-force computation to be exported to other processors */
*HydroDataGet; /*!< holds imported particle data for SPH hydro-force computation */
extern struct hydrodata_out
{
FLOAT Acc[3];
FLOAT DtEntropy;
#ifdef FEEDBACK
FLOAT DtEgySpecFeedback;
FLOAT FeedbackAccel[3]; /*!< acceleration due to feedback force */
#endif
FLOAT MaxSignalVel;
#ifdef COMPUTE_VELOCITY_DISPERSION
FLOAT VelocityDispersion[VELOCITY_DISPERSION_SIZE];
#endif
#ifdef MULTIPHASE
FLOAT StickyDVel[3]; /*!< differences in velocities induced by sticky collisions */
#endif
#ifdef OUTPUT_CONDUCTIVITY
FLOAT OptVar2;
#endif
#ifdef ART_VISCO_CD
double DmatCD[3][3];
double TmatCD[3][3];
double R_CD;
FLOAT MaxSignalVelCD;
#endif
#if defined(TIMESTEP_UPDATE_FOR_FEEDBACK) && defined(CHIMIE_THERMAL_FEEDBACK)
FLOAT AccFeedbackUpdated[3];
FLOAT maxSignalVelFeedbackUpdated;
#endif
#ifdef METAL_DIFFUSION
FLOAT MetalDiffusionA;
FLOAT MetalDiffusionB[NELEMENTS];
#endif
}
*HydroDataResult, /*!< stores the locally computed SPH hydro results for imported particles */
*HydroDataPartialResult; /*!< imported partial SPH hydro-force results from other processors */
#ifdef MULTIPHASE
extern struct stickydata_in
{
FLOAT Pos[3];
FLOAT Vel[3];
FLOAT Mass;
FLOAT Hsml;
int ID;
int StickyMaxID;
int StickyNgb;
float StickyMaxFs;
int Task;
int Index;
}
*StickyDataIn, /*!< holds particle data for sticky computation to be exported to other processors */
*StickyDataGet; /*!< holds imported particle data for sticky computation */
extern struct stickydata_out
{
int StickyMaxID;
int StickyNgb;
float StickyMaxFs;
FLOAT StickyNewVel[3];
}
*StickyDataResult, /*!< stores the locally computed sticky results for imported particles */
*StickyDataPartialResult; /*!< imported partial sticky results from other processors */
extern struct Sticky_index
{
int Index;
int CellIndex;
int Flag;
}
*StickyIndex;
#endif
#ifdef CHIMIE
extern struct chimiedata_in
{
FLOAT Pos[3];
FLOAT Vel[3];
#ifndef LONGIDS
unsigned int ID; /*!< particle identifier */
#else
unsigned long long ID; /*!< particle identifier */
#endif
FLOAT Hsml;
#ifdef FEEDBACK
FLOAT EnergySN;
#endif
#ifdef MULTIPHASE
int Phase;
FLOAT Entropy;
int StickyFlag;
#endif
FLOAT Density;
FLOAT Y;
FLOAT Pressure;
FLOAT F1;
FLOAT DhsmlDensityFactor;
int Timestep;
int Task;
int Index;
double TotalEjectedGasMass;
double TotalEjectedEltMass[NELEMENTS];
double TotalEjectedEgySpec;
double NumberOfSNIa;
double NumberOfSNII;
#ifdef CHIMIE_KINETIC_FEEDBACK
FLOAT NgbMass;
#endif
}
*ChimieDataIn, /*!< holds particle data for Chimie computation to be exported to other processors */
*ChimieDataGet; /*!< holds imported particle data for Chimie computation */
extern struct chimiedata_out
{
FLOAT Acc[3];
FLOAT DtEntropy;
#ifdef FEEDBACK
FLOAT DtEgySpecFeedback;
FLOAT FeedbackAccel[3]; /*!< acceleration due to feedback force */
#endif
FLOAT MaxSignalVel;
#ifdef COMPUTE_VELOCITY_DISPERSION
FLOAT VelocityDispersion[VELOCITY_DISPERSION_SIZE];
#endif
#ifdef MULTIPHASE
FLOAT StickyDVel[3]; /*!< differences in velocities induced by sticky collisions */
#endif
}
*ChimieDataResult, /*!< stores the locally computed Chimie results for imported particles */
*ChimieDataPartialResult; /*!< imported partial Chimie results from other processors */
extern struct starsdensdata_in
{
FLOAT Pos[3];
FLOAT Hsml;
int Index;
int Task;
}
*StarsDensDataIn, /*!< holds particle data for SPH density computation to be exported to other processors */
*StarsDensDataGet; /*!< holds imported particle data for SPH density computation */
extern struct starsdensdata_out
{
FLOAT Rho;
FLOAT Y;
FLOAT DhsmlDensity;
FLOAT Ngb;
#ifdef CHIMIE_KINETIC_FEEDBACK
FLOAT NgbMass;
#endif
#if CHIMIE_EJECTA_RADIUS == 2
FLOAT Pressure;
#endif
}
*StarsDensDataResult, /*!< stores the locally computed SPH density results for imported particles */
*StarsDensDataPartialResult; /*!< imported partial SPH density results from other processors */
#endif /*CHIMIE*/
#ifdef DISSIPATION_FORCES
extern struct dissipationforcesdata_in
{
FLOAT Pos[3];
FLOAT Vel[3];
FLOAT Hsml;
FLOAT Mass;
FLOAT Density;
int Task;
int Index;
}
*DissipationForcesDataIn, /*!< holds particle data for SPH hydro-force computation to be exported to other processors */
*DissipationForcesDataGet; /*!< holds imported particle data for SPH hydro-force computation */
extern struct dissipationforcesdata_out
{
FLOAT Acc[3];
FLOAT DtEnergy;
}
*DissipationForcesDataResult, /*!< stores the locally computed SPH hydro results for imported particles */
*DissipationForcesDataPartialResult; /*!< imported partial SPH hydro-force results from other processors */
#endif /* DISSIPATION_FORCES */
#ifdef FOF
extern struct FOFdata_in
{
FLOAT Pos[3];
FLOAT Hsml;
FLOAT Density;
int ID;
int FOF_Head;
int FOF_Tail;
int FOF_Prev;
int FOF_Next;
int FOF_CPUHead; /*!< index of the particle in its local proc */
int FOF_CPUPrev; /*!< index of the particle in its local proc */
int FOF_idx;
FLOAT FOF_DensMax;
int Task;
int Index;
}
*FOFDataIn, /*!< holds particle data for SPH hydro-force computation to be exported to other processors */
*FOFDataGet; /*!< holds imported particle data for SPH hydro-force computation */
extern struct FOFdata_out
{
int FOF_Head;
int FOF_Prev;
FLOAT FOF_DensMax;
int FOF_CPUHead;
int FOF_CPUPrev;
int FOF_Done;
}
*FOFDataResult, /*!< stores the locally computed SPH hydro results for imported particles */
*FOFDataPartialResult; /*!< imported partial SPH hydro-force results from other processors */
+
+
+extern struct FOFgravdata_in
+{
+ union
+ {
+ FLOAT Pos[3];
+ FLOAT Acc[3];
+ FLOAT FOFPotential;
+ }
+ u;
+#if defined(UNEQUALSOFTENINGS) || defined(STELLAR_FLUX)
+ int Type;
+#ifdef ADAPTIVE_GRAVSOFT_FORGAS
+ FLOAT Soft;
+#endif
+#endif
+ int FOF_gidx;
+ int FOF_gid;
+ union
+ {
+ FLOAT OldAcc;
+ int Ninteractions;
+ }
+ w;
+}
+ *FOFGravDataIn, /*!< holds particle data to be exported to other processors */
+ *FOFGravDataGet, /*!< holds particle data imported from other processors */
+ *FOFGravDataResult, /*!< holds the partial results computed for imported particles. Note: We use GravDataResult = GravDataGet, such that the result replaces the imported data */
+ *FOFGravDataOut; /*!< holds partial results received from other processors. This will overwrite the GravDataIn array */
+
+
+extern struct FOFgravdata_index
+{
+ int Task;
+ int Index;
+ int SortIndex;
+}
+ *FOFGravDataIndexTable; /*!< the particles to be exported are grouped by task-number. This table allows the results to be disentangled again and to be assigned to the correct particle */
+
+
#endif /* FOF */
#ifdef TESSEL
extern struct ghostdata_in
{
FLOAT Pos[3];
FLOAT rSearch;
int Index;
int Task;
}
*GhostDataIn, /*!< holds particle data for SPH density computation to be exported to other processors */
*GhostDataGet; /*!< holds imported particle data for SPH density computation */
extern struct ghostdata_out
{
FLOAT Value;
}
*GhostDataResult, /*!< stores the locally computed SPH density results for imported particles */
*GhostDataPartialResult; /*!< imported partial SPH density results from other processors */
/* ghost particles */
//extern struct ghost_particle_data
//{
// FLOAT Pos[3]; /*!< particle position at its current time */
// FLOAT Mass; /*!< particle mass */
//}
// *gP;
extern int NumgPart;
#endif /* TESSEL */
#ifdef SYNCHRONIZE_NGB_TIMESTEP
extern struct SynchroinzeNgbTimestepdata_in
{
FLOAT Pos[3];
FLOAT Hsml;
int Ti_step;
int Ti_endstep;
int Index;
int Task;
#ifdef MULTIPHASE
int Phase;
#endif
}
*SynchroinzeNgbTimestepDataIn,
*SynchroinzeNgbTimestepDataGet;
#endif
#ifdef PY_INTERFACE
extern struct denssphdata_in
{
FLOAT Pos[3];
FLOAT Vel[3];
FLOAT Hsml;
FLOAT Density;
FLOAT DhsmlDensityFactor;
int Index;
int Task;
FLOAT Observable;
}
*DensSphDataIn, /*!< holds particle data for SPH density computation to be exported to other processors */
*DensSphDataGet; /*!< holds imported particle data for SPH density computation */
extern struct denssphdata_out
{
FLOAT Rho;
FLOAT Div, Rot[3];
FLOAT DhsmlDensity;
FLOAT Ngb;
FLOAT GradObservable[3];
}
*DensSphDataResult, /*!< stores the locally computed SPH density results for imported particles */
*DensSphDataPartialResult; /*!< imported partial SPH density results from other processors */
extern struct sphdata_in
{
FLOAT Pos[3];
FLOAT Vel[3];
FLOAT Hsml;
FLOAT Density;
FLOAT DhsmlDensityFactor;
FLOAT ObsMoment0;
FLOAT ObsMoment1;
FLOAT Observable;
int Task;
int Index;
}
*SphDataIn, /*!< holds particle data for SPH hydro-force computation to be exported to other processors */
*SphDataGet; /*!< holds imported particle data for SPH hydro-force computation */
extern struct sphdata_out
{
FLOAT ObsMoment0;
FLOAT ObsMoment1;
FLOAT GradObservable[3];
}
*SphDataResult, /*!< stores the locally computed SPH hydro results for imported particles */
*SphDataPartialResult; /*!< imported partial SPH hydro-force results from other processors */
#endif /*PY_INTERFACE*/
#endif
diff --git a/src/begrun.c b/src/begrun.c
index ef92f88..eb234ed 100644
--- a/src/begrun.c
+++ b/src/begrun.c
@@ -1,2701 +1,2735 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <mpi.h>
#include <sys/types.h>
#include <unistd.h>
#include <gsl/gsl_rng.h>
#include "allvars.h"
#include "proto.h"
/*! \file begrun.c
* \brief initial set-up of a simulation run
*
* This file contains various functions to initialize a simulation run. In
* particular, the parameterfile is read in and parsed, the initial
* conditions or restart files are read, and global variables are
* initialized to their proper values.
*/
/*! This function performs the initial set-up of the simulation. First, the
* parameterfile is set, then routines for setting units, reading
* ICs/restart-files are called, auxialiary memory is allocated, etc.
*/
void begrun(void)
{
struct global_data_all_processes all;
#ifdef DETAILED_CPU
double tstart,tend;
tstart = second();
#endif
if(ThisTask == 0)
{
printf("\nThis is Gadget, version `%s'.\n", GADGETVERSION);
printf("\nRunning on %d processors.\n", NTask);
}
read_parameter_file(ParameterFile); /* ... read in parameters for this run */
allocate_commbuffers(); /* ... allocate buffer-memory for particle
exchange during force computation */
set_units();
#if defined(PERIODIC) && (!defined(PMGRID) || defined(FORCETEST))
ewald_init();
#endif
open_outputfiles();
random_generator = gsl_rng_alloc(gsl_rng_ranlxd1);
#ifdef RANDOMSEED_AS_PARAMETER
if(ThisTask == 0)
printf("Using %d as initial random seed\n",All.RandomSeed);
gsl_rng_set(random_generator, All.RandomSeed); /* start-up seed */
#else
if(ThisTask == 0)
printf("Using %d as initial random seed\n",42);
gsl_rng_set(random_generator, 42); /* start-up seed */
#endif
#ifdef PMGRID
long_range_init();
#endif
All.TimeLastRestartFile = CPUThisRun;
#ifdef MULTIPHASE
All.StickyLastCollisionTime = All.TimeBegin;
#endif
#ifdef COSMICTIME
if(All.ComovingIntegrationOn)
{
if (ThisTask==0)
printf("Initialize cosmic table\n");
init_cosmictime_table();
if (ThisTask==0)
printf("Initialize cosmic table done.\n");
}
if (ThisTask==0)
printf("Initialize full cosmic table\n");
init_full_cosmictime_table();
if (ThisTask==0)
printf("Initialize full cosmic table done.\n");
#endif
/* other physics initialization */
#ifdef COOLING
if (All.CoolingType==0) /* sutherland */
{
if(ThisTask == 0) printf("Initialize cooling function...\n");
init_cooling(0);
if(ThisTask == 0) printf("Initialize cooling function done.\n");
}
if (All.CoolingType==2) /* cooling with metals */
{
if(ThisTask == 0) printf("Initialize cooling function...\n");
#ifdef COOLING_WIERSMA
//InitWiersmaCooling("/home/epfl/revaz/code/gear/PyCool/tables_wiersma/coolingtables/");
InitWiersmaCooling(All.CoolingDirectory);
//SetRedshiftInterpolationOff();
#else
#ifdef COOLING_GRACKLE
init_cooling_GRACKLE();
#else
init_cooling_with_metals();
#endif
#endif
if(ThisTask == 0) printf("Initialize cooling function done.\n");
}
#endif
#ifdef CHIMIE
int i;
if(ThisTask == 0) printf("Initialize chimie...\n");
init_chimie();
check_chimie();
if(ThisTask == 0)
{
for (i=0;i<get_nelts();i++)
printf("solar mass abundance %s\t= %g\n",get_Element(i),get_SolarMassAbundance(i));
}
if(ThisTask == 0) printf("Initialize chimie done...\n");
#endif
#ifdef COOLING
#ifdef CHIMIE
All.CoolingParameters_FeHSolar = get_SolarMassAbundance(FE); /* for consitency, use the value defined in chimie file */
#else
All.CoolingParameters_FeHSolar = FEH_SOLAR; /* use a default value */
#endif
#endif
#ifdef AB_TURB
init_turb();
#endif
#ifdef ART_VISCO_CD
art_visc_allocate();
#endif
#ifdef CHIMIE_ONE_SN_ONLY
All.ChimieOneSN=0;
#endif
#ifdef HOT_HALO
All.Halocs = BOLTZMANN*All.HaloT/(16./26.*PROTONMASS)/(All.UnitVelocity_in_cm_per_s*All.UnitVelocity_in_cm_per_s);
All.HaloPartMass *= SOLAR_MASS/All.UnitMass_in_g;
All.HaloLast = All.TimeBegin;
All.HaloAccYBound = 0;
#endif
if(RestartFlag == 0 || RestartFlag == 2)
{
set_random_numbers();
init(); /* ... read in initial model */
init_local_sys_state();
}
else
{
all = All; /* save global variables. (will be read from restart file) */
restart(RestartFlag); /* ... read restart file. Note: This also resets
all variables in the struct `All'.
However, during the run, some variables in the parameter
file are allowed to be changed, if desired. These need to
copied in the way below.
Note: All.PartAllocFactor is treated in restart() separately.
*/
/* yr
if we want a parameter to be taken as the one written in the parameter file,
we have to save it below,
instead, the value of the restart file will be taken.
This is usefull, for example, if stop a run and want it to be restarted with
different parameters.
*/
All.MinSizeTimestep = all.MinSizeTimestep;
All.MaxSizeTimestep = all.MaxSizeTimestep;
All.BufferSize = all.BufferSize;
All.BunchSizeForce = all.BunchSizeForce;
All.BunchSizeDensity = all.BunchSizeDensity;
All.BunchSizeHydro = all.BunchSizeHydro;
All.BunchSizeDomain = all.BunchSizeDomain;
#ifdef MULTIPHASE
All.BunchSizeSticky = all.BunchSizeSticky;
#endif
#ifdef CHIMIE
All.BunchSizeChimie = all.BunchSizeChimie;
#endif
+#ifdef FOF
+ All.BunchSizeFOF = all.BunchSizeFOF;
+ All.BunchSizeForceFOF = all.BunchSizeForceFOF;
+#endif
+
All.TimeLimitCPU = all.TimeLimitCPU;
All.ResubmitOn = all.ResubmitOn;
All.TimeBetSnapshot = all.TimeBetSnapshot;
All.TimeBetStatistics = all.TimeBetStatistics;
All.CpuTimeBetRestartFile = all.CpuTimeBetRestartFile;
All.ErrTolIntAccuracy = all.ErrTolIntAccuracy;
All.MaxRMSDisplacementFac = all.MaxRMSDisplacementFac;
All.ErrTolForceAcc = all.ErrTolForceAcc;
All.TypeOfTimestepCriterion = all.TypeOfTimestepCriterion;
All.TypeOfOpeningCriterion = all.TypeOfOpeningCriterion;
All.NumFilesWrittenInParallel = all.NumFilesWrittenInParallel;
All.TreeDomainUpdateFrequency = all.TreeDomainUpdateFrequency;
All.SnapFormat = all.SnapFormat;
All.NumFilesPerSnapshot = all.NumFilesPerSnapshot;
All.MaxNumNgbDeviation = all.MaxNumNgbDeviation;
All.ArtBulkViscConst = all.ArtBulkViscConst;
#ifdef ART_CONDUCTIVITY
All.ArtCondConst = all.ArtCondConst;
All.ArtCondThreshold = all.ArtCondThreshold;
#endif
All.OutputListOn = all.OutputListOn;
All.CourantFac = all.CourantFac;
All.OutputListLength = all.OutputListLength;
memcpy(All.OutputListTimes, all.OutputListTimes, sizeof(double) * All.OutputListLength);
#ifdef RANDOMSEED_AS_PARAMETER
All.RandomSeed = all.RandomSeed;
#endif
#ifdef MULTIPHASE
All.CriticalTemperature = all.CriticalTemperature;
All.CriticalNonCollisionalTemperature = all.CriticalNonCollisionalTemperature;
All.StickyUseGridForCollisions = all.StickyUseGridForCollisions;
All.StickyTime = all.StickyTime;
All.StickyCollisionTime = all.StickyCollisionTime;
All.StickyIdleTime = all.StickyIdleTime;
All.StickyMinVelocity = all.StickyMinVelocity;
All.StickyMaxVelocity = all.StickyMaxVelocity;
All.StickyLambda = all.StickyLambda;
All.StickyDensity = all.StickyDensity;
All.StickyDensityPower = all.StickyDensityPower;
All.StickyRsphFact = all.StickyRsphFact;
All.StickyBetaR = all.StickyBetaR;
All.StickyBetaT = all.StickyBetaT;
All.StickyGridNx = all.StickyGridNx;
All.StickyGridNy = all.StickyGridNy;
All.StickyGridNz = all.StickyGridNz;
All.StickyGridXmin = all.StickyGridXmin;
All.StickyGridXmax = all.StickyGridXmax;
All.StickyGridYmin = all.StickyGridYmin;
All.StickyGridYmax = all.StickyGridYmax;
All.StickyGridZmin = all.StickyGridZmin;
All.StickyGridZmax = all.StickyGridZmax;
#ifdef COLDGAS_CYCLE
All.ColdGasCycleTransitionTime = all.ColdGasCycleTransitionTime;
All.ColdGasCycleTransitionParameter = all.ColdGasCycleTransitionParameter;
#endif
#endif
#ifdef JEANS_PRESSURE_FLOOR
All.JeansMassFactor = all.JeansMassFactor;
#endif
#ifdef OUTERPOTENTIAL
#ifdef NFW
All.HaloConcentration = all.HaloConcentration;
All.HaloMass = all.HaloMass;
All.GasMassFraction = all.GasMassFraction;
#endif
#ifdef PLUMMER
All.PlummerMass = all.PlummerMass;
All.PlummerSoftenning = all.PlummerSoftenning;
#endif
#ifdef HOMOSPHERE
All.HomosphereMass = all.HomosphereMass;
All.HomosphereMaxRadius = all.HomosphereMaxRadius;
#endif
#ifdef MIYAMOTONAGAI
All.MiyamotoNagaiMass = all.MiyamotoNagaiMass;
All.MiyamotoNagaiHr = all.MiyamotoNagaiHr;
All.MiyamotoNagaiHz = all.MiyamotoNagaiHz;
#endif
#ifdef PISOTHERM
All.Rho0 = all.Rho0;
All.Rc = all.Rc;
All.GasMassFraction = all.GasMassFraction;
#endif
#ifdef CORIOLIS
All.CoriolisOmegaX0 = all.CoriolisOmegaX0;
All.CoriolisOmegaY0 = all.CoriolisOmegaY0;
All.CoriolisOmegaZ0 = all.CoriolisOmegaZ0;
#endif
#endif
#ifdef SFR
//All.StarFormationNStarsFromGas = all.StarFormationNStarsFromGas; /* do not change the param. if restarting, else, StarFormationStarMass will be wrong */
//All.StarFormationStarMass = all.StarFormationStarMass;
All.StarFormationMgMsFraction = all.StarFormationMgMsFraction;
All.StarFormationType = all.StarFormationType;
All.StarFormationCstar = all.StarFormationCstar;
All.StarFormationTime = all.StarFormationTime;
All.StarFormationDensity = all.StarFormationDensity;
All.StarFormationTemperature = all.StarFormationTemperature;
#ifdef SFR_USE_JEANS
All.StarformationJeansMassFactor = all.StarformationJeansMassFactor;
All.StarformationSofteningMaxPhys = all.StarformationSofteningMaxPhys;
All.StarformationSoftening = all.StarformationSoftening;
#endif
#endif
#ifdef FOF
All.FoF_Density = all.FoF_Density;
All.FoF_ThresholdDensityFactor = all.FoF_ThresholdDensityFactor;
All.FoF_MinHeadDensityFactor = all.FoF_MinHeadDensityFactor;
All.FoF_MinGroupMembers = all.FoF_MinGroupMembers;
All.FoF_MinGroupMass = all.FoF_MinGroupMass;
All.FoF_VirialFractionThreshold = all.FoF_VirialFractionThreshold;
All.FoF_TimeBetFoF = all.FoF_TimeBetFoF;
All.FoF_HsmlSearchRadiusFactor = all.FoF_HsmlSearchRadiusFactor;
All.FoF_HsmlMaxDistFactor = all.FoF_HsmlMaxDistFactor;
All.FoF_StarFormationType = all.FoF_StarFormationType;
#endif
#ifdef COOLING
All.CoolingType = all.CoolingType;
All.CutofCoolingTemperature = all.CutofCoolingTemperature;
All.InitGasMetallicity = all.InitGasMetallicity;
#endif
#ifdef CHIMIE
All.ChimieSupernovaEnergy = all.ChimieSupernovaEnergy; /* do not use this value, use the restartfile one */
All.ChimieKineticFeedbackFraction = all.ChimieKineticFeedbackFraction;
All.ChimieWindSpeed = all.ChimieWindSpeed;
All.ChimieWindTime = all.ChimieWindTime;
All.ChimieSNIaThermalTime = all.ChimieSNIaThermalTime;
All.ChimieSNIIThermalTime = all.ChimieSNIIThermalTime;
All.ChimieMaxSizeTimestep = all.ChimieMaxSizeTimestep;
#ifdef CHIMIE_TIMEBET
All.ChimieTimeBetChimie = all.ChimieTimeBetChimie;
#endif
#ifdef CHIMIE_ONE_SN_ONLY
All.ChimieOneSNMass = all.ChimieOneSNMass;
#endif
#if CHIMIE_EJECTA_RADIUS == 1
All.ChimieEjectaRadius = all.ChimieEjectaRadius;
#endif
#endif
#if defined (HEATING_PE)
All.HeatingPeElectronFraction = all.HeatingPeElectronFraction;
#endif
#if defined (HEATING_PE) || defined (STELLAR_FLUX) || defined (EXTERNAL_FLUX)
All.HeatingPeSolarEnergyDensity = all.HeatingPeSolarEnergyDensity;
#endif
#if defined (HEATING_PE) || defined (STELLAR_FLUX)
All.HeatingPeLMRatioGas = all.HeatingPeLMRatioGas;
All.HeatingPeLMRatioHalo = all.HeatingPeLMRatioHalo;
All.HeatingPeLMRatioDisk = all.HeatingPeLMRatioDisk;
All.HeatingPeLMRatioBulge = all.HeatingPeLMRatioBulge;
All.HeatingPeLMRatioStars = all.HeatingPeLMRatioStars;
All.HeatingPeLMRatioBndry = all.HeatingPeLMRatioBndry;
All.HeatingPeLMRatio[0] = all.HeatingPeLMRatio[0];
All.HeatingPeLMRatio[1] = all.HeatingPeLMRatio[1];
All.HeatingPeLMRatio[2] = all.HeatingPeLMRatio[2];
All.HeatingPeLMRatio[3] = all.HeatingPeLMRatio[3];
All.HeatingPeLMRatio[4] = all.HeatingPeLMRatio[4];
All.HeatingPeLMRatio[5] = all.HeatingPeLMRatio[5];
#endif
#ifdef EXTERNAL_FLUX
All.HeatingExternalFLuxEnergyDensity = all.HeatingExternalFLuxEnergyDensity;
#endif
#ifdef FEEDBACK
All.SupernovaEgySpecPerMassUnit = all.SupernovaEgySpecPerMassUnit;
All.SupernovaFractionInEgyKin = all.SupernovaFractionInEgyKin;
All.SupernovaTime = all.SupernovaTime;
#endif
#ifdef FEEDBACK_WIND
All.SupernovaWindEgySpecPerMassUnit = all.SupernovaWindEgySpecPerMassUnit;
All.SupernovaWindFractionInEgyKin = all.SupernovaWindFractionInEgyKin;
All.SupernovaWindParameter = all.SupernovaWindParameter;
All.SupernovaWindIntAccuracy = all.SupernovaWindIntAccuracy;
#endif
#ifdef BUBBLES
All.BubblesDelta = all.BubblesDelta;
All.BubblesAlpha = all.BubblesAlpha;
All.BubblesRadiusFactor = all.BubblesRadiusFactor;
All.BubblesR = all.BubblesR;
#endif
#ifdef AGN_HEATING
All.AGNHeatingPower = all.AGNHeatingPower;
All.AGNHeatingRmax = all.AGNHeatingRmax;
#endif
#ifdef AGN_ACCRETION
All.TimeBetAccretion = all.TimeBetAccretion;
All.AccretionRadius = all.AccretionRadius;
All.AGNFactor = all.AGNFactor;
All.MinMTotInRa = all.MinMTotInRa;
#endif
#ifdef BONDI_ACCRETION
All.BondiEfficiency = all.BondiEfficiency;
All.BondiBlackHoleMass = all.BondiBlackHoleMass;
All.BondiHsmlFactor = all.BondiHsmlFactor;
All.BondiPower = all.BondiPower;
All.BondiTimeBet = all.BondiTimeBet;
#endif
#if defined(ART_VISCO_MM)|| defined(ART_VISCO_RO) || defined(ART_VISCO_CD)
All.ArtBulkViscConstMin = all.ArtBulkViscConstMin;
All.ArtBulkViscConstMax = all.ArtBulkViscConstMax;
All.ArtBulkViscConstL = all.ArtBulkViscConstL;
#endif
#ifdef METAL_DIFFUSION
All.MetalDiffusionConst = all.MetalDiffusionConst;
#endif
#ifdef AB_TURB
All.StDecay = all.StDecay;
All.StEnergy = all.StEnergy;
All.StDtFreq = all.StDtFreq;
All.StKmin = all.StKmin;
All.StKmax = all.StKmax;
All.StSolWeight = all.StSolWeight;
All.StAmplFac = all.StAmplFac;
All.StSpectForm = all.StSpectForm;
All.StSeed = all.StSeed;
#endif
#ifdef SYNCHRONIZE_NGB_TIMESTEP
All.NgbFactorTimestep = all.NgbFactorTimestep;
#endif
#ifdef COOLING_GRACKLE
All.GrackleUVbackground = all.GrackleUVbackground;
All.GrackleRedshift = all.GrackleRedshift;
#ifdef COOLING_GRACKLE_H_SSHIELDING
All.GrackleHSShieldingDensityThreshold = all.GrackleHSShieldingDensityThreshold;
#endif
#endif
strcpy(All.ResubmitCommand, all.ResubmitCommand);
strcpy(All.OutputListFilename, all.OutputListFilename);
strcpy(All.OutputDir, all.OutputDir);
strcpy(All.RestartFile, all.RestartFile);
strcpy(All.EnergyFile, all.EnergyFile);
#ifdef SYSTEMSTATISTICS
strcpy(All.SystemFile, all.SystemFile);
#endif
strcpy(All.InfoFile, all.InfoFile);
strcpy(All.CpuFile, all.CpuFile);
strcpy(All.LogFile, all.LogFile);
#ifdef SFR
strcpy(All.SfrFile, all.SfrFile);
#endif
#ifdef CHIMIE
strcpy(All.ChimieFile, all.ChimieFile);
#endif
#ifdef MULTIPHASE
strcpy(All.PhaseFile, all.PhaseFile);
strcpy(All.StickyFile, all.StickyFile);
#endif
#ifdef AGN_ACCRETION
strcpy(All.AccretionFile, all.AccretionFile);
#endif
#ifdef BONDI_ACCRETION
strcpy(All.BondiFile, all.BondiFile);
#endif
#ifdef BUBBLES
strcpy(All.BubbleFile, all.BubbleFile);
#endif
strcpy(All.TimingsFile, all.TimingsFile);
strcpy(All.SnapshotFileBase, all.SnapshotFileBase);
#ifdef FOF
strcpy(All.FoF_SnapshotFileBase, all.FoF_SnapshotFileBase);
+ strcpy(All.FoF_IMFSnapshotFileBase, all.FoF_IMFSnapshotFileBase);
+#ifdef CHIMIE
+ strcpy(All.FoF_ChimieFile, all.FoF_ChimieFile);
+#endif
#endif
if(All.TimeMax != all.TimeMax)
readjust_timebase(All.TimeMax, all.TimeMax);
}
#ifdef PMGRID
long_range_init_regionsize();
#endif
if(All.ComovingIntegrationOn)
init_drift_table();
#ifdef COSMICTIME
if(All.ComovingIntegrationOn)
{
if (ThisTask==0)
printf("Initialize cosmic table\n");
init_cosmictime_table();
if (ThisTask==0)
printf("Initialize cosmic table done.\n");
}
if (ThisTask==0)
printf("Initialize full cosmic table\n");
init_full_cosmictime_table();
if (ThisTask==0)
printf("Initialize full cosmic table done.\n");
#endif
if(RestartFlag == 2)
All.Ti_nextoutput = find_next_outputtime(All.Ti_Current + 1);
else
All.Ti_nextoutput = find_next_outputtime(All.Ti_Current);
All.TimeLastRestartFile = CPUThisRun;
/* other initialization for special behavior */
#ifdef SFR
if (ThisTask == 0)
printf("StarFormationStarMass = %g\n\n",All.StarFormationStarMass);
#endif
#ifdef OUTERPOTENTIAL
if(ThisTask == 0) printf("Initialize outer potential...\n");
init_outer_potential();
if(ThisTask == 0) printf("Initialize outer potential done.\n");
#endif
#ifdef BUBBLES
if(ThisTask == 0) printf("Initialize bubble function...\n");
init_bubble();
if(ThisTask == 0) printf("Initialize bubble function done.\n");
#endif
#ifdef PERIODICOUTER
init_quat();
#endif
#ifdef MULTIPHASE
if(ThisTask == 0) printf("Initialize sticky...\n");
header.critical_energy_spec = All.CriticalEgySpec;
init_sticky();
if(ThisTask == 0) printf("Initialize sticky done.\n");
#endif
#ifdef PNBODY
if(ThisTask == 0) printf("Initialize pnbody...\n");
init_pnbody();
if(ThisTask == 0) printf("Initialize pnbody done.\n");
#endif
#ifdef DETAILED_CPU
tend = second();
All.CPU_Begrun += timediff(tstart, tend);
All.CPU_Begrun -= All.CPU_Leapfrog;
All.CPU_Begrun -= All.CPU_Domain;
All.CPU_Begrun -= All.CPU_Snapshot;
#endif
}
/*! Computes conversion factors between internal code units and the
* cgs-system.
*/
void set_units(void)
{
double meanweight;
All.UnitTime_in_s = All.UnitLength_in_cm / All.UnitVelocity_in_cm_per_s;
All.UnitTime_in_Megayears = All.UnitTime_in_s / SEC_PER_MEGAYEAR;
if(All.GravityConstantInternal == 0)
All.G = GRAVITY / pow(All.UnitLength_in_cm, 3) * All.UnitMass_in_g * pow(All.UnitTime_in_s, 2);
else
All.G = All.GravityConstantInternal;
All.UnitDensity_in_cgs = All.UnitMass_in_g / pow(All.UnitLength_in_cm, 3);
All.UnitPressure_in_cgs = All.UnitMass_in_g / All.UnitLength_in_cm / pow(All.UnitTime_in_s, 2);
All.UnitCoolingRate_in_cgs = All.UnitPressure_in_cgs / All.UnitTime_in_s;
All.UnitEnergy_in_cgs = All.UnitMass_in_g * pow(All.UnitLength_in_cm, 2) / pow(All.UnitTime_in_s, 2);
/* convert some physical input parameters to internal units */
All.Hubble = HUBBLE * All.UnitTime_in_s;
#ifdef HUBBLE_PARAM_WHEN_NOT_IN_UNITS
/* in case we want to use the Hubble constant with models, where the units does not
depends on the little h, we use All.HubbleParamNIU to get the correct value
of the Hubble constant */
if(All.ComovingIntegrationOn)
{
printf("It is not a good idea to use HUBBLE_PARAM_WHEN_NOT_IN_UNITS with ComovingIntegrationOn !!!\n");
fflush(stdout);
endrun(9765487632);
}
All.Hubble = All.Hubble*All.HubbleParamNIU;
#endif
meanweight = 4.0 / (1 + 3 * HYDROGEN_MASSFRAC); /* note: we assume neutral gas here */
/*meanweight = 4 / (8 - 5 * (1 - HYDROGEN_MASSFRAC));*/ /* note: we assume FULL ionized gas here */
All.Boltzmann = BOLTZMANN /All.UnitEnergy_in_cgs;
All.ProtonMass = PROTONMASS/All.UnitMass_in_g;
All.mumh = All.ProtonMass*meanweight;
#ifdef MULTIPHASE
All.StickyTime *= 3.1536e+13*All.HubbleParam/All.UnitTime_in_s; /* Myr to code unit */
All.StickyCollisionTime *= 3.1536e+13*All.HubbleParam/All.UnitTime_in_s; /* Myr to code unit */
All.StickyIdleTime *= 3.1536e+13*All.HubbleParam/All.UnitTime_in_s; /* Myr to code unit */
All.StickyMinVelocity *=1e5/All.UnitVelocity_in_cm_per_s; /* km/s to code unit */
All.StickyMaxVelocity *=1e5/All.UnitVelocity_in_cm_per_s; /* km/s to code unit */
if (All.StickyTime==0)
All.StickyLambda = 0;
else
All.StickyLambda = 1./All.StickyTime;
All.CriticalEgySpec = 1./GAMMA_MINUS1 * All.Boltzmann/All.mumh * All.CriticalTemperature;
All.CriticalNonCollisionalEgySpec = 1./GAMMA_MINUS1 * All.Boltzmann/All.mumh * All.CriticalNonCollisionalTemperature;
All.StickyDensity = All.StickyDensity/All.UnitDensity_in_cgs/(All.HubbleParam*All.HubbleParam);
//if((All.StickyLambda > 0.1/All.MaxSizeTimestep)&&(ThisTask==0))
// {
// printf("\nStickyLambda is to big and you may experiment numerical problems !\n");
// printf("You should either decrease StickyLambda or decrease MaxSizeTimestep.\n");
// printf("(StickyLambda=%g,maxStickyLambda=%g)\n",All.StickyLambda,0.01/All.MaxSizeTimestep);
// printf("try \n");
// printf("StickyLambda <= %g or MaxSizeTimestep <= %g \n",(0.01/All.MaxSizeTimestep),(0.01/All.StickyLambda));
// fflush(stdout);
// endrun(121212);
// }
#ifdef COLDGAS_CYCLE
All.ColdGasCycleTransitionTime *= 3.1536e+13*All.HubbleParam/All.UnitTime_in_s; /* Myr to code unit */
#endif
#endif
#ifdef SFR
All.StarFormationTime = All.StarFormationTime/All.UnitTime_in_s * 3.1536e16*All.HubbleParam;
All.StarFormationDensity = All.StarFormationDensity/All.UnitDensity_in_cgs/(All.HubbleParam*All.HubbleParam);
#endif
#ifdef FOF
All.FoF_Density = All.FoF_Density/All.UnitDensity_in_cgs/(All.HubbleParam*All.HubbleParam);
All.FoF_ThresholdDensity = All.FoF_ThresholdDensityFactor*All.FoF_Density;
All.FoF_MinHeadDensity = All.FoF_MinHeadDensityFactor *All.FoF_Density;
All.FoF_MinGroupMass *=SOLAR_MASS/All.UnitMass_in_g*All.HubbleParam; /* to CMU */
#endif
#if defined (HEATING_PE) || defined (STELLAR_FLUX)
All.HeatingPeLMRatio[0] = All.HeatingPeLMRatioGas;
All.HeatingPeLMRatio[1] = All.HeatingPeLMRatioHalo;
All.HeatingPeLMRatio[2] = All.HeatingPeLMRatioDisk;
All.HeatingPeLMRatio[3] = All.HeatingPeLMRatioBulge;
All.HeatingPeLMRatio[4] = All.HeatingPeLMRatioStars;
All.HeatingPeLMRatio[5] = All.HeatingPeLMRatioBndry;
int k;
for (k=0;k<6;k++)
{
All.HeatingPeLMRatio[k] *= 1./SOLAR_MASS; /* erg/s/Msol to erg/s/g */
All.HeatingPeLMRatio[k] *= All.UnitMass_in_g*All.UnitTime_in_s / All.UnitEnergy_in_cgs / All.HubbleParam; /* erg/s/g to code unit */
}
#endif
#ifdef FEEDBACK
All.SupernovaEgySpecPerMassUnit *= All.UnitMass_in_g / All.UnitEnergy_in_cgs;
All.SupernovaTime *= 3.1536e+13*All.HubbleParam/All.UnitTime_in_s; /* Myr to code unit */
#endif
#ifdef FEEDBACK_WIND
All.SupernovaWindEgySpecPerMassUnit *= All.UnitMass_in_g / All.UnitEnergy_in_cgs;
All.SupernovaWindSpeed = sqrt( 2*All.SupernovaWindFractionInEgyKin * All.SupernovaWindEgySpecPerMassUnit / All.SupernovaWindParameter );
#endif
#if defined (AGN_ACCRETION) || defined (BONDI_ACCRETION)
All.LightSpeed = C/All.UnitVelocity_in_cm_per_s;
#endif
#ifdef CHIMIE
All.ChimieSupernovaEnergy = All.ChimieSupernovaEnergy/All.UnitMass_in_g/pow(All.UnitVelocity_in_cm_per_s,2)*All.HubbleParam;
All.ChimieWindSpeed = All.ChimieWindSpeed*1e5/All.UnitVelocity_in_cm_per_s;
All.ChimieWindTime = All.ChimieWindTime*3.1536e13/All.UnitTime_in_s*All.HubbleParam;
All.ChimieSNIaThermalTime = All.ChimieSNIaThermalTime*3.1536e13/All.UnitTime_in_s*All.HubbleParam;
All.ChimieSNIIThermalTime = All.ChimieSNIIThermalTime*3.1536e13/All.UnitTime_in_s*All.HubbleParam;
All.ChimieMaxSizeTimestep = All.ChimieMaxSizeTimestep*3.1536e13/All.UnitTime_in_s*All.HubbleParam;
#ifdef CHIMIE_TIMEBET
All.ChimieTimeBetChimie = All.ChimieTimeBetChimie*3.1536e13/All.UnitTime_in_s*All.HubbleParam;
#endif
#endif
#if defined(CHIMIE) || defined(FOF)
All.CMUtoMsol = All.UnitMass_in_g/SOLAR_MASS/All.HubbleParam; /* convertion factor from Code Mass Unit to Solar Mass */
All.MsoltoCMU = 1/All.CMUtoMsol; /* convertion factor from Solar Mass to Code Mass Unit */
#endif
#ifdef CHIMIE
#ifdef CHIMIE_ONE_SN_ONLY
All.ChimieOneSNMass = All.ChimieOneSNMass*All.MsoltoCMU;
#endif
#if CHIMIE_EJECTA_RADIUS == 1
All.ChimieEjectaRadius = All.ChimieEjectaRadius * KPC_IN_CM/All.UnitLength_in_cm * All.HubbleParam; /* kpc to code length units */
#endif
#endif
#ifdef JEANS_PRESSURE_FLOOR
All.JeansMassFactor = pow(All.JeansMassFactor,2/3.);
#endif
#ifdef COOLING_GRACKLE
#ifdef COOLING_GRACKLE_H_SSHIELDING
All.GrackleHSShieldingDensityThreshold = All.GrackleHSShieldingDensityThreshold*1.6726e-24/All.UnitDensity_in_cgs/(All.HubbleParam*All.HubbleParam); /* atom/cm3 to density code unit */
#endif
#endif
#ifdef FOF
All.FoF_TimeBetFoF = All.FoF_TimeBetFoF*3.1536e13/All.UnitTime_in_s*All.HubbleParam;
#endif
#ifdef COMPUTE_PHYSICAL_UNITS
// density to atom per CC (we assume the density is already corrected from hubbpleparam and scaling factor)
All.CDUtoAtomPerCC = All.UnitMass_in_g / pow(All.UnitLength_in_cm,3) / PROTONMASS ;
#endif
if(ThisTask == 0)
{
printf("\nHubble (internal units) = %g\n", All.Hubble);
printf("G (internal units) = %g\n", All.G);
printf("Boltzmann = %g \n", All.Boltzmann);
printf("ProtonMass = %g \n", All.ProtonMass);
printf("mumh = %g \n", All.mumh);
printf("UnitMass_in_g = %g \n", All.UnitMass_in_g);
printf("UnitTime_in_s = %g \n", All.UnitTime_in_s);
printf("UnitVelocity_in_cm_per_s = %g \n", All.UnitVelocity_in_cm_per_s);
printf("UnitDensity_in_cgs = %g \n", All.UnitDensity_in_cgs);
printf("UnitEnergy_in_cgs = %g \n", All.UnitEnergy_in_cgs);
printf("\n");
#ifdef SFR
printf("StarFormationDensity (internal units) = %g \n", All.StarFormationDensity);
printf("StarFormationTime (internal units) = %g \n", All.StarFormationTime);
#endif
#ifdef FEEDBACK
printf("SupernovaTime (internal units) = %g \n", All.SupernovaTime);
printf("SupernovaEgySpecPerMassUnit (internal units) = %g \n", All.SupernovaEgySpecPerMassUnit);
#endif
#ifdef FEEDBACK_WIND
printf("SupernovaWindEgySpecPerMassUnit (internal units) = %g \n", All.SupernovaWindEgySpecPerMassUnit);
printf("SupernovaWindSpeed (internal units) = %g \n", All.SupernovaWindSpeed);
#endif
#ifdef MULTIPHASE
printf("CriticalEgySpec (internal units) = %g \n", All.CriticalEgySpec);
printf("CriticalNonCollisionalEgySpec (internal units) = %g \n", All.CriticalNonCollisionalEgySpec);
printf("StickyCollisionTime (internal units) = %g \n", All.StickyCollisionTime);
printf("StickyIdleTime (internal units) = %g \n", All.StickyIdleTime);
printf("StickyDensity (internal units) = %g \n", All.StickyDensity);
printf("StickyTime (internal units) = %g \n", All.StickyTime);
printf("StickyMinVelocity (internal units) = %g \n", All.StickyMinVelocity);
printf("StickyMaxVelocity (internal units) = %g \n", All.StickyMaxVelocity);
#endif
#ifdef COLDGAS_CYCLE
printf("ColdGasCycleTransitionTime (internal units) = %g \n", All.ColdGasCycleTransitionTime);
#endif
#ifdef CHIMIE
printf("ChimieSupernovaEnergy (internal units) = %g \n", All.ChimieSupernovaEnergy);
printf("ChimieWindSpeed (internal units) = %g \n", All.ChimieWindSpeed);
printf("ChimieWindTime (internal units) = %g \n", All.ChimieWindTime);
printf("ChimieSNIaThermalTime (internal units) = %g \n", All.ChimieSNIaThermalTime);
printf("ChimieSNIIThermalTime (internal units) = %g \n", All.ChimieSNIIThermalTime);
printf("ChimieMaxSizeTimestep (internal units) = %g \n", All.ChimieMaxSizeTimestep);
#ifdef CHIMIE_TIMEBET
printf("ChimieTimeBetChimie (internal units) = %g \n", All.ChimieTimeBetChimie);
#endif
#endif
#ifdef FOF
printf("FoF_Density (internal units) = %g \n",All.FoF_Density);
printf("FoF_ThresholdDensity (internal units) = %g \n",All.FoF_ThresholdDensity);
printf("FoF_MinHeadDensity (internal units) = %g \n",All.FoF_MinHeadDensity);
printf("FoF_MinGroupMass (internal units) = %g \n",All.FoF_MinGroupMass);
printf("FoF_VirialFractionThreshold (internal units) = %g \n",All.FoF_VirialFractionThreshold);
printf("FoF_HsmlSearchRadiusFactor (internal units) = %g \n",All.FoF_HsmlSearchRadiusFactor);
printf("FoF_TimeBetFoF (internal units) = %g \n",All.FoF_TimeBetFoF);
#endif
#ifdef JEANS_PRESSURE_FLOOR
printf("JeansMassFactor^(2/3) = %g \n",All.JeansMassFactor);
#endif
#ifdef COOLING_GRACKLE
#ifdef COOLING_GRACKLE_H_SSHIELDING
printf("GrackleHSShieldingDensityThreshold(internal units)= %g \n",All.GrackleHSShieldingDensityThreshold);
#endif
#endif
#ifdef COMPUTE_PHYSICAL_UNITS
printf("CDUtoAtomPerCC = %g \n",All.CDUtoAtomPerCC);
#endif
printf("\n");
}
#ifdef ISOTHERM_EQS
All.MinEgySpec = 0;
#else
All.MinEgySpec = 1 / meanweight * (1.0 / GAMMA_MINUS1) * (BOLTZMANN / PROTONMASS) * All.MinGasTemp;
All.MinEgySpec *= All.UnitMass_in_g / All.UnitEnergy_in_cgs;
#endif
}
/*! Initialize local system state variables
*/
void init_local_sys_state(void)
{
#ifdef SFR
LocalSysState.StarEnergyInt = 0.;
#ifdef COOLING
LocalSysState.RadiatedEnergy = 0.;
#endif
#endif
#ifdef CHIMIE_THERMAL_FEEDBACK
LocalSysState.EnergyThermalFeedback = 0.;
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
LocalSysState.EnergyKineticFeedback = 0.;
#endif
#ifdef MULTIPHASE
LocalSysState.EnergyRadSticky = 0.;
#endif
#ifdef FEEDBACK_WIND
LocalSysState.EnergyFeedbackWind = 0.;
#endif
#ifdef INTEGRAL_CONSERVING_DISSIPATION
LocalSysState.EnergyICDissipation = 0.;
#endif
}
/*! This function opens various log-files that report on the status and
* performance of the simulstion. On restart from restart-files
* (start-option 1), the code will append to these files.
*/
void open_outputfiles(void)
{
char mode[2], buf[200];
#ifdef ADVANCEDSTATISTICS
int i=0;
#endif
if(RestartFlag == 0 || RestartFlag == 2)
strcpy(mode, "w");
else
strcpy(mode, "a");
/* for this kind of log, all tasks write its own file */
#ifdef CHIMIE
#ifdef CHIMIE_STATS
sprintf(buf, "%s%s_%s.%d", All.OutputDir, All.ChimieFile,"SNs",ThisTask);
if(!(FdChimieStatsSNs = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
sprintf(buf, "%s%s_%s.%d", All.OutputDir, All.ChimieFile,"Gas",ThisTask);
if(!(FdChimieStatsGas = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
#endif
+
+#ifdef FOF
+ sprintf(buf, "%s%s.%d", All.OutputDir, All.FoF_ChimieFile,ThisTask);
+ if(!(FdFOF_Chimie = fopen(buf, mode)))
+ {
+ printf("error in opening file '%s'\n", buf);
+ endrun(1);
+ }
+#endif // FOF
+
+
#endif
if(ThisTask != 0) /* only the root processor writes to the log files */
return;
sprintf(buf, "%s%s", All.OutputDir, All.CpuFile);
if(!(FdCPU = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
#ifdef ADVANCEDCPUSTATISTICS
else
{
if(RestartFlag == 0 || RestartFlag == 2) /* write the header */
{
fprintf(FdCPU,"# Step ");
fprintf(FdCPU,"Time ");
fprintf(FdCPU,"nCPUs ");
fprintf(FdCPU,"CPU_Total ");
#ifdef DETAILED_CPU
fprintf(FdCPU,"CPU_Leapfrog ");
fprintf(FdCPU,"CPU_Physics ");
fprintf(FdCPU,"CPU_Residual ");
fprintf(FdCPU,"CPU_Accel ");
fprintf(FdCPU,"CPU_Begrun ");
#endif
fprintf(FdCPU,"CPU_Gravity ");
fprintf(FdCPU,"CPU_Hydro ");
#ifdef COOLING
fprintf(FdCPU,"CPU_Cooling ");
#endif
#ifdef SFR
fprintf(FdCPU,"CPU_StarFormation ");
#endif
#ifdef CHIMIE
fprintf(FdCPU,"CPU_Chimie ");
#endif
#ifdef MULTIPHASE
fprintf(FdCPU,"CPU_Sticky ");
#endif
fprintf(FdCPU,"CPU_Domain ");
fprintf(FdCPU,"CPU_Potential ");
fprintf(FdCPU,"CPU_Predict ");
fprintf(FdCPU,"CPU_TimeLine ");
fprintf(FdCPU,"CPU_Snapshot ");
fprintf(FdCPU,"CPU_TreeWalk ");
fprintf(FdCPU,"CPU_TreeConstruction ");
fprintf(FdCPU,"CPU_CommSum ");
fprintf(FdCPU,"CPU_Imbalance ");
fprintf(FdCPU,"CPU_HydCompWalk ");
fprintf(FdCPU,"CPU_HydCommSumm ");
fprintf(FdCPU,"CPU_HydImbalance ");
fprintf(FdCPU,"CPU_EnsureNgb ");
fprintf(FdCPU,"CPU_PM ");
fprintf(FdCPU,"CPU_Peano ");
#ifdef DETAILED_CPU_DOMAIN
fprintf(FdCPU,"CPU_Domain_findExtend ");
fprintf(FdCPU,"CPU_Domain_determineTopTree ");
fprintf(FdCPU,"CPU_Domain_sumCost ");
fprintf(FdCPU,"CPU_Domain_findSplit ");
fprintf(FdCPU,"CPU_Domain_shiftSplit ");
fprintf(FdCPU,"CPU_Domain_countToGo ");
fprintf(FdCPU,"CPU_Domain_exchange ");
#endif
#ifdef DETAILED_CPU_GRAVITY
fprintf(FdCPU,"CPU_Gravity_TreeWalk1 ");
fprintf(FdCPU,"CPU_Gravity_TreeWalk2 ");
fprintf(FdCPU,"CPU_Gravity_CommSum1 ");
fprintf(FdCPU,"CPU_Gravity_CommSum2 ");
fprintf(FdCPU,"CPU_Gravity_Imbalance1 ");
fprintf(FdCPU,"CPU_Gravity_Imbalance2 ");
#endif
/* return */
fprintf(FdCPU,"\n");
fflush(FdCPU);
}
}
#endif
sprintf(buf, "%s%s", All.OutputDir, All.InfoFile);
if(!(FdInfo = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
sprintf(buf, "%s%s", All.OutputDir, All.LogFile);
if(!(FdLog = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
sprintf(buf, "%s%s", All.OutputDir, All.EnergyFile);
if(!(FdEnergy = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
#ifdef ADVANCEDSTATISTICS
else
{
if(RestartFlag == 0 || RestartFlag == 2 ) /* write the header */
{
fprintf(FdEnergy,"# Time EnergyInt EnergyPot EnergyKin ");
#ifdef COOLING
fprintf(FdEnergy,"EnergyRadSph ");
#endif
#ifdef AGN_HEATING
fprintf(FdEnergy,"EnergyAGNHeat ");
#endif
#ifdef DISSIPATION_FORCES
fprintf(FdEnergy,"EnergyDissipationForces ");
#endif
#ifdef INTEGRAL_CONSERVING_DISSIPATION
fprintf(FdEnergy,"EnergyICDissipation ");
#endif
#ifdef MULTIPHASE
fprintf(FdEnergy,"EnergyRadSticky ");
#endif
#ifdef FEEDBACK_WIND
fprintf(FdEnergy,"EnergyFeedbackWind ");
#endif
#ifdef BUBBLES
fprintf(FdEnergy,"EnergyBubbles ");
#endif
#ifdef CHIMIE_THERMAL_FEEDBACK
fprintf(FdEnergy,"EnergyThermalFeedback ");
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
fprintf(FdEnergy,"EnergyKineticFeedback ");
#endif
for (i=0;i<6;i++)
{
fprintf(FdEnergy,"EnergyIntComp%d EnergyPotComp%d EnergyKinComp%d ",i+1,i+1,i+1);
#ifdef COOLING
fprintf(FdEnergy,"EnergyRadSphComp%d ",i+1);
#endif
#ifdef MULTIPHASE
fprintf(FdEnergy,"EnergyRadStickyComp%d ",i+1);
#endif
#ifdef FEEDBACK_WIND
fprintf(FdEnergy,"EnergyFeedbackWindComp%d ",i+1);
#endif
#ifdef BUBBLES
fprintf(FdEnergy,"EnergyBubblesComp%d ",i+1);
#endif
#ifdef CHIMIE_THERMAL_FEEDBACK
fprintf(FdEnergy,"EnergyThermalFeedbackComp%d ",i+1);
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
fprintf(FdEnergy,"EnergyKineticFeedbackComp%d ",i+1);
#endif
}
for (i=0;i<6;i++)
fprintf(FdEnergy,"MassComp%d ",i+1);
/* return */
fprintf(FdEnergy,"\n");
fflush(FdEnergy);
}
}
#endif
#ifdef SYSTEMSTATISTICS
sprintf(buf, "%s%s", All.OutputDir, All.SystemFile);
if(!(FdSystem = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
#endif
sprintf(buf, "%s%s", All.OutputDir, All.TimingsFile);
if(!(FdTimings = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
#ifdef FORCETEST
if(RestartFlag == 0 || RestartFlag == 2)
{
sprintf(buf, "%s%s", All.OutputDir, "forcetest.txt");
if(!(FdForceTest = fopen(buf, "w")))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
fclose(FdForceTest);
}
#endif
#ifdef SFR
sprintf(buf, "%s%s", All.OutputDir, All.SfrFile);
if(!(FdSfr = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
#endif
#ifdef CHIMIE
sprintf(buf, "%s%s", All.OutputDir, All.ChimieFile);
if(!(FdChimie = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
#endif
#ifdef MULTIPHASE
sprintf(buf, "%s%s", All.OutputDir, All.PhaseFile);
if(!(FdPhase = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
sprintf(buf, "%s%s", All.OutputDir, All.StickyFile);
if(!(FdSticky = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
#endif
#ifdef AGN_ACCRETION
sprintf(buf, "%s%s", All.OutputDir, All.AccretionFile);
if(!(FdAccretion = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
#endif
#ifdef BONDI_ACCRETION
sprintf(buf, "%s%s", All.OutputDir, All.BondiFile);
if(!(FdBondi = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
#endif
#ifdef BUBBLES
sprintf(buf, "%s%s", All.OutputDir, All.BubbleFile);
if(!(FdBubble = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
#endif
#ifdef GAS_ACCRETION
sprintf(buf, "%s%s", All.OutputDir, All.GasAccretionFile);
if(!(FdGasAccretion = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
#endif
#ifdef PERIODICOUTER
sprintf(buf, "%s%s", All.OutputDir, All.TraceFile);
if(!(FdTrace = fopen(buf, mode)))
{
printf("error in opening file '%s'\n", buf);
endrun(1);
}
#endif
}
/*! This function closes the global log-files.
*/
void close_outputfiles(void)
{
/* for this kind of log, all tasks write its own file */
#ifdef CHIMIE
#ifdef CHIMIE_STATS
fclose(FdChimieStatsSNs);
fclose(FdChimieStatsGas);
#endif
+#ifdef FOF
+ fclose(FdFOF_Chimie);
+#endif
#endif
if(ThisTask != 0) /* only the root processor writes to the log files */
return;
fclose(FdCPU);
fclose(FdInfo);
fclose(FdLog);
fclose(FdEnergy);
#ifdef SYSTEMSTATISTICS
fclose(FdSystem);
#endif
fclose(FdTimings);
#ifdef FORCETEST
fclose(FdForceTest);
#endif
#ifdef SFR
fclose(FdSfr);
#endif
#ifdef CHIMIE
fclose(FdChimie);
#endif
#ifdef MULTIPHASE
fclose(FdPhase);
fclose(FdSticky);
#endif
#ifdef AGN_ACCRETION
fclose(FdAccretion);
#endif
#ifdef BONDI_ACCRETION
fclose(FdBondi);
#endif
#ifdef BUBBLES
fclose(FdBubble);
#endif
#ifdef GAS_ACCRETION
fclose(FdGasAccretion);
#endif
}
/*! This function parses the parameterfile in a simple way. Each paramater
* is defined by a keyword (`tag'), and can be either of type double, int,
* or character string. The routine makes sure that each parameter
* appears exactly once in the parameterfile, otherwise error messages are
* produced that complain about the missing parameters.
*/
void read_parameter_file(char *fname)
{
#define DOUBLE 1
#define STRING 2
#define INT 3
#define MAXTAGS 300
FILE *fd, *fdout;
char buf[200], buf1[200], buf2[200], buf3[400];
int i, j, nt;
int id[MAXTAGS];
void *addr[MAXTAGS];
char tag[MAXTAGS][50];
int errorFlag = 0;
if(sizeof(long long) != 8)
{
if(ThisTask == 0)
printf("\nType `long long' is not 64 bit on this platform. Stopping.\n\n");
endrun(0);
}
if(sizeof(int) != 4)
{
if(ThisTask == 0)
printf("\nType `int' is not 32 bit on this platform. Stopping.\n\n");
endrun(0);
}
if(sizeof(float) != 4)
{
if(ThisTask == 0)
printf("\nType `float' is not 32 bit on this platform. Stopping.\n\n");
endrun(0);
}
if(sizeof(double) != 8)
{
if(ThisTask == 0)
printf("\nType `double' is not 64 bit on this platform. Stopping.\n\n");
endrun(0);
}
if(ThisTask == 0) /* read parameter file on process 0 */
{
nt = 0;
strcpy(tag[nt], "InitCondFile");
addr[nt] = All.InitCondFile;
id[nt++] = STRING;
strcpy(tag[nt], "OutputDir");
addr[nt] = All.OutputDir;
id[nt++] = STRING;
strcpy(tag[nt], "SnapshotFileBase");
addr[nt] = All.SnapshotFileBase;
id[nt++] = STRING;
strcpy(tag[nt], "EnergyFile");
addr[nt] = All.EnergyFile;
id[nt++] = STRING;
#ifdef SYSTEMSTATISTICS
strcpy(tag[nt], "SystemFile");
addr[nt] = All.SystemFile;
id[nt++] = STRING;
#endif
strcpy(tag[nt], "CpuFile");
addr[nt] = All.CpuFile;
id[nt++] = STRING;
#ifdef SFR
strcpy(tag[nt], "SfrFile");
addr[nt] = All.SfrFile;
id[nt++] = STRING;
#endif
#ifdef CHIMIE
strcpy(tag[nt], "ChimieFile");
addr[nt] = All.ChimieFile;
id[nt++] = STRING;
#endif
#ifdef MULTIPHASE
strcpy(tag[nt], "PhaseFile");
addr[nt] = All.PhaseFile;
id[nt++] = STRING;
strcpy(tag[nt], "StickyFile");
addr[nt] = All.StickyFile;
id[nt++] = STRING;
#endif
#ifdef AGN_ACCRETION
strcpy(tag[nt], "AccretionFile");
addr[nt] = All.AccretionFile;
id[nt++] = STRING;
#endif
#ifdef BONDI_ACCRETION
strcpy(tag[nt], "BondiFile");
addr[nt] = All.BondiFile;
id[nt++] = STRING;
#endif
#ifdef BUBBLES
strcpy(tag[nt], "BubbleFile");
addr[nt] = All.BubbleFile;
id[nt++] = STRING;
#endif
#ifdef GAS_ACCRETION
strcpy(tag[nt], "GasAccretionFile");
addr[nt] = All.GasAccretionFile;
id[nt++] = STRING;
#endif
strcpy(tag[nt], "InfoFile");
addr[nt] = All.InfoFile;
id[nt++] = STRING;
strcpy(tag[nt], "LogFile");
addr[nt] = All.LogFile;
id[nt++] = STRING;
strcpy(tag[nt], "TimingsFile");
addr[nt] = All.TimingsFile;
id[nt++] = STRING;
strcpy(tag[nt], "RestartFile");
addr[nt] = All.RestartFile;
id[nt++] = STRING;
strcpy(tag[nt], "ResubmitCommand");
addr[nt] = All.ResubmitCommand;
id[nt++] = STRING;
strcpy(tag[nt], "OutputListFilename");
addr[nt] = All.OutputListFilename;
id[nt++] = STRING;
strcpy(tag[nt], "OutputListOn");
addr[nt] = &All.OutputListOn;
id[nt++] = INT;
strcpy(tag[nt], "Omega0");
addr[nt] = &All.Omega0;
id[nt++] = DOUBLE;
strcpy(tag[nt], "OmegaBaryon");
addr[nt] = &All.OmegaBaryon;
id[nt++] = DOUBLE;
strcpy(tag[nt], "OmegaLambda");
addr[nt] = &All.OmegaLambda;
id[nt++] = DOUBLE;
strcpy(tag[nt], "HubbleParam");
addr[nt] = &All.HubbleParam;
id[nt++] = DOUBLE;
#ifdef HUBBLE_PARAM_WHEN_NOT_IN_UNITS
strcpy(tag[nt], "HubbleParamNIU");
addr[nt] = &All.HubbleParamNIU;
id[nt++] = DOUBLE;
#endif
strcpy(tag[nt], "BoxSize");
addr[nt] = &All.BoxSize;
id[nt++] = DOUBLE;
strcpy(tag[nt], "PeriodicBoundariesOn");
addr[nt] = &All.PeriodicBoundariesOn;
id[nt++] = INT;
strcpy(tag[nt], "TimeOfFirstSnapshot");
addr[nt] = &All.TimeOfFirstSnapshot;
id[nt++] = DOUBLE;
strcpy(tag[nt], "CpuTimeBetRestartFile");
addr[nt] = &All.CpuTimeBetRestartFile;
id[nt++] = DOUBLE;
strcpy(tag[nt], "TimeBetStatistics");
addr[nt] = &All.TimeBetStatistics;
id[nt++] = DOUBLE;
strcpy(tag[nt], "TimeBegin");
addr[nt] = &All.TimeBegin;
id[nt++] = DOUBLE;
strcpy(tag[nt], "TimeMax");
addr[nt] = &All.TimeMax;
id[nt++] = DOUBLE;
strcpy(tag[nt], "TimeBetSnapshot");
addr[nt] = &All.TimeBetSnapshot;
id[nt++] = DOUBLE;
#ifdef SET_SNAPSHOT_FILE_COUNT
strcpy(tag[nt], "SnapshotFileCount");
addr[nt] = &All.SnapshotFileCount;
id[nt++] = INT;
#endif
strcpy(tag[nt], "UnitVelocity_in_cm_per_s");
addr[nt] = &All.UnitVelocity_in_cm_per_s;
id[nt++] = DOUBLE;
strcpy(tag[nt], "UnitLength_in_cm");
addr[nt] = &All.UnitLength_in_cm;
id[nt++] = DOUBLE;
strcpy(tag[nt], "UnitMass_in_g");
addr[nt] = &All.UnitMass_in_g;
id[nt++] = DOUBLE;
strcpy(tag[nt], "TreeDomainUpdateFrequency");
addr[nt] = &All.TreeDomainUpdateFrequency;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ErrTolIntAccuracy");
addr[nt] = &All.ErrTolIntAccuracy;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ErrTolTheta");
addr[nt] = &All.ErrTolTheta;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ErrTolForceAcc");
addr[nt] = &All.ErrTolForceAcc;
id[nt++] = DOUBLE;
strcpy(tag[nt], "MinGasHsmlFractional");
addr[nt] = &All.MinGasHsmlFractional;
id[nt++] = DOUBLE;
strcpy(tag[nt], "MaxSizeTimestep");
addr[nt] = &All.MaxSizeTimestep;
id[nt++] = DOUBLE;
strcpy(tag[nt], "MinSizeTimestep");
addr[nt] = &All.MinSizeTimestep;
id[nt++] = DOUBLE;
strcpy(tag[nt], "MaxRMSDisplacementFac");
addr[nt] = &All.MaxRMSDisplacementFac;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ArtBulkViscConst");
addr[nt] = &All.ArtBulkViscConst;
id[nt++] = DOUBLE;
#ifdef ART_CONDUCTIVITY
strcpy(tag[nt], "ArtCondConst");
addr[nt] = &All.ArtCondConst;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ArtCondThreshold");
addr[nt] = &All.ArtCondThreshold;
id[nt++] = DOUBLE;
#endif
#if defined(ART_VISCO_MM)|| defined(ART_VISCO_RO) || defined(ART_VISCO_CD)
strcpy(tag[nt], "ArtBulkViscConstMin");
addr[nt] = &All.ArtBulkViscConstMin;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ArtBulkViscConstMax");
addr[nt] = &All.ArtBulkViscConstMax;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ArtBulkViscConstL");
addr[nt] = &All.ArtBulkViscConstL;
id[nt++] = DOUBLE;
#endif
#if METAL_DIFFUSION
strcpy(tag[nt], "MetalDiffusionConst");
addr[nt] = &All.MetalDiffusionConst;
id[nt++] = DOUBLE;
#endif
#ifdef AB_TURB
strcpy(tag[nt], "ST_decay");
addr[nt] = &All.StDecay;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ST_energy");
addr[nt] = &All.StEnergy;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ST_DtFreq");
addr[nt] = &All.StDtFreq;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ST_Kmin");
addr[nt] = &All.StKmin;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ST_Kmax");
addr[nt] = &All.StKmax;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ST_SolWeight");
addr[nt] = &All.StSolWeight;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ST_AmplFac");
addr[nt] = &All.StAmplFac;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ST_SpectForm");
addr[nt] = &All.StSpectForm;
id[nt++] = INT;
strcpy(tag[nt], "ST_Seed");
addr[nt] = &All.StSeed;
id[nt++] = INT;
#endif
#ifdef SYNCHRONIZE_NGB_TIMESTEP
strcpy(tag[nt], "NgbFactorTimestep");
addr[nt] = &All.NgbFactorTimestep;
id[nt++] = INT;
#endif
strcpy(tag[nt], "CourantFac");
addr[nt] = &All.CourantFac;
id[nt++] = DOUBLE;
strcpy(tag[nt], "DesNumNgb");
addr[nt] = &All.DesNumNgb;
id[nt++] = DOUBLE;
strcpy(tag[nt], "MaxNumNgbDeviation");
addr[nt] = &All.MaxNumNgbDeviation;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ComovingIntegrationOn");
addr[nt] = &All.ComovingIntegrationOn;
id[nt++] = INT;
strcpy(tag[nt], "ICFormat");
addr[nt] = &All.ICFormat;
id[nt++] = INT;
strcpy(tag[nt], "SnapFormat");
addr[nt] = &All.SnapFormat;
id[nt++] = INT;
strcpy(tag[nt], "NumFilesPerSnapshot");
addr[nt] = &All.NumFilesPerSnapshot;
id[nt++] = INT;
strcpy(tag[nt], "NumFilesWrittenInParallel");
addr[nt] = &All.NumFilesWrittenInParallel;
id[nt++] = INT;
strcpy(tag[nt], "ResubmitOn");
addr[nt] = &All.ResubmitOn;
id[nt++] = INT;
strcpy(tag[nt], "TypeOfTimestepCriterion");
addr[nt] = &All.TypeOfTimestepCriterion;
id[nt++] = INT;
strcpy(tag[nt], "TypeOfOpeningCriterion");
addr[nt] = &All.TypeOfOpeningCriterion;
id[nt++] = INT;
strcpy(tag[nt], "TimeLimitCPU");
addr[nt] = &All.TimeLimitCPU;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SofteningHalo");
addr[nt] = &All.SofteningHalo;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SofteningDisk");
addr[nt] = &All.SofteningDisk;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SofteningBulge");
addr[nt] = &All.SofteningBulge;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SofteningGas");
addr[nt] = &All.SofteningGas;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SofteningStars");
addr[nt] = &All.SofteningStars;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SofteningBndry");
addr[nt] = &All.SofteningBndry;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SofteningHaloMaxPhys");
addr[nt] = &All.SofteningHaloMaxPhys;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SofteningDiskMaxPhys");
addr[nt] = &All.SofteningDiskMaxPhys;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SofteningBulgeMaxPhys");
addr[nt] = &All.SofteningBulgeMaxPhys;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SofteningGasMaxPhys");
addr[nt] = &All.SofteningGasMaxPhys;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SofteningStarsMaxPhys");
addr[nt] = &All.SofteningStarsMaxPhys;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SofteningBndryMaxPhys");
addr[nt] = &All.SofteningBndryMaxPhys;
id[nt++] = DOUBLE;
strcpy(tag[nt], "BufferSize");
addr[nt] = &All.BufferSize;
id[nt++] = INT;
strcpy(tag[nt], "PartAllocFactor");
addr[nt] = &All.PartAllocFactor;
id[nt++] = DOUBLE;
strcpy(tag[nt], "TreeAllocFactor");
addr[nt] = &All.TreeAllocFactor;
id[nt++] = DOUBLE;
#ifdef SFR
strcpy(tag[nt], "StarsAllocFactor");
addr[nt] = &All.StarsAllocFactor;
id[nt++] = DOUBLE;
#endif
strcpy(tag[nt], "GravityConstantInternal");
addr[nt] = &All.GravityConstantInternal;
id[nt++] = DOUBLE;
strcpy(tag[nt], "InitGasTemp");
addr[nt] = &All.InitGasTemp;
id[nt++] = DOUBLE;
strcpy(tag[nt], "MinGasTemp");
addr[nt] = &All.MinGasTemp;
id[nt++] = DOUBLE;
#ifdef RANDOMSEED_AS_PARAMETER
strcpy(tag[nt], "RandomSeed");
addr[nt] = &All.RandomSeed;
id[nt++] = INT;
#endif
#ifdef COOLING
strcpy(tag[nt], "CoolingFile");
addr[nt] = All.CoolingFile;
id[nt++] = STRING;
#ifdef COOLING_WIERSMA
strcpy(tag[nt], "CoolingDirectory");
addr[nt] = All.CoolingDirectory;
id[nt++] = STRING;
#endif
#ifdef COOLING_GRACKLE
strcpy(tag[nt], "GrackleCloudyTable");
addr[nt] = All.GrackleCloudyTable;
id[nt++] = STRING;
strcpy(tag[nt], "GrackleUVbackground");
addr[nt] = &All.GrackleUVbackground;
id[nt++] = INT;
strcpy(tag[nt], "GrackleRedshift");
addr[nt] = &All.GrackleRedshift;
id[nt++] = DOUBLE;
#ifdef COOLING_GRACKLE_H_SSHIELDING
strcpy(tag[nt], "GrackleHSShieldingDensityThreshold");
addr[nt] = &All.GrackleHSShieldingDensityThreshold;
id[nt++] = DOUBLE;
#endif
#endif
strcpy(tag[nt], "CutofCoolingTemperature");
addr[nt] = &All.CutofCoolingTemperature;
id[nt++] = DOUBLE;
strcpy(tag[nt], "InitGasMetallicity");
addr[nt] = &All.InitGasMetallicity;
id[nt++] = DOUBLE;
strcpy(tag[nt], "CoolingType");
addr[nt] = &All.CoolingType;
id[nt++] = DOUBLE;
#endif
#ifdef CHIMIE
strcpy(tag[nt], "ChimieNumberOfParameterFiles");
addr[nt] = &All.ChimieNumberOfParameterFiles;
id[nt++] = INT;
strcpy(tag[nt], "ChimieParameterFile");
addr[nt] = All.ChimieParameterFile;
id[nt++] = STRING;
strcpy(tag[nt], "ChimieSupernovaEnergy");
addr[nt] = &All.ChimieSupernovaEnergy;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ChimieKineticFeedbackFraction");
addr[nt] = &All.ChimieKineticFeedbackFraction;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ChimieWindSpeed");
addr[nt] = &All.ChimieWindSpeed;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ChimieWindTime");
addr[nt] = &All.ChimieWindTime;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ChimieSNIaThermalTime");
addr[nt] = &All.ChimieSNIaThermalTime;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ChimieSNIIThermalTime");
addr[nt] = &All.ChimieSNIIThermalTime;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ChimieMaxSizeTimestep");
addr[nt] = &All.ChimieMaxSizeTimestep;
id[nt++] = DOUBLE;
#ifdef CHIMIE_TIMEBET
strcpy(tag[nt], "ChimieTimeBetChimie");
addr[nt] = &All.ChimieTimeBetChimie;
id[nt++] = DOUBLE;
#endif
#ifdef CHIMIE_ONE_SN_ONLY
strcpy(tag[nt], "ChimieOneSNMass");
addr[nt] = &All.ChimieOneSNMass;
id[nt++] = DOUBLE;
#endif
#if CHIMIE_EJECTA_RADIUS == 1
strcpy(tag[nt], "ChimieEjectaRadius");
addr[nt] = &All.ChimieEjectaRadius;
id[nt++] = DOUBLE;
#endif
#endif
#if defined (HEATING_PE)
strcpy(tag[nt], "HeatingPeElectronFraction");
addr[nt] = &All.HeatingPeElectronFraction;
id[nt++] = DOUBLE;
#endif
#if defined (HEATING_PE) || defined (STELLAR_FLUX) || defined (EXTERNAL_FLUX)
strcpy(tag[nt], "HeatingPeSolarEnergyDensity");
addr[nt] = &All.HeatingPeSolarEnergyDensity;
id[nt++] = DOUBLE;
#endif
#if defined (HEATING_PE) || defined (STELLAR_FLUX)
strcpy(tag[nt], "HeatingPeLMRatioGas");
addr[nt] = &All.HeatingPeLMRatioGas;
id[nt++] = DOUBLE;
strcpy(tag[nt], "HeatingPeLMRatioHalo");
addr[nt] = &All.HeatingPeLMRatioHalo;
id[nt++] = DOUBLE;
strcpy(tag[nt], "HeatingPeLMRatioDisk");
addr[nt] = &All.HeatingPeLMRatioDisk;
id[nt++] = DOUBLE;
strcpy(tag[nt], "HeatingPeLMRatioBulge");
addr[nt] = &All.HeatingPeLMRatioBulge;
id[nt++] = DOUBLE;
strcpy(tag[nt], "HeatingPeLMRatioStars");
addr[nt] = &All.HeatingPeLMRatioStars;
id[nt++] = DOUBLE;
strcpy(tag[nt], "HeatingPeLMRatioBndry");
addr[nt] = &All.HeatingPeLMRatioBndry;
id[nt++] = DOUBLE;
#endif
#ifdef EXTERNAL_FLUX
strcpy(tag[nt], "HeatingExternalFLuxEnergyDensity");
addr[nt] = &All.HeatingExternalFLuxEnergyDensity;
id[nt++] = DOUBLE;
#endif
#ifdef MULTIPHASE
strcpy(tag[nt], "CriticalTemperature");
addr[nt] = &All.CriticalTemperature;
id[nt++] = DOUBLE;
strcpy(tag[nt], "CriticalNonCollisionalTemperature");
addr[nt] = &All.CriticalNonCollisionalTemperature;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StickyUseGridForCollisions");
addr[nt] = &All.StickyUseGridForCollisions;
id[nt++] = INT;
strcpy(tag[nt], "StickyTime");
addr[nt] = &All.StickyTime;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StickyCollisionTime");
addr[nt] = &All.StickyCollisionTime;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StickyIdleTime");
addr[nt] = &All.StickyIdleTime;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StickyMinVelocity");
addr[nt] = &All.StickyMinVelocity;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StickyMaxVelocity");
addr[nt] = &All.StickyMaxVelocity;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StickyBetaR");
addr[nt] = &All.StickyBetaR;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StickyBetaT");
addr[nt] = &All.StickyBetaT;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StickyGridNx");
addr[nt] = &All.StickyGridNx;
id[nt++] = INT;
strcpy(tag[nt], "StickyGridNy");
addr[nt] = &All.StickyGridNy;
id[nt++] = INT;
strcpy(tag[nt], "StickyGridNz");
addr[nt] = &All.StickyGridNz;
id[nt++] = INT;
strcpy(tag[nt], "StickyGridXmin");
addr[nt] = &All.StickyGridXmin;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StickyGridXmax");
addr[nt] = &All.StickyGridXmax;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StickyGridYmin");
addr[nt] = &All.StickyGridYmin;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StickyGridYmax");
addr[nt] = &All.StickyGridYmax;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StickyGridZmin");
addr[nt] = &All.StickyGridZmin;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StickyGridZmax");
addr[nt] = &All.StickyGridZmax;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StickyDensity");
addr[nt] = &All.StickyDensity;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StickyDensityPower");
addr[nt] = &All.StickyDensityPower;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StickyRsphFact");
addr[nt] = &All.StickyRsphFact;
id[nt++] = DOUBLE;
#ifdef COLDGAS_CYCLE
strcpy(tag[nt], "ColdGasCycleTransitionTime");
addr[nt] = &All.ColdGasCycleTransitionTime;
id[nt++] = DOUBLE;
strcpy(tag[nt], "ColdGasCycleTransitionParameter");
addr[nt] = &All.ColdGasCycleTransitionParameter;
id[nt++] = DOUBLE;
#endif
#endif
#ifdef JEANS_PRESSURE_FLOOR
strcpy(tag[nt], "JeansMassFactor");
addr[nt] = &All.JeansMassFactor;
id[nt++] = DOUBLE;
#endif
#ifdef OUTERPOTENTIAL
#ifdef NFW
strcpy(tag[nt], "HaloConcentration");
addr[nt] = &All.HaloConcentration;
id[nt++] = DOUBLE;
strcpy(tag[nt], "HaloMass");
addr[nt] = &All.HaloMass;
id[nt++] = DOUBLE;
strcpy(tag[nt], "GasMassFraction");
addr[nt] = &All.GasMassFraction;
id[nt++] = DOUBLE;
#endif
#ifdef PLUMMER
strcpy(tag[nt], "PlummerMass");
addr[nt] = &All.PlummerMass;
id[nt++] = DOUBLE;
strcpy(tag[nt], "PlummerSoftenning");
addr[nt] = &All.PlummerSoftenning;
id[nt++] = DOUBLE;
#endif
#ifdef HOMOSPHERE
strcpy(tag[nt], "HomosphereMass");
addr[nt] = &All.HomosphereMass;
id[nt++] = DOUBLE;
strcpy(tag[nt], "HomosphereMaxRadius");
addr[nt] = &All.HomosphereMaxRadius;
id[nt++] = DOUBLE;
#endif
#ifdef MIYAMOTONAGAI
strcpy(tag[nt], "MiyamotoNagaiMass");
addr[nt] = &All.MiyamotoNagaiMass;
id[nt++] = DOUBLE;
strcpy(tag[nt], "MiyamotoNagaiHr");
addr[nt] = &All.MiyamotoNagaiHr;
id[nt++] = DOUBLE;
strcpy(tag[nt], "MiyamotoNagaiHz");
addr[nt] = &All.MiyamotoNagaiHz;
id[nt++] = DOUBLE;
#endif
#ifdef PISOTHERM
strcpy(tag[nt], "Rho0");
addr[nt] = &All.Rho0;
id[nt++] = DOUBLE;
strcpy(tag[nt], "Rc");
addr[nt] = &All.Rc;
id[nt++] = DOUBLE;
strcpy(tag[nt], "GasMassFraction");
addr[nt] = &All.GasMassFraction;
id[nt++] = DOUBLE;
#endif
#ifdef CORIOLIS
strcpy(tag[nt], "CoriolisOmegaX0");
addr[nt] = &All.CoriolisOmegaX0;
id[nt++] = DOUBLE;
strcpy(tag[nt], "CoriolisOmegaY0");
addr[nt] = &All.CoriolisOmegaY0;
id[nt++] = DOUBLE;
strcpy(tag[nt], "CoriolisOmegaZ0");
addr[nt] = &All.CoriolisOmegaZ0;
id[nt++] = DOUBLE;
#endif
#endif
#ifdef SFR
strcpy(tag[nt], "StarFormationNStarsFromGas");
addr[nt] = &All.StarFormationNStarsFromGas;
id[nt++] = INT;
strcpy(tag[nt], "StarFormationMgMsFraction");
addr[nt] = &All.StarFormationMgMsFraction;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StarFormationStarMass");
addr[nt] = &All.StarFormationStarMass;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StarFormationType");
addr[nt] = &All.StarFormationType;
id[nt++] = INT;
strcpy(tag[nt], "StarFormationCstar");
addr[nt] = &All.StarFormationCstar;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StarFormationTime");
addr[nt] = &All.StarFormationTime;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StarFormationDensity");
addr[nt] = &All.StarFormationDensity;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StarFormationTemperature");
addr[nt] = &All.StarFormationTemperature;
id[nt++] = DOUBLE;
#ifdef SFR_USE_JEANS
strcpy(tag[nt], "StarformationJeansMassFactor");
addr[nt] = &All.StarformationJeansMassFactor;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StarformationSofteningMaxPhys");
addr[nt] = &All.StarformationSofteningMaxPhys;
id[nt++] = DOUBLE;
strcpy(tag[nt], "StarformationSoftening");
addr[nt] = &All.StarformationSoftening;
id[nt++] = DOUBLE;
#endif
#endif
#ifdef FOF
strcpy(tag[nt], "FoF_Density");
addr[nt] = &All.FoF_Density;
id[nt++] = DOUBLE;
strcpy(tag[nt], "FoF_ThresholdDensityFactor");
addr[nt] = &All.FoF_ThresholdDensityFactor;
id[nt++] = DOUBLE;
strcpy(tag[nt], "FoF_MinHeadDensityFactor");
addr[nt] = &All.FoF_MinHeadDensityFactor;
id[nt++] = DOUBLE;
strcpy(tag[nt], "FoF_MinGroupMembers");
addr[nt] = &All.FoF_MinGroupMembers;
id[nt++] = INT;
strcpy(tag[nt], "FoF_MinGroupMass");
addr[nt] = &All.FoF_MinGroupMass;
id[nt++] = DOUBLE;
strcpy(tag[nt], "FoF_VirialFractionThreshold");
addr[nt] = &All.FoF_VirialFractionThreshold;
id[nt++] = DOUBLE;
strcpy(tag[nt], "FoF_HsmlSearchRadiusFactor");
addr[nt] = &All.FoF_HsmlSearchRadiusFactor;
id[nt++] = DOUBLE;
strcpy(tag[nt], "FoF_HsmlMaxDistFactor");
addr[nt] = &All.FoF_HsmlMaxDistFactor;
id[nt++] = DOUBLE;
strcpy(tag[nt], "FoF_TimeBetFoF");
addr[nt] = &All.FoF_TimeBetFoF;
id[nt++] = DOUBLE;
strcpy(tag[nt], "FoF_SnapshotFileBase");
addr[nt] = All.FoF_SnapshotFileBase;
id[nt++] = STRING;
+
+ strcpy(tag[nt], "FoF_IMFSnapshotFileBase");
+ addr[nt] = All.FoF_IMFSnapshotFileBase;
+ id[nt++] = STRING;
strcpy(tag[nt], "FoF_StarFormationType");
addr[nt] = &All.FoF_StarFormationType;
- id[nt++] = INT;
+ id[nt++] = INT;
+
+#ifdef CHIMIE
+ strcpy(tag[nt], "FoF_ChimieFile");
+ addr[nt] = All.FoF_ChimieFile;
+ id[nt++] = STRING;
+#endif
+
#endif
#ifdef FEEDBACK
strcpy(tag[nt], "SupernovaEgySpecPerMassUnit");
addr[nt] = &All.SupernovaEgySpecPerMassUnit;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SupernovaFractionInEgyKin");
addr[nt] = &All.SupernovaFractionInEgyKin;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SupernovaTime");
addr[nt] = &All.SupernovaTime;
id[nt++] = DOUBLE;
#endif
#ifdef FEEDBACK_WIND
strcpy(tag[nt], "SupernovaWindEgySpecPerMassUnit");
addr[nt] = &All.SupernovaWindEgySpecPerMassUnit;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SupernovaWindFractionInEgyKin");
addr[nt] = &All.SupernovaWindFractionInEgyKin;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SupernovaWindParameter");
addr[nt] = &All.SupernovaWindParameter;
id[nt++] = DOUBLE;
strcpy(tag[nt], "SupernovaWindIntAccuracy");
addr[nt] = &All.SupernovaWindIntAccuracy;
id[nt++] = DOUBLE;
#endif
#ifdef AGN_ACCRETION
strcpy(tag[nt], "TimeBetAccretion");
addr[nt] = &All.TimeBetAccretion;
id[nt++] = DOUBLE;
strcpy(tag[nt], "AccretionRadius");
addr[nt] = &All.AccretionRadius;
id[nt++] = DOUBLE;
strcpy(tag[nt], "AGNFactor");
addr[nt] = &All.AGNFactor;
id[nt++] = DOUBLE;
strcpy(tag[nt], "MinMTotInRa");
addr[nt] = &All.MinMTotInRa;
id[nt++] = DOUBLE;
#endif
#ifdef BUBBLES
strcpy(tag[nt], "BubblesDelta");
addr[nt] = &All.BubblesDelta;
id[nt++] = DOUBLE;
strcpy(tag[nt], "BubblesAlpha");
addr[nt] = &All.BubblesAlpha;
id[nt++] = DOUBLE;
strcpy(tag[nt], "BubblesRadiusFactor");
addr[nt] = &All.BubblesRadiusFactor;
id[nt++] = DOUBLE;
strcpy(tag[nt], "BubblesInitFile");
addr[nt] = All.BubblesInitFile;
id[nt++] = STRING;
#endif
#ifdef AGN_HEATING
strcpy(tag[nt], "AGNHeatingPower");
addr[nt] = &All.AGNHeatingPower;
id[nt++] = DOUBLE;
strcpy(tag[nt], "AGNHeatingRmax");
addr[nt] = &All.AGNHeatingRmax;
id[nt++] = DOUBLE;
#endif
#ifdef BONDI_ACCRETION
strcpy(tag[nt], "BondiEfficiency");
addr[nt] = &All.BondiEfficiency;
id[nt++] = DOUBLE;
strcpy(tag[nt], "BondiBlackHoleMass");
addr[nt] = &All.BondiBlackHoleMass;
id[nt++] = DOUBLE;
strcpy(tag[nt], "BondiHsmlFactor");
addr[nt] = &All.BondiHsmlFactor;
id[nt++] = DOUBLE;
strcpy(tag[nt], "BondiTimeBet");
addr[nt] = &All.BondiTimeBet;
id[nt++] = DOUBLE;
#endif
#ifdef PERIODICOUTER
/*Trace Output file*/
strcpy(tag[nt], "TraceFile");
addr[nt] = All.TraceFile;
id[nt++] = STRING;
/*External position */
strcpy(tag[nt],"TracePosX");
addr[nt] = &All.TracePos[0];
id[nt++] = DOUBLE;
strcpy(tag[nt],"TracePosY");
addr[nt] = &All.TracePos[1];
id[nt++] = DOUBLE;
strcpy(tag[nt],"TracePosZ");
addr[nt] = &All.TracePos[2];
id[nt++] = DOUBLE;
/*Box Velocity*/
strcpy(tag[nt],"TraceVelX");
addr[nt] = &All.TraceVel[0];
id[nt++] = DOUBLE;
strcpy(tag[nt],"TraceVelY");
addr[nt] = &All.TraceVel[1];
id[nt++] = DOUBLE;
strcpy(tag[nt],"TraceVelZ");
addr[nt] = &All.TraceVel[2];
id[nt++] = DOUBLE;
/*Inertial Frame*/
strcpy(tag[nt],"InertialV");
addr[nt] = &All.InertialV;
id[nt++] = INT;
#ifndef TRACE_ACC
/*Internal trace particle position*/
strcpy(tag[nt],"TracePeriodX");
addr[nt] = &All.TracePeriodPos[0];
id[nt++] = DOUBLE;
strcpy(tag[nt],"TracePeriodY");
addr[nt] = &All.TracePeriodPos[1];
id[nt++] = DOUBLE;
strcpy(tag[nt],"TracePeriodZ");
addr[nt] = &All.TracePeriodPos[2];
id[nt++] = DOUBLE;
#endif
#endif
#ifdef HOT_HALO
strcpy(tag[nt],"HaloT");
addr[nt] = &All.HaloT;
id[nt++] = DOUBLE;
strcpy(tag[nt],"HaloPMass");
addr[nt] = &All.HaloPartMass;
id[nt++] = DOUBLE;
strcpy(tag[nt],"HaloScale");
addr[nt] = &All.HaloScaleFactor;
id[nt++] = DOUBLE;
#endif
if((fd = fopen(fname, "r")))
{
sprintf(buf, "%s%s", fname, "-usedvalues");
if(!(fdout = fopen(buf, "w")))
{
printf("error opening file '%s' \n", buf);
errorFlag = 1;
}
else
{
while(!feof(fd))
{
*buf = 0;
fgets(buf, 200, fd);
if(sscanf(buf, "%s%s%s", buf1, buf2, buf3) < 2)
continue;
if(buf1[0] == '%')
continue;
for(i = 0, j = -1; i < nt; i++)
if(strcmp(buf1, tag[i]) == 0)
{
j = i;
tag[i][0] = 0;
break;
}
if(j >= 0)
{
switch (id[j])
{
case DOUBLE:
*((double *) addr[j]) = atof(buf2);
fprintf(fdout, "%-35s%g\n", buf1, *((double *) addr[j]));
break;
case STRING:
strcpy(addr[j], buf2);
fprintf(fdout, "%-35s%s\n", buf1, buf2);
break;
case INT:
*((int *) addr[j]) = atoi(buf2);
fprintf(fdout, "%-35s%d\n", buf1, *((int *) addr[j]));
break;
}
}
else
{
fprintf(stdout, "Error in file %s: Tag '%s' not allowed or multiple defined.\n",
fname, buf1);
errorFlag = 1;
}
}
fclose(fd);
fclose(fdout);
i = strlen(All.OutputDir);
if(i > 0)
if(All.OutputDir[i - 1] != '/')
strcat(All.OutputDir, "/");
/* copy parameters-usedvalues file*/
sprintf(buf1, "%s%s", fname, "-usedvalues");
sprintf(buf2, "%s%s", All.OutputDir, "parameters-usedvalues");
fd = fopen(buf1,"r");
fdout = fopen(buf2,"w");
while(1)
{
fgets(buf, 200, fd);
if (feof(fd)) break;
fprintf(fdout, buf, 200);
}
fclose(fd);
fclose(fdout);
}
}
else
{
printf("\nParameter file %s not found.\n\n", fname);
errorFlag = 2;
}
if(errorFlag != 2)
for(i = 0; i < nt; i++)
{
if(*tag[i])
{
printf("Error. I miss a value for tag '%s' in parameter file '%s'.\n", tag[i], fname);
errorFlag = 1;
}
}
if(All.OutputListOn && errorFlag == 0)
errorFlag += read_outputlist(All.OutputListFilename);
else
All.OutputListLength = 0;
}
MPI_Bcast(&errorFlag, 1, MPI_INT, 0, MPI_COMM_WORLD);
if(errorFlag)
{
MPI_Finalize();
exit(0);
}
/* now communicate the relevant parameters to the other processes */
MPI_Bcast(&All, sizeof(struct global_data_all_processes), MPI_BYTE, 0, MPI_COMM_WORLD);
if(All.NumFilesWrittenInParallel < 1)
{
if(ThisTask == 0)
printf("NumFilesWrittenInParallel MUST be at least 1\n");
endrun(0);
}
if(All.NumFilesWrittenInParallel > NTask)
{
if(ThisTask == 0)
printf("NumFilesWrittenInParallel MUST be smaller than number of processors\n");
endrun(0);
}
#ifdef PERIODIC
if(All.PeriodicBoundariesOn == 0)
{
if(ThisTask == 0)
{
printf("Code was compiled with periodic boundary conditions switched on.\n");
printf("You must set `PeriodicBoundariesOn=1', or recompile the code.\n");
}
endrun(0);
}
#else
if(All.PeriodicBoundariesOn == 1)
{
if(ThisTask == 0)
{
printf("Code was compiled with periodic boundary conditions switched off.\n");
printf("You must set `PeriodicBoundariesOn=0', or recompile the code.\n");
}
endrun(0);
}
#endif
if(All.TypeOfTimestepCriterion >= 1)
{
if(ThisTask == 0)
{
printf("The specified timestep criterion\n");
printf("is not valid\n");
}
endrun(0);
}
#if defined(LONG_X) || defined(LONG_Y) || defined(LONG_Z)
#ifndef NOGRAVITY
if(ThisTask == 0)
{
printf("Code was compiled with LONG_X/Y/Z, but not with NOGRAVITY.\n");
printf("Stretched periodic boxes are not implemented for gravity yet.\n");
}
endrun(0);
#endif
#endif
#ifdef SYNCHRONIZE_NGB_TIMESTEP
int ti = 1;
while((ti != All.NgbFactorTimestep) && (ti!=TIMEBASE))
ti <<= 1;
if (ti==TIMEBASE)
{
if(ThisTask == 0)
{
printf("\nThe parameter NgbFactorTimestep must be a power of two\n");
printf("NgbFactorTimestep=%d is not valid\n\n",All.NgbFactorTimestep);
endrun(7);
}
}
#endif
#undef DOUBLE
#undef STRING
#undef INT
#undef MAXTAGS
}
/*! this function reads a table with a list of desired output times. The
* table does not have to be ordered in any way, but may not contain more
* than MAXLEN_OUTPUTLIST entries.
*/
int read_outputlist(char *fname)
{
FILE *fd;
if(!(fd = fopen(fname, "r")))
{
printf("can't read output list in file '%s'\n", fname);
return 1;
}
All.OutputListLength = 0;
do
{
if(fscanf(fd, " %lg ", &All.OutputListTimes[All.OutputListLength]) == 1)
All.OutputListLength++;
else
break;
}
while(All.OutputListLength < MAXLEN_OUTPUTLIST);
fclose(fd);
printf("\nfound %d times in output-list.\n", All.OutputListLength);
return 0;
}
/*! If a restart from restart-files is carried out where the TimeMax
* variable is increased, then the integer timeline needs to be
* adjusted. The approach taken here is to reduce the resolution of the
* integer timeline by factors of 2 until the new final time can be
* reached within TIMEBASE.
*/
void readjust_timebase(double TimeMax_old, double TimeMax_new)
{
int i;
long long ti_end;
if(ThisTask == 0)
{
printf("\nAll.TimeMax has been changed in the parameterfile\n");
printf("Need to adjust integer timeline\n\n\n");
}
if(TimeMax_new < TimeMax_old)
{
if(ThisTask == 0)
printf("\nIt is not allowed to reduce All.TimeMax\n\n");
endrun(556);
}
if(All.ComovingIntegrationOn)
ti_end = log(TimeMax_new / All.TimeBegin) / All.Timebase_interval;
else
ti_end = (TimeMax_new - All.TimeBegin) / All.Timebase_interval;
while(ti_end > TIMEBASE)
{
All.Timebase_interval *= 2.0;
ti_end /= 2;
All.Ti_Current /= 2;
#ifdef PMGRID
All.PM_Ti_begstep /= 2;
All.PM_Ti_endstep /= 2;
#endif
for(i = 0; i < NumPart; i++)
{
P[i].Ti_begstep /= 2;
P[i].Ti_endstep /= 2;
}
}
All.TimeMax = TimeMax_new;
}
diff --git a/src/chimie.c b/src/chimie.c
index b4af1b0..5093eff 100644
--- a/src/chimie.c
+++ b/src/chimie.c
@@ -1,8632 +1,8643 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <mpi.h>
#include <gsl/gsl_math.h>
#include "allvars.h"
#include "proto.h"
#ifdef CHIMIE
#ifdef CHIMIE_FROM_HDF5
#include <hdf5.h>
#include "hdf5io.h"
#endif
#ifdef PYCHEM
#include <Python.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <numpy/arrayobject.h>
/*
****************************************************
these variables are already defined in Gadget (or not needed)
****************************************************
*/
#define TO_DOUBLE(a) ( (PyArrayObject*) PyArray_CastToType(a, PyArray_DescrFromType(NPY_DOUBLE) ,0) )
#endif /* PYCHEM */
const char *get_filename_ext(const char *filename) {
const char *dot = strrchr(filename, '.');
if(!dot || dot == filename) return "";
return dot + 1;
}
/****************************************************************************************/
/*
/*
/*
/* COMMON CHIMIE PART
/*
/*
/*
/****************************************************************************************/
#define MAXPTS 10
#define MAXDATASIZE 200
#define MAXDATAZSIZE 110
/********************************************************
hdf5 reading routines
*********************************************************/
#ifdef CHIMIE_FROM_HDF5
#define HEADER_GRP "/Header"
#define DATA_GRP "/Data"
/********************************************************
Chemistry functions
*********************************************************/
struct ChemistryHeaderStruct
{
char * version;
char * author;
char * date;
};
struct ChemistryDataAttributesStruct
{
int nelts;
char **elts;
double *SolarMassAbundances;
double MeanWDMass;
char *SNIIYieldsFile;
char *SNIIHeliumCoreFile;
char *DYINYieldsFile;
char *DYINHeliumCoreFile;
char *SNIaFile;
char *SolarAbundancesFile;
};
struct ChemistryYieldsTableStruct
{
int nbins;
double min;
double step;
char *label;
double *data;
};
struct ChemistryYieldsTable2DStruct
{
int nx;
int ny;
double x0;
double y0;
double dx;
double dy;
char *label;
double **data;
};
struct ChemistryLiveTimesStruct
{
int nx;
int ny;
double **coeff_z;
};
struct ChemistryIMFStruct
{
int n;
double *ms;
double *as;
char *bs;
double Mmin;
double Mmax;
};
struct ChemistrySNIaStruct
{
double Mpl;
double Mpu;
double a;
double Mdl1;
double Mdu1;
double bb1;
double Mdl2;
double Mdu2;
double bb2;
struct ElementsDataStruct Metals;
};
struct ChemistrySNIIStruct
{
double Mmin;
double Mmax;
int npts;
int nelts;
char **elts;
struct ChemistryYieldsTableStruct *table;
};
struct ChemistryDYINStruct
{
double Mmin;
double Mmax;
int npts;
int nelts;
char **elts;
struct ChemistryYieldsTableStruct *table;
struct ChemistryYieldsTable2DStruct *tableZ;
int Zflag;
int nptZs;
};
/*! Read a table containing yields
* stored in the dataset named "name"
*/
struct ChemistryYieldsTableStruct readYieldsTable(hid_t group,char *name)
{
struct ChemistryYieldsTableStruct table;
hid_t dset;
herr_t status;
table.data = readDatasetAsArrayDouble(group,name);
/* read attributes */
dset = H5Dopen( group , name, H5P_DEFAULT);
table.nbins = readAttributeAsInt(dset,"nbins");
table.min = readAttributeAsDouble(dset,"min");
table.step = readAttributeAsDouble(dset,"step");
table.label = readAttributeAsString(dset,"label");
//printYieldsTable(table);
status = H5Dclose(dset);
return table;
}
/*! Read a table containing 2d yields
* stored in the dataset named "name"
*/
struct ChemistryYieldsTable2DStruct readYieldsTable2D(hid_t group,char *name)
{
struct ChemistryYieldsTable2DStruct table;
hid_t dset;
herr_t status;
table.data = readDatasetAsArray2DDouble_v0(group,name);
/* read attributes */
dset = H5Dopen( group , name, H5P_DEFAULT);
table.nx = readAttributeAsInt(dset,"nx");
table.ny = readAttributeAsInt(dset,"ny");
table.x0 = readAttributeAsDouble(dset,"x0");
table.y0 = readAttributeAsDouble(dset,"y0");
table.dx = readAttributeAsDouble(dset,"dx");
table.dy = readAttributeAsDouble(dset,"dy");
table.label = readAttributeAsString(dset,"label");
//printYieldsTable(table);
status = H5Dclose(dset);
return table;
}
/*! Read the attributes linked to the data group
*/
int readDataAttributes(hid_t table,struct ChemistryDataAttributesStruct *Param)
{
hid_t group;
herr_t status;
group = H5Gopen(table, DATA_GRP,H5P_DEFAULT);
Param->nelts = readAttributeAsInt(group,"nelts");
Param->elts = readAttributeAsArrayString(group,"elts");
Param->SolarMassAbundances = readAttributeAsArrayDouble(group,"SolarMassAbundances");
Param->MeanWDMass = readAttributeAsDouble(group,"MeanWDMass");
Param->elts = readAttributeAsArrayString(group,"elts");
Param->SNIIYieldsFile = readAttributeAsString(group,"SNIIYieldsFile");
Param->SNIIHeliumCoreFile = readAttributeAsString(group,"SNIIHeliumCoreFile");
Param->DYINYieldsFile = readAttributeAsString(group,"DYINYieldsFile");
Param->DYINHeliumCoreFile = readAttributeAsString(group,"DYINHeliumCoreFile");
Param->SNIaFile = readAttributeAsString(group,"SNIaFile");
Param->SolarAbundancesFile = readAttributeAsString(group,"SolarAbundancesFile");
status = H5Gclose (group);
return 0;
}
/*! Print the attributes linked to the data group
*/
int printDataAttributes(struct ChemistryDataAttributesStruct Parameters)
{
int i;
printf("\n");
printf("Data attribute content:\n\n");
printf("\t nelts = %d\n",Parameters.nelts);
printf("\t elts = ");
for (i=0; i<Parameters.nelts; i++)
printf ("%s ",Parameters.elts[i]);
printf ("\n");
printf("\t SolarMassAbundances = ");
for (i=0; i<Parameters.nelts; i++)
printf ("%g ",Parameters.SolarMassAbundances[i]);
printf ("\n");
printf("\t MeanWDMass = %g\n",Parameters.MeanWDMass);
printf("\n");
printf("\t SNIIYieldsFile = %s\n",Parameters.SNIIYieldsFile);
printf("\t SNIIHeliumCoreFile = %s\n",Parameters.SNIIHeliumCoreFile);
printf("\n");
printf("\t DYINYieldsFile = %s\n",Parameters.DYINYieldsFile);
printf("\t DYINHeliumCoreFile = %s\n",Parameters.DYINHeliumCoreFile);
printf("\n");
printf("\t SNIaFile = %s\n",Parameters.SNIaFile);
printf("\t SolarAbundancesFile = %s\n",Parameters.SolarAbundancesFile);
printf("\n");
return 0;
}
/*! Read the attributes linked to the header group
*/
int readHeader(hid_t table,struct ChemistryHeaderStruct *Header)
{
hid_t group;
herr_t status;
group = H5Gopen(table, HEADER_GRP,H5P_DEFAULT);
/* read attribute */
Header->version = readAttributeAsString(group,"version");
Header->author = readAttributeAsString(group,"author");
Header->date = readAttributeAsString(group,"date");
status = H5Gclose (group);
return 0;
}
/*! Print the attributes linked to the header group
*/
int printHeader(struct ChemistryHeaderStruct Header)
{
printf("\n");
printf("Header content:\n\n");
printf("\t version = %s\n",Header.version);
printf("\t author = %s\n",Header.author);
printf("\t date = %s\n",Header.date);
printf("\n");
return 0;
}
/*! Print the content of a yield table
*/
int printYieldsTable(struct ChemistryYieldsTableStruct table,char * space)
{
int i;
printf("%s%s:\n\n",space,table.label);
printf("%s\t nbins = %d\n",space,table.nbins);
printf("%s\t min = %g\n",space,table.min);
printf("%s\t step = %g\n",space,table.step);
printf("%s\t label = %s\n",space,table.label);
printf("\n");
for(i=0;i<3;i++)
printf("%s\t [%d] %g\n",space,i,table.data[i]);
printf("%s\t ...\n",space);
for(i=table.nbins-3;i<table.nbins;i++)
printf("%s\t [%d] %g\n",space,i,table.data[i]);
printf("\n");
return 0;
}
/*! Print the content of a yield table
*/
int printYieldsTable2D(struct ChemistryYieldsTable2DStruct table,char * space)
{
int i,j;
printf("%s%s:\n\n",space,table.label);
printf("%s\t nx = %d\n",space,table.nx);
printf("%s\t x0 = %g\n",space,table.x0);
printf("%s\t dx = %g\n",space,table.dx);
printf("%s\t ny = %d\n",space,table.ny);
printf("%s\t y0 = %g\n",space,table.y0);
printf("%s\t dy = %g\n",space,table.dy);
printf("%s\t label = %s\n",space,table.label);
printf("\n");
for(i=0;i<3;i++)
{
printf("%s\t [%d] ",space,i);
for (j=0;j<table.ny;j++)
printf("%g ",table.data[i][j]);
printf("\n");
}
printf("%s\t ...\n",space);
for(i=table.nx-3;i<table.nx;i++)
{
printf("%s\t [%d] ",space,i);
for (j=0;j<table.ny;j++)
printf("%g ",table.data[i][j]);
printf("\n");
}
printf("\n");
return 0;
}
int readLiveTimes(hid_t table,struct ChemistryLiveTimesStruct *livetimes)
{
hid_t group;
hid_t subgroup;
hid_t dset;
herr_t status;
group = H5Gopen(table, DATA_GRP,H5P_DEFAULT);
subgroup = H5Gopen(group,"LiveTimes",H5P_DEFAULT);
livetimes->coeff_z = readDatasetAsArray2DDouble_v0(subgroup,"coeff_z");
dset = H5Dopen( subgroup , "coeff_z", H5P_DEFAULT);
livetimes->nx = readAttributeAsInt(dset,"nx");
livetimes->ny = readAttributeAsInt(dset,"ny");
status = H5Dclose (dset);
status = H5Gclose (subgroup);
status = H5Gclose (group);
return 0;
}
/*! Print the content of an LiveTimes struct
*/
int printLiveTimes(struct ChemistryLiveTimesStruct livetimes)
{
int i,j;
printf("Output from LiveTimes:\n\n");
printf("\t coeff_z = \n");
for (i=0; i<livetimes.nx; i++) {
printf ("\t\t [");
for (j=0; j<livetimes.ny; j++)
printf (" %6.4f", livetimes.coeff_z[i][j]);
printf ("]\n");
}
printf("\n");
}
int readIMF(hid_t table,struct ChemistryIMFStruct *imf)
{
hid_t group;
hid_t subgroup;
herr_t status;
group = H5Gopen(table, DATA_GRP,H5P_DEFAULT);
subgroup = H5Gopen(group,"IMF",H5P_DEFAULT);
imf->Mmin = readAttributeAsDouble(subgroup,"Mmin");
imf->Mmax = readAttributeAsDouble(subgroup,"Mmax");
imf->n = readAttributeAsInt(subgroup,"n");
imf->ms = readAttributeAsArrayDouble(subgroup,"ms");
imf->as = readAttributeAsArrayDouble(subgroup,"as");
status = H5Gclose (subgroup);
status = H5Gclose (group);
return 0;
}
/*! Print the content of an IMF
*/
int printIMF(struct ChemistryIMFStruct imf)
{
int i;
printf("Output from IMF:\n\n");
printf("\t n = %d\n",imf.n);
printf("\t Mmin = %g\n",imf.Mmin);
printf("\t Mmax = %g\n",imf.Mmax);
printf("\t as = ");
for (i=0; i<imf.n+1; i++)
printf ("%g ",imf.as[i]);
printf ("\n");
//printf("\t bs = ");
//for (i=0; i<imf.n+1; i++)
// printf ("%g ",imf.bs[i]);
//printf ("\n");
printf("\t ms = ");
for (i=0; i<imf.n; i++)
printf ("%g ",imf.ms[i]);
printf ("\n");
printf("\n");
}
int readSNIa(hid_t table,struct ChemistrySNIaStruct *snia)
{
hid_t group;
hid_t subgroup;
herr_t status;
group = H5Gopen(table, DATA_GRP,H5P_DEFAULT);
subgroup = H5Gopen(group,"SNIa",H5P_DEFAULT);
snia->Mpl = readAttributeAsDouble(subgroup,"Mpl");
snia->Mpu = readAttributeAsDouble(subgroup,"Mpu");
snia->a = readAttributeAsDouble(subgroup,"a");
snia->Mdl1 = readAttributeAsDouble(subgroup,"Mdl1");
snia->Mdu1 = readAttributeAsDouble(subgroup,"Mdu1");
snia->bb1 = readAttributeAsDouble(subgroup,"bb1");
snia->Mdl2 = readAttributeAsDouble(subgroup,"Mdl2");
snia->Mdu2 = readAttributeAsDouble(subgroup,"Mdu2");
snia->bb2 = readAttributeAsDouble(subgroup,"bb2");
snia->Metals = readGroupAsElementsData(subgroup,"Metals");
status = H5Gclose (subgroup);
status = H5Gclose (group);
return 0;
}
/*! Print the content of an SNIa struct
*/
int printSNIa(struct ChemistrySNIaStruct snia)
{
int i;
printf("Output from SNIa:\n\n");
printf("\t Mpl = %g\n",snia.Mpl );
printf("\t Mpu = %g\n",snia.Mpu );
printf("\t a = %g\n",snia.a );
printf("\t Mdl1 = %g\n",snia.Mdl1);
printf("\t Mdu1 = %g\n",snia.Mdu1);
printf("\t bb1 = %g\n",snia.bb1 );
printf("\t Mdl2 = %g\n",snia.Mdl2);
printf("\t Mdu2 = %g\n",snia.Mdu2);
printf("\t bb2 = %g\n",snia.bb2 );
printf("\n");
printf("\t Metals:\n\n");
for (i=0; i<snia.Metals.nelts; i++)
printf ("\t\t %s\t= %g\n",snia.Metals.elts[i],snia.Metals.data[i]);
printf("\n");
}
int readSNII(hid_t table,struct ChemistrySNIIStruct *snii)
{
hid_t group;
hid_t subgroup;
herr_t status;
int i;
group = H5Gopen(table, DATA_GRP,H5P_DEFAULT);
subgroup = H5Gopen(group,"SNII",H5P_DEFAULT);
snii->Mmin = readAttributeAsDouble(subgroup,"Mmin");
snii->Mmax = readAttributeAsDouble(subgroup,"Mmax");
snii->npts = readAttributeAsInt(subgroup,"npts");
snii->nelts = readAttributeAsInt(subgroup,"nelts");
snii->elts = readAttributeAsArrayString(subgroup,"elts");
snii->table = malloc( snii->nelts * sizeof(struct ChemistryYieldsTableStruct) );
/* read the yields */
for(i=0;i<snii->nelts;i++)
snii->table[i]=readYieldsTable(subgroup,snii->elts[i]);
status = H5Gclose (subgroup);
status = H5Gclose (group);
return 0;
}
/*! Print the content of an SNII struct
*/
int printSNII(struct ChemistrySNIIStruct snii)
{
int i;
printf("Output from SNII:\n\n");
printf("\t Mmin = %g\n",snii.Mmin);
printf("\t Mmax = %g\n",snii.Mmax);
printf("\t npts = %d\n",snii.npts);
printf("\t nelts = %d\n",snii.nelts);
printf("\t elts = ");
for (i=0; i<snii.nelts; i++)
printf ("%s ",snii.elts[i]);
printf ("\n");
printf("\n");
printf("\t Metals:\n\n");
for(i=0;i<snii.nelts;i++)
printYieldsTable(snii.table[i],"\t\t");
}
int readDYIN(hid_t table,struct ChemistryDYINStruct *dyin)
{
hid_t group;
hid_t subgroup;
hid_t subsubgroup;
herr_t status;
int i;
group = H5Gopen(table, DATA_GRP,H5P_DEFAULT);
subgroup = H5Gopen(group,"DYIN",H5P_DEFAULT);
dyin->Mmin = readAttributeAsDouble(subgroup,"Mmin");
dyin->Mmax = readAttributeAsDouble(subgroup,"Mmax");
dyin->npts = readAttributeAsInt(subgroup,"npts");
dyin->nelts = readAttributeAsInt(subgroup,"nelts");
dyin->elts = readAttributeAsArrayString(subgroup,"elts");
dyin->table = malloc( dyin->nelts * sizeof(struct ChemistryYieldsTableStruct) );
/* read the yields */
for(i=0;i<dyin->nelts;i++)
dyin->table[i]=readYieldsTable(subgroup,dyin->elts[i]);
dyin->Zflag = readAttributeAsInt(subgroup,"Zflag");
if (dyin->Zflag==1)
{
/* read data with Z dependences */
subsubgroup = H5Gopen(subgroup,"MetallicityDependent",H5P_DEFAULT);
dyin->nptZs = readAttributeAsInt(subsubgroup,"nptZs");
dyin->tableZ = malloc( dyin->nelts * sizeof(struct ChemistryYieldsTable2DStruct) );
/* read the yields */
for(i=0;i<dyin->nelts;i++)
dyin->tableZ[i]=readYieldsTable2D(subsubgroup,dyin->elts[i]);
status = H5Gclose (subsubgroup);
/* end read data with Z dependences */
}
status = H5Gclose (subgroup);
status = H5Gclose (group);
return 0;
}
/*! Print the content of an DYIN struct
*/
int printDYIN(struct ChemistryDYINStruct dyin)
{
int i;
printf("Output from DYIN:\n\n");
printf("\t Mmin = %g\n",dyin.Mmin);
printf("\t Mmax = %g\n",dyin.Mmax);
printf("\t npts = %d\n",dyin.npts);
printf("\t nelts = %d\n",dyin.nelts);
if (dyin.Zflag==1)
printf("\t nptZs = %d\n",dyin.nptZs);
printf("\t elts = ");
for (i=0; i<dyin.nelts; i++)
printf ("%s ",dyin.elts[i]);
printf ("\n");
printf("\n");
printf("\t Metals:\n\n");
for(i=0;i<dyin.nelts;i++)
printYieldsTable(dyin.table[i],"\t\t");
if (dyin.Zflag==1)
{
printf("\t Metals Z:\n\n");
for(i=0;i<dyin.nelts;i++)
printYieldsTable2D(dyin.tableZ[i],"\t\t");
}
}
#endif // CHIMIE_FROM_HDF5
/********************************************************
endof hdf5 reading routines
*********************************************************/
static int verbose=0;
static double *MassFracSNII;
static double *MassFracSNIa;
static double *MassFracDYIN;
static double *SingleMassFracSNII;
static double *SingleMassFracSNIa;
static double *SingleMassFracDYIN;
static double *EjectedMass;
static double *SingleEjectedMass;
static double **MassFracSNIIs;
static double **MassFracSNIas;
static double **MassFracDYINs;
static double **SingleMassFracSNIIs;
static double **SingleMassFracSNIas;
static double **SingleMassFracDYINs;
static double **EjectedMasss;
static double **SingleEjectedMasss;
/* intern global variables */
static struct local_params_chimie
{
float coeff_z[3][3];
float Mmin,Mmax;
int n;
float ms[MAXPTS];
float as[MAXPTS+1];
float bs[MAXPTS+1];
float fs[MAXPTS];
double imf_Ntot;
#ifdef CHIMIE_OPTIMAL_SAMPLING
float k;
float m_max;
#endif
float SNII_Mmin;
float SNII_Mmax;
//float SNII_cte;
//float SNII_a;
float SNIa_Mpl;
float SNIa_Mpu;
float SNIa_a;
float SNIa_cte;
float SNIa_Mdl1;
float SNIa_Mdu1;
float SNIa_a1;
float SNIa_b1;
float SNIa_cte1;
float SNIa_bb1;
float SNIa_Mdl2;
float SNIa_Mdu2;
float SNIa_a2;
float SNIa_b2;
float SNIa_cte2;
float SNIa_bb2;
float SNIa_NWDN;
float DYIN_Mmin;
float DYIN_Mmax;
//float DYIN_cte;
//float DYIN_a;
float Mco;
int nptsSNII; /* number of division in mass SNII */
int nptsDYIN; /* number of division in mass DYIN */
int nptZsSNII; /* number of division in Z SNII */
int nptZsDYIN; /* number of division in Z DYIN */
int nelts;
int DYIN_Zflag;
float MassMinForEjecta;
}
*Cps,*Cp;
static struct local_elts_chimie
{
/* SNII */
float MminSNII; /* minimal mass */
float StepSNII; /* log of mass step */
float ArraySNII[MAXDATASIZE]; /* data */
float MetalSNII[MAXDATASIZE]; /* data */
/* DYIN */
float MminDYIN; /* minimal mass */
float StepDYIN; /* log of mass step */
float ArrayDYIN[MAXDATASIZE]; /* data */
float MetalDYIN[MAXDATASIZE]; /* data */
float MminZDYIN; /* minimal Z */
float StepZDYIN; /* step in Z */
float ArrayZDYIN[MAXDATASIZE][MAXDATAZSIZE]; /* data Z */
float MetalZDYIN[MAXDATASIZE][MAXDATAZSIZE]; /* data Z */
float MSNIa;
float SolarMassAbundance;
char label[72];
}
**Elts,*Elt;
/*! This function allocate all varaiables related to the chemistry
*/
void allocate_chimie()
{
int j;
/* allocate Cp */
Cps = malloc((All.ChimieNumberOfParameterFiles) * sizeof(struct local_params_chimie));
/* allocate elts */
Elts = malloc((All.ChimieNumberOfParameterFiles) * sizeof(struct local_elts_chimie));
//for (j=0;j<All.ChimieNumberOfParameterFiles;j++)
// Elt[j] = malloc((nelts) * sizeof(struct local_elts_chimie));
MassFracSNIIs = malloc((All.ChimieNumberOfParameterFiles) * sizeof(double));
MassFracSNIas = malloc((All.ChimieNumberOfParameterFiles) * sizeof(double));
MassFracDYINs = malloc((All.ChimieNumberOfParameterFiles) * sizeof(double));
EjectedMasss = malloc((All.ChimieNumberOfParameterFiles) * sizeof(double));
SingleMassFracSNIIs= malloc((All.ChimieNumberOfParameterFiles) * sizeof(double));
SingleMassFracSNIas= malloc((All.ChimieNumberOfParameterFiles) * sizeof(double));
SingleMassFracDYINs= malloc((All.ChimieNumberOfParameterFiles) * sizeof(double));
SingleEjectedMasss = malloc((All.ChimieNumberOfParameterFiles) * sizeof(double));
}
/*! Set the chemistry table to use
*/
void set_table(int i)
{
if (i>=All.ChimieNumberOfParameterFiles)
{
printf("\n set_table : i>= %d !!!\n\n",All.ChimieNumberOfParameterFiles);
endrun(88809);
}
else
{
Cp = &Cps[i];
Elt = Elts[i];
MassFracSNII = MassFracSNIIs[i]; /* all this is useless, no ?*/
MassFracSNIa = MassFracSNIas[i];
MassFracDYIN = MassFracDYINs[i];
SingleMassFracSNII = SingleMassFracSNIIs[i];
SingleMassFracSNIa = SingleMassFracSNIas[i];
SingleMassFracDYIN = SingleMassFracDYINs[i];
EjectedMass = EjectedMasss[i];
SingleEjectedMass = SingleEjectedMasss[i];
}
}
/*! Read the chemistry table (hdf5 format)
*/
#ifdef CHIMIE_FROM_HDF5
void read_chimie_h5(char * filename,int it)
{
hid_t table;
herr_t status;
struct ChemistryHeaderStruct ChemistryHeader;
struct ChemistryDataAttributesStruct ChemistryBasicParameters;
struct ChemistryLiveTimesStruct ChemistryLiveTimes;
struct ChemistryIMFStruct ChemistryIMF;
struct ChemistrySNIaStruct ChemistrySNIa;
struct ChemistrySNIIStruct ChemistrySNII;
struct ChemistryDYINStruct ChemistryDYIN;
table = H5Fopen(filename, H5F_ACC_RDONLY, H5P_DEFAULT);
readHeader(table,&ChemistryHeader);
if (verbose && ThisTask==0)
printHeader(ChemistryHeader);
readDataAttributes(table,&ChemistryBasicParameters);
if (verbose && ThisTask==0)
printDataAttributes(ChemistryBasicParameters);
readLiveTimes(table,&ChemistryLiveTimes);
if (verbose && ThisTask==0)
printLiveTimes(ChemistryLiveTimes);
readIMF(table,&ChemistryIMF);
if (verbose && ThisTask==0)
printIMF(ChemistryIMF);
readSNIa(table,&ChemistrySNIa);
if (verbose && ThisTask==0)
printSNIa(ChemistrySNIa);
readSNII(table,&ChemistrySNII);
if (verbose && ThisTask==0)
printSNII(ChemistrySNII);
readDYIN(table,&ChemistryDYIN);
if (verbose && ThisTask==0)
printDYIN(ChemistryDYIN);
status = H5Fclose(table);
Cps[it].MassMinForEjecta = MAX_REAL_NUMBER;
/* convert to chimie struct */
int i,j,k;
/* Livetimes */
for(i=0;i<3;i++)
for(j=0;j<3;j++)
Cps[it].coeff_z[i][j] = ChemistryLiveTimes.coeff_z[i][j];
/* IMF Parameters */
Cps[it].Mmin = ChemistryIMF.Mmin;
Cps[it].Mmax = ChemistryIMF.Mmax;
Cps[it].n = ChemistryIMF.n;
if (Cps[it].n>0)
for (i=0;i<Cps[it].n;i++)
Cps[it].ms[i] = ChemistryIMF.ms[i];
for (i=0;i<Cps[it].n+1;i++)
Cps[it].as[i]= ChemistryIMF.as[i];
/* Parameters for SNII Rates */
Cps[it].SNII_Mmin = ChemistrySNII.Mmin;
Cps[it].SNII_Mmax = ChemistrySNII.Mmax;
Cps[it].MassMinForEjecta = dmin(Cps[it].MassMinForEjecta,Cps[it].SNII_Mmin);
/* Parameters for DYIN Rates */
Cps[it].DYIN_Mmin = ChemistryDYIN.Mmin;
Cps[it].DYIN_Mmax = ChemistryDYIN.Mmax;
Cps[it].DYIN_Zflag= ChemistryDYIN.Zflag;
Cps[it].MassMinForEjecta = dmin(Cps[it].MassMinForEjecta,Cps[it].DYIN_Mmin);
/* Parameters for SNIa Rates */
Cps[it].SNIa_Mpl = ChemistrySNIa.Mpl;
Cps[it].SNIa_Mpu = ChemistrySNIa.Mpu;
Cps[it].SNIa_a = ChemistrySNIa.a;
Cps[it].SNIa_Mdl1 = ChemistrySNIa.Mdl1;
Cps[it].SNIa_Mdu1 = ChemistrySNIa.Mdu1;
Cps[it].SNIa_bb1 = ChemistrySNIa.bb1;
Cps[it].SNIa_Mdl2 = ChemistrySNIa.Mdl2;
Cps[it].SNIa_Mdu2 = ChemistrySNIa.Mdu2;
Cps[it].SNIa_bb2 = ChemistrySNIa.bb2;
Cps[it].MassMinForEjecta = dmin(Cps[it].MassMinForEjecta,Cps[it].SNIa_Mdl1);
Cps[it].MassMinForEjecta = dmin(Cps[it].MassMinForEjecta,Cps[it].SNIa_Mdl2);
/* Metal injection SNII */
Cps[it].nptsSNII = ChemistrySNII.npts;
//if (Cps[it].SNII_Zflag==1)
// Cps[it].nptZsSNII = ChemistrySNII.nptZs;
/* Metal injection DYIN */
Cps[it].nptsDYIN = ChemistryDYIN.npts;
if (Cps[it].DYIN_Zflag==1)
Cps[it].nptZsDYIN = ChemistryDYIN.nptZs;
Cps[it].nelts = ChemistryBasicParameters.nelts;
/* allocate memory for elts */
if ((Cps[it].nptsSNII<=MAXDATASIZE)&&(Cps[it].nptsDYIN<=MAXDATASIZE))
{
Elts[it] = malloc((Cps[it].nelts+2) * sizeof(struct local_elts_chimie));
}
else
{
printf("\n Cps[it].nptsSNII = %d > MAXDATASIZE = %d !!!\n\n",Cps[it].nptsSNII,MAXDATASIZE);
printf("\n Cps[it].nptsDYIN = %d > MAXDATASIZE = %d !!!\n\n",Cps[it].nptsDYIN,MAXDATASIZE);
endrun(88800);
}
/* allocate memory */
MassFracSNIIs[it] = malloc((Cps[it].nelts+2) * sizeof(double)); /* really needed ? */
MassFracSNIas[it] = malloc((Cps[it].nelts+2) * sizeof(double));
MassFracDYINs[it] = malloc((Cps[it].nelts+2) * sizeof(double));
EjectedMasss[it] = malloc((Cps[it].nelts+2) * sizeof(double));
SingleMassFracSNIIs[it] = malloc((Cps[it].nelts+2) * sizeof(double));
SingleMassFracSNIas[it] = malloc((Cps[it].nelts+2) * sizeof(double));
SingleMassFracDYINs[it] = malloc((Cps[it].nelts+2) * sizeof(double));
SingleEjectedMasss[it] = malloc((Cps[it].nelts+2) * sizeof(double));
/**/
/* injected metals SNII */
/**/
for (i=0;i<Cps[it].nelts+2;i++)
{
//printf("%s\n",ChemistrySNII.table[i].label);
strcpy(Elts[it][i].label,ChemistrySNII.table[i].label);
Elts[it][i].MminSNII = ChemistrySNII.table[i].min;
Elts[it][i].StepSNII = ChemistrySNII.table[i].step;
for (j=0;j<Cps[it].nptsSNII;j++)
Elts[it][i].MetalSNII[j] = ChemistrySNII.table[i].data[j];
}
/* integral of injected metals SNII */
for (i=0;i<Cps[it].nelts+2;i++)
{
//printf("%s\n",ChemistrySNII.table[i+Cps[it].nelts+2].label);
for (j=0;j<Cps[it].nptsSNII;j++)
Elts[it][i].ArraySNII[j] = ChemistrySNII.table[i+Cps[it].nelts+2].data[j];
}
/**/
/* injected metals DYIN */
/**/
for (i=0;i<Cps[it].nelts+2;i++)
{
//printf("%s\n",ChemistryDYIN.table[i].label);
strcpy(Elts[it][i].label,ChemistryDYIN.table[i].label);
Elts[it][i].MminDYIN = ChemistryDYIN.table[i].min;
Elts[it][i].StepDYIN = ChemistryDYIN.table[i].step;
for (j=0;j<Cps[it].nptsDYIN;j++)
Elts[it][i].MetalDYIN[j] = ChemistryDYIN.table[i].data[j];
}
/* integral of injected metals DYIN */
for (i=0;i<Cps[it].nelts+2;i++)
{
//printf("%s\n",ChemistryDYIN.table[i+Cps[it].nelts+2].label);
for (j=0;j<Cps[it].nptsDYIN;j++)
Elts[it][i].ArrayDYIN[j] = ChemistryDYIN.table[i+Cps[it].nelts+2].data[j];
}
/* metallicity dependent table */
if (Cps[it].DYIN_Zflag==1)
{
for (i=0;i<Cps[it].nelts+2;i++)
{
Elts[it][i].MminZDYIN = ChemistryDYIN.tableZ[i].y0;
Elts[it][i].StepZDYIN = ChemistryDYIN.tableZ[i].dy;
for (j=0;j<Cps[it].nptsDYIN;j++)
for (k=0;k<Cps[it].nptZsDYIN;k++)
{
Elts[it][i].MetalZDYIN[j][k] = ChemistryDYIN.tableZ[i].data[j][k];
Elts[it][i].ArrayZDYIN[j][k] = ChemistryDYIN.tableZ[i+Cps[it].nelts+2].data[j][k];
}
}
}
/* Metal injection SNIa */
Cps[it].Mco = ChemistryBasicParameters.MeanWDMass;
/* for each elt in */
for (i=0;i<Cps[it].nelts+2;i++)
{
if (strcmp(Elts[it][i].label,ChemistrySNIa.Metals.elts[i])!=0)
{
printf("%s != %s\n",Elts[it][i].label,ChemistrySNIa.Metals.elts[i]);
endrun(888012);
}
Elts[it][i].MSNIa = ChemistrySNIa.Metals.data[i];
}
/* Solar Mass Abundances */
for (i=0;i<Cps[it].nelts;i++)
{
if (strcmp(Elts[it][i+2].label,ChemistryBasicParameters.elts[i])!=0)
{
printf("%s != %s\n",Elts[it][i+2].label,ChemistryBasicParameters.elts[i]);
endrun(888013);
}
Elts[it][i+2].SolarMassAbundance = ChemistryBasicParameters.SolarMassAbundances[i];
}
//if (verbose && ThisTask==0)
// info(it);
}
#endif // CHIMIE_FROM_HDF5
/*! Read the chemistry table
*/
void read_chimie(char * filename,int it)
{
char line[72],buffer[72];
FILE *fd;
int i,j;
if (verbose && ThisTask==0)
printf("reading %s ...\n",filename);
fd = fopen(filename,"r");
/* read Lifetime */
/* #### Livetime #### */
fgets(line, sizeof(line), fd);
fgets(line, sizeof(line), fd);
fscanf(fd, "%g %g %g\n", &Cps[it].coeff_z[0][0],&Cps[it].coeff_z[0][1],&Cps[it].coeff_z[0][2]);
fscanf(fd, "%g %g %g\n", &Cps[it].coeff_z[1][0],&Cps[it].coeff_z[1][1],&Cps[it].coeff_z[1][2]);
fscanf(fd, "%g %g %g\n", &Cps[it].coeff_z[2][0],&Cps[it].coeff_z[2][1],&Cps[it].coeff_z[2][2]);
fgets(line, sizeof(line), fd);
/* IMF Parameters */
/* #### IMF Parameters #### */
fgets(line, sizeof(line), fd);
fscanf(fd, "%g %g\n",&Cps[it].Mmin,&Cps[it].Mmax);
fscanf(fd, "%d\n",&Cps[it].n);
if (Cps[it].n>0)
for (i=0;i<Cps[it].n;i++)
fscanf(fd,"%g",&Cps[it].ms[i]);
else
fgets(line, sizeof(line), fd);
for (i=0;i<Cps[it].n+1;i++)
fscanf(fd,"%g",&Cps[it].as[i]);
fgets(line, sizeof(line), fd);
/* Parameters for SNII Rates */
/* #### SNII Parameters #### */
fgets(line, sizeof(line), fd);
fgets(line, sizeof(line), fd);
fscanf(fd, "%g \n",&Cps[it].SNII_Mmin);
fgets(line, sizeof(line), fd);
/* Parameters for SNIa Rates */
/* #### SNIa Parameters #### */
fgets(line, sizeof(line), fd);
fscanf(fd, "%g %g\n",&Cps[it].SNIa_Mpl,&Cps[it].SNIa_Mpu);
fscanf(fd, "%g \n",&Cps[it].SNIa_a);
fscanf(fd, "%g %g %g\n",&Cps[it].SNIa_Mdl1,&Cps[it].SNIa_Mdu1,&Cps[it].SNIa_bb1);
fscanf(fd, "%g %g %g\n",&Cps[it].SNIa_Mdl2,&Cps[it].SNIa_Mdu2,&Cps[it].SNIa_bb2);
fgets(line, sizeof(line), fd);
/* Metal injection SNII */
/* #### Metal Parameters ####*/
fgets(line, sizeof(line), fd);
fgets(line, sizeof(line), fd);
fscanf(fd, "%d %d\n",&Cps[it].nptsSNII,&Cps[it].nelts);
/* allocate memory for elts */
if (Cps[it].nptsSNII<=MAXDATASIZE)
{
Elts[it] = malloc((Cps[it].nelts+2) * sizeof(struct local_elts_chimie));
}
else
{
printf("\n Cps[it].nptsSNII = %d > MAXDATASIZE = %d !!!\n\n",Cps[it].nptsSNII,MAXDATASIZE);
endrun(88800);
}
/* allocate memory */
MassFracSNIIs[it] = malloc((Cps[it].nelts+2) * sizeof(double)); /* really needed ? */
MassFracSNIas[it] = malloc((Cps[it].nelts+2) * sizeof(double));
MassFracDYINs[it] = malloc((Cps[it].nelts+2) * sizeof(double));
EjectedMasss[it] = malloc((Cps[it].nelts+2) * sizeof(double));
SingleMassFracSNIIs[it] = malloc((Cps[it].nelts+2) * sizeof(double));
SingleMassFracSNIas[it] = malloc((Cps[it].nelts+2) * sizeof(double));
SingleMassFracDYINs[it] = malloc((Cps[it].nelts+2) * sizeof(double));
SingleEjectedMasss[it] = malloc((Cps[it].nelts+2) * sizeof(double));
/* injected metals */
for (i=0;i<Cps[it].nelts+2;i++)
{
fgets(line, sizeof(line), fd);
/* strip trailing line */
for (j = 0; j < strlen(line); j++)
if ( line[j] == '\n' || line[j] == '\r' )
line[j] = '\0';
/* copy labels */
strcpy(Elts[it][i].label,line);
/* probleme */
strcpy(buffer,&Elts[it][i].label[2]);
strcpy(Elts[it][i].label,buffer);
fgets(line, sizeof(line), fd);
fscanf(fd, "%g %g\n",&Elts[it][i].MminSNII,&Elts[it][i].StepSNII);
for (j=0;j<Cps[it].nptsSNII;j++)
{
fscanf(fd, "%g\n",&Elts[it][i].MetalSNII[j]);
}
}
/* integrals of injected metals */
fgets(line, sizeof(line), fd);
fgets(line, sizeof(line), fd);
fscanf(fd, "%d %d\n",&Cps[it].nptsSNII,&Cps[it].nelts);
fgets(line, sizeof(line), fd);
fgets(line, sizeof(line), fd);
/* integrals of injected metals */
for (i=0;i<Cps[it].nelts+2;i++)
{
fgets(line, sizeof(line), fd);
fgets(line, sizeof(line), fd);
fscanf(fd, "%g %g\n",&Elts[it][i].MminSNII,&Elts[it][i].StepSNII);
for (j=0;j<Cps[it].nptsSNII;j++)
{
fscanf(fd, "%g\n",&Elts[it][i].ArraySNII[j]);
}
}
/* Metal injection SNIa */
fgets(line, sizeof(line), fd);
fgets(line, sizeof(line), fd);
fscanf(fd, "%g\n",&Cps[it].Mco);
fgets(line, sizeof(line), fd);
fgets(line, sizeof(line), fd);
fgets(line, sizeof(line), fd);
int nelts;
char label[72];
fscanf(fd, "%d\n",&nelts);
/* check */
if (nelts != Cps[it].nelts)
{
printf("\nThe number of elements in SNII (=%d) is not identical to the on of SNIa (=%d) !!!\n\n",Cps[it].nelts,nelts);
printf("This is not supported by the current implementation !!!\n");
endrun(88805);
}
for (i=0;i<Cps[it].nelts+2;i++)
{
fgets(line, sizeof(line), fd); /* label */
/* check label */
/* strip trailing line */
for (j = 0; j < strlen(line); j++)
if ( line[j] == '\n' || line[j] == '\r' )
line[j] = '\0';
strcpy(label,line);
strcpy(buffer,&label[2]);
strcpy(label,buffer);
if (strcmp(label,Elts[it][i].label)!=0)
{
printf("\nLabel of SNII element %d (=%s) is different from the SNIa one (=%s) !!!\n\n",i,Elts[it][i].label,label);
endrun(88806);
}
//fgets(line, sizeof(line), fd);
fscanf(fd, "%g\n",&Elts[it][i].MSNIa);
}
/* Solar Mass Abundances */
fgets(line, sizeof(line), fd);
fgets(line, sizeof(line), fd);
fgets(line, sizeof(line), fd);
fgets(line, sizeof(line), fd);
fscanf(fd, "%d\n",&nelts);
/* check */
if (nelts != Cps[it].nelts)
{
printf("\nThe number of elements in SolarMassAbundances (=%d) is not identical to the on of SNIa (=%d) !!!\n\n",Cps[it].nelts,nelts);
printf("This is not supported by the current implementation !!!\n");
endrun(88805);
}
for (i=0;i<Cps[it].nelts;i++)
{
fgets(line, sizeof(line), fd); /* label */
/* check label */
/* strip trailing line */
for (j = 0; j < strlen(line); j++)
if ( line[j] == '\n' || line[j] == '\r' )
line[j] = '\0';
strcpy(label,line);
strcpy(buffer,&label[2]);
strcpy(label,buffer);
if (strcmp(label,Elts[it][i+2].label)!=0)
{
printf("\nLabel of SNII element %d (=%s) is different from the SNIa one (=%s) !!!\n\n",i,Elts[it][i+2].label,label);
endrun(88806);
}
//fgets(line, sizeof(line), fd);
fscanf(fd, "%g\n",&Elts[it][i+2].SolarMassAbundance);
}
fclose(fd);
if (verbose && ThisTask==0)
info(it);
}
/*! This function returns the mass fraction of a star of mass m
* using the current IMF
*/
static double get_imf(double m)
{
int i;
int n;
n = Cp->n;
/* convert m in msol */
m = m*All.CMUtoMsol;
if (n==0)
return Cp->bs[0]* pow(m,Cp->as[0]);
else
{
for (i=0;i<n;i++)
if (m < Cp->ms[i])
return Cp->bs[i]* pow(m,Cp->as[i]);
return Cp->bs[n]* pow(m,Cp->as[n]);
}
}
/*! This function returns the mass fraction between m1 and m2
* per mass unit, using the current IMF
*/
static double get_imf_M(double m1, double m2)
{
int i;
int n;
double p;
double integral=0;
double mmin,mmax;
n = Cp->n;
/* convert m in msol */
m1 = m1*All.CMUtoMsol;
m2 = m2*All.CMUtoMsol;
if (n==0)
{
p = Cp->as[0]+1;
integral = (Cp->bs[0]/p) * ( pow(m2,p) - pow(m1,p) );
//printf("--> %g %g %g %g int=%g\n",m1,m2,pow(m2,p), pow(m1,p),integral);
}
else
{
integral = 0;
/* first */
if (m1<Cp->ms[0])
{
mmin = m1;
mmax = dmin(Cp->ms[0],m2);
p = Cp->as[0] + 1;
integral += (Cp->bs[0]/p) * ( pow(mmax,p) - pow(mmin,p) );
}
/* last */
if (m2>Cp->ms[n-1])
{
mmin = dmax(Cp->ms[n-1],m1);
mmax = m2;
p = Cp->as[n] + 1;
integral += (Cp->bs[n]/p) * ( pow(mmax,p) - pow(mmin,p) );
}
/* loop over other segments */
for (i=0;i<n-1;i++)
{
mmin = dmax(Cp->ms[i ],m1);
mmax = dmin(Cp->ms[i+1],m2);
if (mmin<mmax)
{
p = Cp->as[i+1] + 1;
integral += (Cp->bs[i+1]/p) * ( pow(mmax,p) - pow(mmin,p) );
}
}
}
return integral;
}
/*! This function returns the number fraction between m1 and m2
* per mass unit, using the current IMF
*/
static double get_imf_N(double m1, double m2)
{
int i;
int n;
double p;
double integral=0;
double mmin,mmax;
n = Cp->n;
/* convert m in msol */
m1 = m1*All.CMUtoMsol;
m2 = m2*All.CMUtoMsol;
if (n==0)
{
p = Cp->as[0];
integral = (Cp->bs[0]/p) * ( pow(m2,p) - pow(m1,p) );
}
else
{
integral = 0;
/* first */
if (m1<Cp->ms[0])
{
mmin = m1;
mmax = dmin(Cp->ms[0],m2);
p = Cp->as[0];
integral += (Cp->bs[0]/p) * ( pow(mmax,p) - pow(mmin,p) );
}
/* last */
if (m2>Cp->ms[n-1])
{
mmin = dmax(Cp->ms[n-1],m1);
mmax = m2;
p = Cp->as[n];
integral += (Cp->bs[n]/p) * ( pow(mmax,p) - pow(mmin,p) );
}
/* loop over other segments */
for (i=0;i<n-1;i++)
{
mmin = dmax(Cp->ms[i ],m1);
mmax = dmin(Cp->ms[i+1],m2);
if (mmin<mmax)
{
p = Cp->as[i+1];
integral += (Cp->bs[i+1]/p) * ( pow(mmax,p) - pow(mmin,p) );
}
}
}
/* convert into mass unit mass unit */
integral = integral *All.CMUtoMsol;
return integral;
}
/*! Sample the imf using monte carlo approach
*/
static double imf_sampling()
{
int i;
int n;
double m;
double f;
double pmin,pmax;
n = Cp->n;
/* init random */
//srandom(irand);
f = (double)random()/(double)RAND_MAX;
if (n==0)
{
pmin = pow(Cp->Mmin,Cp->as[0]);
pmax = pow(Cp->Mmax,Cp->as[0]);
m = pow(f*(pmax - pmin) + pmin ,1./Cp->as[0]);
return m* All.MsoltoCMU;
}
else
{
if (f<Cp->fs[0])
{
pmin = pow(Cp->Mmin ,Cp->as[0]);
m = pow(Cp->imf_Ntot*Cp->as[0]/Cp->bs[0]* (f-0) + pmin ,1./Cp->as[0]);
return m* All.MsoltoCMU;
}
for (i=0;i<n-1;i++)
{
if (f<Cp->fs[i+1])
{
pmin = pow(Cp->ms[i] ,Cp->as[i+1]);
m = pow(Cp->imf_Ntot*Cp->as[i+1]/Cp->bs[i+1]* (f-Cp->fs[i]) + pmin ,1./Cp->as[i+1]);
return m* All.MsoltoCMU;
}
}
/* last portion */
pmin = pow(Cp->ms[n-1] ,Cp->as[n]);
m = pow(Cp->imf_Ntot*Cp->as[n]/Cp->bs[n]* (f-Cp->fs[n-1]) + pmin ,1./Cp->as[n]);
return m* All.MsoltoCMU;
}
}
static double imf_sampling_from_random(double f)
{
int i;
int n;
double m;
double pmin,pmax;
n = Cp->n;
if (n==0)
{
pmin = pow(Cp->Mmin,Cp->as[0]);
pmax = pow(Cp->Mmax,Cp->as[0]);
m = pow(f*(pmax - pmin) + pmin ,1./Cp->as[0]);
return m* All.MsoltoCMU;
}
else
{
if (f<Cp->fs[0])
{
pmin = pow(Cp->Mmin ,Cp->as[0]);
m = pow(Cp->imf_Ntot*Cp->as[0]/Cp->bs[0]* (f-0) + pmin ,1./Cp->as[0]);
return m* All.MsoltoCMU;
}
for (i=0;i<n-1;i++)
{
if (f<Cp->fs[i+1])
{
pmin = pow(Cp->ms[i] ,Cp->as[i+1]);
m = pow(Cp->imf_Ntot*Cp->as[i+1]/Cp->bs[i+1]* (f-Cp->fs[i]) + pmin ,1./Cp->as[i+1]);
return m* All.MsoltoCMU;
}
}
/* last portion */
pmin = pow(Cp->ms[n-1] ,Cp->as[n]);
m = pow(Cp->imf_Ntot*Cp->as[n]/Cp->bs[n]* (f-Cp->fs[n-1]) + pmin ,1./Cp->as[n]);
return m* All.MsoltoCMU;
}
}
/*! This function initializes the imf parameters
defined in the chemistry file
*/
void init_imf(void)
{
float integral = 0;
float p;
float cte;
int i,n;
double mmin,mmax;
n = Cp->n;
if (n==0)
{
p = Cp->as[0]+1;
integral = integral + ( pow(Cp->Mmax,p)-pow(Cp->Mmin,p))/(p) ;
Cp->bs[0] = 1./integral ;
}
else
{
cte = 1.0;
if (Cp->Mmin < Cp->ms[0])
{
p = Cp->as[0]+1;
integral = integral + (pow(Cp->ms[0],p) - pow(Cp->Mmin,p))/p;
}
for (i=0;i<n-1;i++)
{
cte = cte* pow( Cp->ms[i],( Cp->as[i] - Cp->as[i+1] ));
p = Cp->as[i+1]+1;
integral = integral + cte*(pow(Cp->ms[i+1],p) - pow(Cp->ms[i],p))/p;
}
if (Cp->Mmax > Cp->ms[-1])
{
cte = cte* pow( Cp->ms[n-1] , ( Cp->as[n-1] - Cp->as[n] ) );
p = Cp->as[n]+1;
integral = integral + cte*(pow(Cp->Mmax,p) - pow(Cp->ms[n-1],p))/p;
}
/* compute all b */
Cp->bs[0] = 1./integral;
for (i=0;i<n;i++)
{
Cp->bs[i+1] = Cp->bs[i] * pow( Cp->ms[i],( Cp->as[i] - Cp->as[i+1] ));
}
}
//if (verbose && ThisTask==0)
// {
// printf("-- bs -- \n");
// for (i=0;i<n+1;i++)
// printf("%g ",Cp->bs[i]);
// printf("\n");
// }
mmin = Cp->Mmin *All.MsoltoCMU; /* in CMU */
mmax = Cp->Mmax *All.MsoltoCMU; /* in CMU */
Cp->imf_Ntot = get_imf_N(mmin,mmax) *All.MsoltoCMU; /* in CMU */
/* init fs : mass fraction at ms */
if (n>0)
{
for (i=0;i<n+1;i++)
{
mmax = Cp->ms[i] *All.MsoltoCMU; /* in CMU */
Cp->fs[i] = All.MsoltoCMU*get_imf_N(mmin,mmax)/Cp->imf_Ntot;
}
}
}
#ifdef CHIMIE_OPTIMAL_SAMPLING
/*
integral of m\xi with the kroupa normalisation ( in k)
input : mass in Msol
*/
double imf_int_mxi(double left,double right, double k)
{
return get_imf_M(left*All.MsoltoCMU,right*All.MsoltoCMU)/(Cp->bs[0])*k;
}
/*
integral of \xi with the kroupa normalisation ( in k)
input : mass in Msol
*/
double imf_int_xi(double left,double right, double k)
{
return get_imf_N(left*All.MsoltoCMU,right*All.MsoltoCMU)/ (Cp->bs[0]*All.CMUtoMsol) * k;
}
/*
compute the normalisation and the maximum stellar mass
i.e, Cp->k and Cp->m_max
input : mass in Msol
output : mass in Msol
*/
double optimal_init_norm(double Mecl)
{
double a,b,c;
double mb;
double Mmax;
Mmax = Cp->Mmax;
Cp->k = 1.; /* kroupa normalisation */
//we use 150Msun for the maximum possible stellar mass (TODO: put it as a parameter)
a = Cp->Mmin;
c = Mmax;
b = (c+a)/2.;
//solve the two equations to find m_max and k iteratively
while(((c/b)-(a/b)) > 0.00001)
{
mb = imf_int_mxi(Cp->Mmin,b,Cp->k)/imf_int_xi(b,Mmax,Cp->k)+b;
if(mb < Mecl)
a = b;
else
c = b;
b = (c+a)/2;
}
//store the results
Cp->m_max = b;
Cp->k = (Mecl-Cp->m_max) / imf_int_mxi(Cp->Mmin,Cp->m_max,Cp->k);
return Cp->m_max;
}
/*
compute the normalisation and the maximum stellar mass
for one single stellar particle
output in StP[m].OptIMF_CurrentMass, in Msol
*/
double init_optimal_imf_sampling(int i)
{
double a,b,c;
double mb;
double Mmax;
double Mecl;
int m;
m = P[i].StPIdx;
Mmax = Cp->Mmax;
Mecl = StP[m].InitialMass*All.CMUtoMsol; /* to Msol */
StP[m].OptIMF_k = 1.; /* kroupa normalisation */
StP[m].OptIMF_N_WD = 0;
//we use 150Msun for the maximum possible stellar mass (TODO: put it as a parameter)
a = Cp->Mmin;
c = Mmax;
b = (c+a)/2.;
//solve the two equations to find m_max and k iteratively
while(((c/b)-(a/b)) > 0.00001)
{
mb = imf_int_mxi(Cp->Mmin,b,StP[m].OptIMF_k)/imf_int_xi(b,Mmax,StP[m].OptIMF_k)+b;
if(mb < Mecl)
a = b;
else
c = b;
b = (c+a)/2;
}
//store the results
StP[m].OptIMF_m_max = b;
StP[m].OptIMF_k = (Mecl-StP[m].OptIMF_m_max) / imf_int_mxi(Cp->Mmin,StP[m].OptIMF_m_max,StP[m].OptIMF_k);
StP[m].OptIMF_CurrentMass = StP[m].OptIMF_m_max;
return StP[m].OptIMF_m_max;
}
/*
compute the next mass given the previous
input : mass in Msol
output : mass in Msol
*/
double optimal_get_next_mass(double m){
double a,b,c,mb;
const double err = 1.e-8;
a = Cp->Mmin;
c = m;
b = (c+a)/2;
mb = imf_int_mxi(b,m,Cp->k);
while(fabs((mb-b)/mb) > err)
{
mb = imf_int_mxi(b,m,Cp->k);
if(mb < b)
c = b;
else
a = b;
b = (c+a)/2;
}
return b;
}
/*
comute the next mass given the previous,
according to the imf of a given particle
output : mass in Msol
*/
double optimal_get_next_mass_for_one_particle(int j){
double a,b,c,mb;
const double err = 1.e-8;
double m;
m = StP[j].OptIMF_CurrentMass;
a = Cp->Mmin;
c = m;
b = (c+a)/2;
mb = imf_int_mxi(b,m,StP[j].OptIMF_k);
while(fabs((mb-b)/mb) > err)
{
mb = imf_int_mxi(b,m,StP[j].OptIMF_k);
if(mb < b)
c = b;
else
a = b;
b = (c+a)/2;
}
return b;
}
/*
stop the imf loop
input : mass in Msol
*/
int optimal_stop_loop(double m)
{
int bool;
if(imf_int_mxi(Cp->Mmin,m,Cp->k) < Cp->Mmin)
bool = 1;
else
bool = 0;
return bool;
}
/*
find m1 such as the stellar mass, according to the IMF, between m1 and m2 is mp.
input : masses in Msol
*/
double optimal_get_m1_from_m2(double m2, double mp)
{
double a,b,c;
double m1,mb;
a = Cp->Mmin;
c = m2;
b = (c+a)/2.;
//solve the two equations to find m_max and k iteratively
while(((c/b)-(a/b)) > 0.00001)
{
mb = imf_int_mxi(b,m2,Cp->k);
if(mb < mp)
c = b;
else
a = b;
b = (c+a)/2;
}
//store the results
m1 = b;
return m1;
}
float optimal_get_k_normalisation_factor()
{
return Cp->k;
}
#endif /* CHIMIE_OPTIMAL_SAMPLING */
/*! This function initializes the chemistry parameters
*/
void init_chimie(void)
{
int i,nf;
double u_lt;
double UnitLength_in_kpc;
double UnitMass_in_Msol;
char filename[500];
char ext[100];
/* check some flags */
#ifndef COSMICTIME
if (All.ComovingIntegrationOn)
{
if(ThisTask == 0)
printf("Code wasn't compiled with COSMICTIME support enabled!\n");
endrun(-88800);
}
#endif
#ifdef CHIMIE_AGB
if(ThisTask == 0)
printf("AGB is enabled\n");
#else
if(ThisTask == 0)
printf("AGB is disabled\n");
#endif
UnitLength_in_kpc = All.UnitLength_in_cm / KPC_IN_CM;
UnitMass_in_Msol = All.UnitMass_in_g / SOLAR_MASS;
//u_lt = -log10( 4.7287e11*sqrt(pow(UnitLength_in_kpc,3)/UnitMass_in_Msol));
/*Sat Dec 25 23:27:10 CET 2010 */
u_lt = -log10(All.UnitTime_in_Megayears*1e6);
allocate_chimie();
for (nf=0;nf<All.ChimieNumberOfParameterFiles;nf++)
{
if (All.ChimieNumberOfParameterFiles==1)
sprintf(filename,"%s",All.ChimieParameterFile);
else
sprintf(filename,"%s.%d",All.ChimieParameterFile,nf);
/* check the file extension and read */
#ifdef CHIMIE_FROM_HDF5
if ( (strcmp("h5",get_filename_ext(filename))==0) || (strcmp("hdf5",get_filename_ext(filename))==0))
read_chimie_h5(filename,nf);
else
#endif //CHIMIE_FROM_HDF5
read_chimie(filename,nf);
/* set the table */
set_table(nf);
/* Conversion into program time unit */
Cp->coeff_z[2][2] = Cp->coeff_z[2][2] + u_lt;
for (i=0;i<3;i++)
Cp->coeff_z[1][i] = Cp->coeff_z[1][i]/2.0;
/* init imf parameters */
init_imf();
/* init SNII parameters */
//if (Cp->n==0)
// {
// //Cp->SNII_cte[0] = Cp->bs[0]/Cp->as[0];
// Cp->SNII_cte = Cp->bs[0]/Cp->as[0];
// Cp->SNII_a = Cp->as[0];
// }
//else
// {
// //for (i=0;i<Cp->n+1;i++) /* if multiple power law in the SNII mass range */
// // Cp->SNII_cte[i] = Cp->bs[i]/Cp->as[i];
// Cp->SNII_cte = Cp->bs[Cp->n]/Cp->as[Cp->n];
// Cp->SNII_a = Cp->as[Cp->n];
// }
/* init DYIN parameters */
//if (Cp->n==0)
// {
// //Cp->DYIN_cte[0] = Cp->bs[0]/Cp->as[0];
// Cp->DYIN_cte = Cp->bs[0]/Cp->as[0];
// Cp->DYIN_a = Cp->as[0];
// }
//else
// {
// //for (i=0;i<Cp->n+1;i++) /* if multiple power law in the DYIN mass range */
// // Cp->DYIN_cte[i] = Cp->bs[i]/Cp->as[i];
// Cp->DYIN_cte = Cp->bs[Cp->n]/Cp->as[Cp->n];
// Cp->DYIN_a = Cp->as[Cp->n];
// }
/* init SNIa parameters */
Cp->SNIa_a1 = Cp->SNIa_a;
Cp->SNIa_b1 = (Cp->SNIa_a1+1)/(pow(Cp->SNIa_Mdu1,Cp->SNIa_a1+1)-pow(Cp->SNIa_Mdl1,Cp->SNIa_a1+1));
Cp->SNIa_cte1 = Cp->SNIa_b1/Cp->SNIa_a1;
Cp->SNIa_a2 = Cp->SNIa_a;
Cp->SNIa_b2 = (Cp->SNIa_a2+1)/(pow(Cp->SNIa_Mdu2,Cp->SNIa_a2+1)-pow(Cp->SNIa_Mdl2,Cp->SNIa_a2+1));
Cp->SNIa_cte2 = Cp->SNIa_b2/Cp->SNIa_a2;
/* init SNIa parameters */
if (Cp->n==0)
{
Cp->SNIa_cte = Cp->bs[0]/Cp->as[0];
Cp->SNIa_a = Cp->as[0];
}
else
{
Cp->SNIa_cte = Cp->bs[Cp->n]/Cp->as[Cp->n];
Cp->SNIa_a = Cp->as[Cp->n];
}
//for (i=0;i<Cp->nelts+2;i++)
// Elt[i].MminSNII = log10(Elt[i].MminSNII);
//
//for (i=0;i<Cp->nelts+2;i++)
// Elt[i].MminDYIN = log10(Elt[i].MminDYIN);
/* output info */
//if (verbose && ThisTask==0)
// {
// //printf("-- SNII_cte -- \n");
// //for (i=0;i<Cp->n+1;i++)
// // printf("%g ",Cp->SNII_cte[i]);
// //printf("%g ",Cp->SNII_cte);
//
// printf("\n");
//}
/* output info */
//if (verbose && ThisTask==0)
// {
// printf("-- DYIN_cte -- \n");
// //for (i=0;i<Cp->n+1;i++)
// // printf("%g ",Cp->DYIN_cte[i]);
// //printf("%g ",Cp->DYIN_cte);
//
// printf("\n");
// }
/* check that the masses are higher than the last IMF elbow */
if (Cp->n>0)
{
if (Cp->SNIa_Mpl < Cp->ms[Cp->n-1])
{
printf("\nSNIa_Mpl = %g < ms[n-1] = %g !!!\n\n",Cp->SNIa_Mpl,Cp->ms[Cp->n-1]);
printf("This is not supported by the current implementation !!!\n");
endrun(88801);
}
if (Cp->SNIa_Mpu < Cp->ms[Cp->n-1])
{
printf("\nSNIa_Mpu = %g < ms[n-1] = %g !!!\n\n",Cp->SNIa_Mpu,Cp->ms[Cp->n-1]);
printf("This is not supported by the current implementation !!!\n");
endrun(88802);
}
if (Cp->SNII_Mmin < Cp->ms[Cp->n-1])
{
printf("\nSNII_Mmin = %g < ms[n-1] = %g !!!\n\n",Cp->SNII_Mmin,Cp->ms[Cp->n-1]);
printf("This is not supported by the current implementation !!!\n");
endrun(88803);
}
if (Cp->SNII_Mmax < Cp->ms[Cp->n-1])
{
printf("\nSNII_Mmax = %g < ms[n-1] = %g !!!\n\n",Cp->SNII_Mmax,Cp->ms[Cp->n-1]);
printf("This is not supported by the current implementation !!!\n");
endrun(88804);
}
if (Cp->DYIN_Mmin < Cp->ms[Cp->n-1])
{
printf("\nDYIN_Mmin = %g < ms[n-1] = %g !!!\n\n",Cp->DYIN_Mmin,Cp->ms[Cp->n-1]);
printf("This is not supported by the current implementation !!!\n");
endrun(88805);
}
if (Cp->DYIN_Mmax < Cp->ms[Cp->n-1])
{
printf("\nDYIN_Mmax = %g < ms[n-1] = %g !!!\n\n",Cp->DYIN_Mmax,Cp->ms[Cp->n-1]);
printf("This is not supported by the current implementation !!!\n");
endrun(88806);
}
}
/* number of WD per solar mass */
Cp->SNIa_NWDN = Cp->SNIa_cte * ( pow(Cp->SNIa_Mpu,Cp->SNIa_a)-pow(Cp->SNIa_Mpl,Cp->SNIa_a) );
}
/*
init short cuts to some elements
*/
FE = get_ElementIndex("Fe");
METALS = get_ElementIndex("Metals");
/* write chime stat header */
#ifdef CHIMIE_STATS
int k;
fprintf(FdChimieStatsSNs,"# ThisTask TimeStep Time ID Mass NSNII NSNIa MassSN x y z ");
fprintf(FdChimieStatsSNs,"EjectedGasMass ");
for (k=0;k<NELEMENTS;k++)
fprintf(FdChimieStatsSNs,"EjectedMass_%s ",&Elt[k+2].label);
fprintf(FdChimieStatsSNs,"\n");
fflush(FdChimieStatsSNs);
fprintf(FdChimieStatsGas,"# ThisTask TimeStep Time ID IDStar aij x y z ");
fprintf(FdChimieStatsGas,"Mass_0 ");
for (k=0;k<NELEMENTS;k++)
fprintf(FdChimieStatsGas,"%s_0 ",&Elt[k+2].label);
fprintf(FdChimieStatsGas,"Mass_1 ");
for (k=0;k<NELEMENTS;k++)
fprintf(FdChimieStatsGas,"%s_1 ",&Elt[k+2].label);
fprintf(FdChimieStatsGas,"\n");
fflush(FdChimieStatsGas);
#endif
}
/*! This function performe simple checks
* to validate the chemistry initialization
*/
void check_chimie(void)
{
int i;
if (ThisTask==0)
{
printf("Number of elts : %d\n",Cp->nelts);
for(i=2;i<Cp->nelts+2;i++)
printf("%s ",&Elt[i].label);
printf("\n");
}
/* check number of elements */
if (NELEMENTS != Cp->nelts)
{
printf("(Taks=%d) NELEMENTS (=%d) != Cp->nelts (=%d) : please check !!!\n\n",ThisTask,NELEMENTS,Cp->nelts);
endrun(88807);
}
/* check that iron is the first element */
//if ((strcmp("Fe",Elt[2].label))!=0)
// {
// printf("(Taks=%d) first element (=%s) is not %s !!!\n\n",ThisTask,Elt[2].label,FIRST_ELEMENT);
// endrun(88808);
// }
}
/*! This function print some info on the chimie parameters
*/
void info(int it)
{
int i,j;
printf("\nTable %d\n\n",it);
printf("%g %g %g\n", Cps[it].coeff_z[0][0],Cps[it].coeff_z[0][1],Cps[it].coeff_z[0][2]);
printf("%g %g %g\n", Cps[it].coeff_z[1][0],Cps[it].coeff_z[1][1],Cps[it].coeff_z[1][2]);
printf("%g %g %g\n", Cps[it].coeff_z[2][0],Cps[it].coeff_z[2][1],Cps[it].coeff_z[2][2]);
printf("\n");
printf("\nIMF\n");
printf("%g %g\n",Cps[it].Mmin,Cps[it].Mmax);
printf("%d\n",Cps[it].n);
for (i=0;i<Cps[it].n;i++)
printf( "ms : %g ",Cps[it].ms[i]);
printf("\n");
for (i=0;i<Cps[it].n+1;i++)
printf( "as : %g ",Cps[it].as[i]);
printf("\n");
printf("\nRate SNII\n");
printf("%g ",Cps[it].SNII_Mmin);
printf("%g ",Cps[it].SNII_Mmax);
printf("\n");
printf("\nRate DYIN\n");
printf("%g ",Cps[it].DYIN_Mmin);
printf("%g ",Cps[it].DYIN_Mmax);
printf("\n");
printf("\nRate SNIa\n");
printf("%g %g\n",Cps[it].SNIa_Mpl,Cps[it].SNIa_Mpu);
printf("%g \n",Cps[it].SNIa_a);
printf("%g %g %g\n",Cps[it].SNIa_Mdl1,Cps[it].SNIa_Mdu1,Cps[it].SNIa_b1);
printf("%g %g %g\n",Cps[it].SNIa_Mdl2,Cps[it].SNIa_Mdu2,Cps[it].SNIa_b2);
printf("\n");
for (i=0;i<Cps[it].nelts+2;i++)
{
printf("> %g %g\n",Elts[it][i].MminSNII,Elts[it][i].StepSNII);
for (j=0;j<Cps[it].nptsSNII;j++)
{
printf(" %g\n",Elts[it][i].ArraySNII[j]);
}
}
for (i=0;i<Cps[it].nelts+2;i++)
{
printf("> %g %g\n",Elts[it][i].MminDYIN,Elts[it][i].StepDYIN);
for (j=0;j<Cps[it].nptsDYIN;j++)
{
printf(" %g\n",Elts[it][i].ArrayDYIN[j]);
}
}
printf("\n");
printf("%g\n",Cps[it].Mco);
for (i=0;i<Cps[it].nelts+2;i++)
printf("%g\n",Elts[it][i].MSNIa);
printf("\n");
}
/*! Return the number of elements considered
*/
int get_nelts()
{
return Cp->nelts;
}
/*! Return the solar mass abundance of elt i
*/
float get_SolarMassAbundance(i)
{
return Elt[i+2].SolarMassAbundance;
}
/*! Return the label of element i
*/
char* get_Element(i)
{
return Elt[i+2].label;
}
int get_ElementIndex(char *elt)
{
/*
example:
get_SolarMassAbundance(get_ElementIndex("Fe"));
*/
int i=-1;
for(i=0;i<Cp->nelts;i++)
if( strcmp(Elt[i+2].label, elt) == 0 )
return i;
printf("element %s is unknown\n",elt);
endrun(777123);
return i;
}
/*! Return the lifetime of a star of mass m and metallicity z
*/
double star_lifetime(double z,double m)
{
/* z is the mass fraction of metals, ie, the metallicity */
/* m is the stellar mass in code unit */
/* Return t in code time unit */
int i;
double a,b,c;
double coeff[3];
double logm,twologm,logm2,time;
/* convert m in msol */
m = m*All.CMUtoMsol;
for (i=0;i<3;i++)
coeff[i] = ( Cp->coeff_z[i][0]*z+Cp->coeff_z[i][1] )*z+Cp->coeff_z[i][2];
a = coeff[0];
b = coeff[1];
c = coeff[2];
logm = log10(m);
twologm = 2.0 * logm;
logm2 = logm*logm;
time = pow(10.,(a*logm2+b*twologm+c));
time = time * All.HubbleParam; /* correct from hubble as not done in coeff_z */
return time;
}
/*! Return the mass of a star having a livetime t and a metallicity z
*/
double star_mass_from_age(double z,double t)
{
/* z is the mass fraction of metals, ie, the metallicity */
/* t is the star life time (in code unit) */
/* return the stellar mass (in code unit) that has a lifetime equal to t */
/* this is the inverse of star_lifetime */
int i;
double a,b,c;
double coeff[3];
double m;
t = t/All.HubbleParam; /* correct from hubble as not done in coeff_z */
for (i=0;i<3;i++)
coeff[i] = ( Cp->coeff_z[i][0]*z+Cp->coeff_z[i][1] )*z+Cp->coeff_z[i][2];
a = coeff[0];
b = coeff[1];
c = coeff[2];
m = -(b+sqrt(b*b-a*(c-log10(t))))/a;
m = pow(10,m); /* here, m is in solar mass */
m = m*All.MsoltoCMU; /* Msol to mass unit */
return m;
}
/****************************************************************************************/
/*
/* Supernova rate : number of supernova per mass unit
/*
/****************************************************************************************/
double DYIN_rate(double m1,double m2)
{
/*
compute the number of stars between m1 and m2
masses in code unit
*/
double RDYIN;
double md,mu;
RDYIN = 0.0;
/* convert m in msol */
m1 = m1*All.CMUtoMsol;
m2 = m2*All.CMUtoMsol;
/* find md, mu */
md = dmax(m1,Cp->DYIN_Mmin);
mu = dmin(m2,Cp->DYIN_Mmax);
if (mu<=md) /* no dying stars in that mass range */
return 0.0;
/* to code units */
md = md * All.MsoltoCMU;
mu = mu * All.MsoltoCMU;
/* compute number in the mass range */
RDYIN = get_imf_N(md,mu);
return RDYIN;
}
double SNII_rate(double m1,double m2)
{
/*
compute the number of SNII between m1 and m2
masses in code unit
*/
double RSNII;
double md,mu;
RSNII = 0.0;
/* convert m in msol */
m1 = m1*All.CMUtoMsol;
m2 = m2*All.CMUtoMsol;
/* (1) find md, mu */
md = dmax(m1,Cp->SNII_Mmin);
mu = dmin(m2,Cp->SNII_Mmax);
if (mu<=md) /* no SNII in that mass range */
return 0.0;
/* !!!!! here we should use get_imf_N !!!! */
/* to ensure the full imf */
//RSNII = Cp->SNII_cte * (pow(mu,Cp->SNII_a)-pow(md,Cp->SNII_a)); /* number per solar mass */
///* convert in number per solar mass to number per mass unit */
//RSNII = RSNII *All.CMUtoMsol;
/* to code units */
md = md * All.MsoltoCMU;
mu = mu * All.MsoltoCMU;
/* compute number in the mass range */
RSNII = get_imf_N(md,mu);
return RSNII;
}
double SNIa_rate(double m1,double m2)
{
/*
compute the number of SNIa between m1 and m2
masses in code unit
*/
double RSNIa;
double md,mu;
RSNIa = 0.0;
/* convert m in msol */
m1 = m1*All.CMUtoMsol;
m2 = m2*All.CMUtoMsol;
/* RG contribution */
md = dmax(m1,Cp->SNIa_Mdl1);
mu = dmin(m2,Cp->SNIa_Mdu1);
if (md<mu)
RSNIa = RSNIa + Cp->SNIa_bb1 * Cp->SNIa_cte1 * (pow(mu,Cp->SNIa_a1)-pow(md,Cp->SNIa_a1));
/* MS contribution */
md = dmax(m1,Cp->SNIa_Mdl2);
mu = dmin(m2,Cp->SNIa_Mdu2);
if (md<mu)
RSNIa = RSNIa + Cp->SNIa_bb2 * Cp->SNIa_cte2 * (pow(mu,Cp->SNIa_a2)-pow(md,Cp->SNIa_a2));
/* WD contribution */
md = dmax(m1,Cp->SNIa_Mpl); /* select stars that have finished their life -> WD */
mu = Cp->SNIa_Mpu; /* no upper bond */
if (mu<=md) /* no SNIa in that mass range */
return 0.0;
RSNIa = RSNIa * Cp->SNIa_cte * (pow(mu,Cp->SNIa_a)-pow(md,Cp->SNIa_a)); /* number per solar mass */
/* convert in number per solar mass to number per mass unit */
RSNIa = RSNIa *All.CMUtoMsol;
return RSNIa;
}
double SNIa_single_rate(double m)
{
/*
compute the number of SNIa per mass unit (in CMU) if the mass of the star is m
m is given in code units.
NOTE : as single stars are follow a normal imf distribution and here
the RG and MS follow another IMF, we need to introduce the normalisation factor
*/
double RSNIa;
RSNIa = 0.0;
/* convert m in msol */
m = m*All.CMUtoMsol;
/* the star mass is greater than the WD interval */
if (m <= Cp->SNIa_Mpl )
{
/* according to its mass the star is a RG */
if ( ( m > Cp->SNIa_Mdl1 ) && ( m <= Cp->SNIa_Mdu1 ) )
RSNIa = Cp->SNIa_bb1 * Cp->SNIa_NWDN * Cp->SNIa_b1 * pow(m,Cp->SNIa_a1 ) / get_imf(m*All.MsoltoCMU);
/* according to its mass the star is a MS */
if ( ( m > Cp->SNIa_Mdl2 ) && ( m <= Cp->SNIa_Mdu2 ) )
RSNIa = Cp->SNIa_bb2 * Cp->SNIa_NWDN * Cp->SNIa_b2 * pow(m,Cp->SNIa_a2 ) / get_imf(m*All.MsoltoCMU);
}
return RSNIa;
}
void DYIN_mass_ejection(double m1,double m2)
{
/*
Compute the mass fraction and yields of dying stars with masses between m1 and m2.
Store the result in the global variable`` MassFracDYIN``::
MassFracDYIN[0] = total gas
MassFracDYIN[1] = helium core (i.e. alpha(m))
MassFracDYIN[i] = frac mass elt i.
*/
double l1,l2;
int i1,i2,i1p,i2p,j;
double f1,f2;
double v1,v2;
/* convert m in msol */
m1 = m1*All.CMUtoMsol;
m2 = m2*All.CMUtoMsol;
/* this was not in Poirier... */
m1 = dmax(m1,Cp->DYIN_Mmin);
m2 = dmin(m2,Cp->DYIN_Mmax);
if ( m2<=m1 )
{
for (j=0;j<Cp->nelts+2;j++)
MassFracDYIN[j] = 0;
return;
}
j = 0;
l1 = ( log10(m1) - Elt[j].MminDYIN) / Elt[j].StepDYIN ;
l2 = ( log10(m2) - Elt[j].MminDYIN) / Elt[j].StepDYIN ;
if (l1 < 0.0) l1 = 0.0;
if (l2 < 0.0) l2 = 0.0;
i1 = (int)l1;
i2 = (int)l2;
i1p = i1 + 1;
i2p = i2 + 1;
f1 = l1 - i1;
f2 = l2 - i2;
/* check (yr) */
if (i1<0) i1=0;
if (i2<0) i2=0;
/* --------- TOTAL GAS ---------- */
j = 0;
v1 = f1 * ( Elt[j].ArrayDYIN[i1p] - Elt[j].ArrayDYIN[i1] ) + Elt[j].ArrayDYIN[i1];
v2 = f2 * ( Elt[j].ArrayDYIN[i2p] - Elt[j].ArrayDYIN[i2] ) + Elt[j].ArrayDYIN[i2];
MassFracDYIN[j] = v2-v1;
/* --------- He core therm ---------- */
j = 1;
v1 = f1 * ( Elt[j].ArrayDYIN[i1p] - Elt[j].ArrayDYIN[i1] ) + Elt[j].ArrayDYIN[i1];
v2 = f2 * ( Elt[j].ArrayDYIN[i2p] - Elt[j].ArrayDYIN[i2] ) + Elt[j].ArrayDYIN[i2];
MassFracDYIN[j] = v2-v1;
/* ---------------------------- */
/* --------- Metals ---------- */
/* ---------------------------- */
j = 2;
l1 = ( log10(m1) - Elt[j].MminDYIN) / Elt[j].StepDYIN ;
l2 = ( log10(m2) - Elt[j].MminDYIN) / Elt[j].StepDYIN ;
if (l1 < 0.0) l1 = 0.0;
if (l2 < 0.0) l2 = 0.0;
i1 = (int)l1;
i2 = (int)l2;
i1p = i1 + 1;
i2p = i2 + 1;
f1 = l1 - i1;
f2 = l2 - i2;
/* check (yr) */
if (i1<0) i1=0;
if (i2<0) i2=0;
for (j=2;j<Cp->nelts+2;j++)
{
v1 = f1 * ( Elt[j].ArrayDYIN[i1p] - Elt[j].ArrayDYIN[i1] ) + Elt[j].ArrayDYIN[i1];
v2 = f2 * ( Elt[j].ArrayDYIN[i2p] - Elt[j].ArrayDYIN[i2] ) + Elt[j].ArrayDYIN[i2];
MassFracDYIN[j] = v2-v1;
}
}
void DYIN_mass_ejection_Z(double m1,double m2, double Z)
{
/*
Compute the mass fraction and yields of dying stars with masses between m1 and m2.
Store the result in the global variable`` MassFracDYIN``::
MassFracDYIN[0] = total gas
MassFracDYIN[1] = helium core (i.e. alpha(m))
MassFracDYIN[i] = frac mass elt i.
*/
double l1,l2;
int i1,i2,i1p,i2p,k;
int j1,j1p;
double f1,f2,g1;
double v1,v2,v11,v12;
/* convert m in msol */
m1 = m1*All.CMUtoMsol;
m2 = m2*All.CMUtoMsol;
/* this was not in Poirier... */
m1 = dmax(m1,Cp->DYIN_Mmin);
m2 = dmin(m2,Cp->DYIN_Mmax);
if ( m2<=m1 )
{
for (k=0;k<Cp->nelts+2;k++)
MassFracDYIN[k] = 0;
return;
}
/* find i1,i1p, index in m1 and m2 */
k = 0;
l1 = ( log10(m1) - Elt[k].MminDYIN) / Elt[k].StepDYIN ;
l2 = ( log10(m2) - Elt[k].MminDYIN) / Elt[k].StepDYIN ;
if (l1 < 0.0) l1 = 0.0;
if (l2 < 0.0) l2 = 0.0;
i1 = (int)l1;
i2 = (int)l2;
i1p = i1 + 1;
i2p = i2 + 1;
f1 = l1 - i1;
f2 = l2 - i2;
/* check (yr) */
if (i1<0) i1=0;
if (i2<0) i2=0;
/* find j1,j1p, index in Z */
l1 = ( log10(Z) - Elt[k].MminZDYIN) / Elt[k].StepZDYIN ;
if (l1 < 0.0) l1 = 0.0;
j1 = (int)l1;
j1p = j1 + 1;
g1 = l1 - j1;
/* check (yr) */
if (j1<0) j1=0;
/* --------- TOTAL GAS ---------- */
k = 0;
/* mass 1 */
v11 = f1 * ( Elt[k].ArrayZDYIN[i1p][j1] - Elt[k].ArrayZDYIN[i1][j1] ) + Elt[k].ArrayZDYIN[i1][j1];
v12 = f1 * ( Elt[k].ArrayZDYIN[i1p][j1p] - Elt[k].ArrayZDYIN[i1][j1p] ) + Elt[k].ArrayZDYIN[i1][j1p];
v1 = g1 * ( v12 - v11 ) + v11;
/* mass 2 */
v11 = f2 * ( Elt[k].ArrayZDYIN[i2p][j1] - Elt[k].ArrayZDYIN[i2][j1] ) + Elt[k].ArrayZDYIN[i2][j1];
v12 = f2 * ( Elt[k].ArrayZDYIN[i2p][j1p] - Elt[k].ArrayZDYIN[i2][j1p] ) + Elt[k].ArrayZDYIN[i2][j1p];
v2 = g1 * ( v12 - v11 ) + v11;
MassFracDYIN[k] = v2-v1;
/* --------- He core therm ---------- */
k = 1;
/* mass 1 */
v11 = f1 * ( Elt[k].ArrayZDYIN[i1p][j1] - Elt[k].ArrayZDYIN[i1][j1] ) + Elt[k].ArrayZDYIN[i1][j1];
v12 = f1 * ( Elt[k].ArrayZDYIN[i1p][j1p] - Elt[k].ArrayZDYIN[i1][j1p] ) + Elt[k].ArrayZDYIN[i1][j1p];
v1 = g1 * ( v12 - v11 ) + v11;
/* mass 2 */
v11 = f2 * ( Elt[k].ArrayZDYIN[i2p][j1] - Elt[k].ArrayZDYIN[i2][j1] ) + Elt[k].ArrayZDYIN[i2][j1];
v12 = f2 * ( Elt[k].ArrayZDYIN[i2p][j1p] - Elt[k].ArrayZDYIN[i2][j1p] ) + Elt[k].ArrayZDYIN[i2][j1p];
v2 = g1 * ( v12 - v11 ) + v11;
MassFracDYIN[k] = v2-v1;
/* ---------------------------- */
/* --------- Metals ---------- */
/* ---------------------------- */
k = 2;
l1 = ( log10(m1) - Elt[k].MminDYIN) / Elt[k].StepDYIN ;
l2 = ( log10(m2) - Elt[k].MminDYIN) / Elt[k].StepDYIN ;
if (l1 < 0.0) l1 = 0.0;
if (l2 < 0.0) l2 = 0.0;
i1 = (int)l1;
i2 = (int)l2;
i1p = i1 + 1;
i2p = i2 + 1;
f1 = l1 - i1;
f2 = l2 - i2;
/* check (yr) */
if (i1<0) i1=0;
if (i2<0) i2=0;
/* find j1,j1p, index in Z */
l1 = ( log10(Z) - Elt[k].MminZDYIN) / Elt[k].StepZDYIN ;
if (l1 < 0.0) l1 = 0.0;
j1 = (int)l1;
j1p = j1 + 1;
g1 = l1 - j1;
/* check (yr) */
if (j1<0) j1=0;
for (k=2;k<Cp->nelts+2;k++)
{
/* mass 1 */
v11 = f1 * ( Elt[k].ArrayZDYIN[i1p][j1] - Elt[k].ArrayZDYIN[i1][j1] ) + Elt[k].ArrayZDYIN[i1][j1];
v12 = f1 * ( Elt[k].ArrayZDYIN[i1p][j1p] - Elt[k].ArrayZDYIN[i1][j1p] ) + Elt[k].ArrayZDYIN[i1][j1p];
v1 = g1 * ( v12 - v11 ) + v11;
/* mass 2 */
v11 = f2 * ( Elt[k].ArrayZDYIN[i2p][j1] - Elt[k].ArrayZDYIN[i2][j1] ) + Elt[k].ArrayZDYIN[i2][j1];
v12 = f2 * ( Elt[k].ArrayZDYIN[i2p][j1p] - Elt[k].ArrayZDYIN[i2][j1p] ) + Elt[k].ArrayZDYIN[i2][j1p];
v2 = g1 * ( v12 - v11 ) + v11;
MassFracDYIN[k] = v2-v1;
}
}
void DYIN_single_mass_ejection(double m1)
{
/*
Compute the mass fraction and yields of a dying stars of masse m1.
Store the result in the global variable ``SingleMassFracDYIN``::
SingleMassFracDYIN[0] = total gas
SingleMassFracDYIN[1] = helium core (i.e. alpha(m))
SingleMassFracDYIN[i] = frac mass elt i.
*/
double l1;
int i1,i1p,j;
double f1;
double v1;
/* convert m in msol */
m1 = m1*All.CMUtoMsol;
/* this was not in Poirier... */
if ( (m1<=Cp->DYIN_Mmin) || (m1>=Cp->DYIN_Mmax) )
{
for (j=0;j<Cp->nelts+2;j++)
SingleMassFracDYIN[j] = 0;
return;
}
j = 0;
l1 = ( log10(m1) - Elt[j].MminDYIN) / Elt[j].StepDYIN ;
if (l1 < 0.0) l1 = 0.0;
i1 = (int)l1;
i1p = i1 + 1;
f1 = l1 - i1;
/* check (yr) */
if (i1<0) i1=0;
/* --------- TOTAL GAS ---------- */
j = 0;
v1 = f1 * ( Elt[j].MetalDYIN[i1p] - Elt[j].MetalDYIN[i1] ) + Elt[j].MetalDYIN[i1];
SingleMassFracDYIN[j] = v1;
/* --------- He core therm ---------- */
j = 1;
v1 = f1 * ( Elt[j].MetalDYIN[i1p] - Elt[j].MetalDYIN[i1] ) + Elt[j].MetalDYIN[i1];
SingleMassFracDYIN[j] = v1;
/* ---------------------------- */
/* --------- Metals ---------- */
/* ---------------------------- */
j = 2;
l1 = ( log10(m1) - Elt[j].MminDYIN) / Elt[j].StepDYIN ;
if (l1 < 0.0) l1 = 0.0;
i1 = (int)l1;
i1p = i1 + 1;
f1 = l1 - i1;
/* check (yr) */
if (i1<0) i1=0;
for (j=2;j<Cp->nelts+2;j++)
{
v1 = f1 * ( Elt[j].MetalDYIN[i1p] - Elt[j].MetalDYIN[i1] ) + Elt[j].MetalDYIN[i1];
SingleMassFracDYIN[j] = v1;
}
}
void DYIN_single_mass_ejection_Z(double m1,double Z)
{
/*
Compute the mass fraction and yields of a dying stars of masse m1.
Store the result in the global variable ``SingleMassFracDYIN``::
SingleMassFracDYIN[0] = total gas
SingleMassFracDYIN[1] = helium core (i.e. alpha(m))
SingleMassFracDYIN[i] = frac mass elt i.
*/
double l1;
int i1,i1p,k;
int j1,j1p;
double f1,g1;
double v1,v11,v12;
/* convert m in msol */
m1 = m1*All.CMUtoMsol;
/* this was not in Poirier... */
if ( (m1<=Cp->DYIN_Mmin) || (m1>=Cp->DYIN_Mmax) )
{
for (k=0;k<Cp->nelts+2;k++)
SingleMassFracDYIN[k] = 0;
return;
}
k = 0;
/* find i1,i1p, index in m */
l1 = ( log10(m1) - Elt[k].MminDYIN) / Elt[k].StepDYIN ;
if (l1 < 0.0) l1 = 0.0;
i1 = (int)l1;
i1p = i1 + 1;
f1 = l1 - i1;
/* check (yr) */
if (i1<0) i1=0;
/* find j1,j1p, index in Z */
l1 = ( log10(Z) - Elt[k].MminZDYIN) / Elt[k].StepZDYIN ;
if (l1 < 0.0) l1 = 0.0;
j1 = (int)l1;
j1p = j1 + 1;
g1 = l1 - j1;
/* check (yr) */
if (j1<0) j1=0;
/* --------- TOTAL GAS ---------- */
k = 0;
v11 = f1 * ( Elt[k].MetalZDYIN[i1p][j1] - Elt[k].MetalZDYIN[i1][j1] ) + Elt[k].MetalZDYIN[i1][j1];
v12 = f1 * ( Elt[k].MetalZDYIN[i1p][j1p] - Elt[k].MetalZDYIN[i1][j1p] ) + Elt[k].MetalZDYIN[i1p][j1];
v1 = g1 * ( v12 - v11 ) + v11;
SingleMassFracDYIN[k] = v1;
/* --------- He core therm ---------- */
k = 1;
v11 = f1 * ( Elt[k].MetalZDYIN[i1p][j1] - Elt[k].MetalZDYIN[i1][j1] ) + Elt[k].MetalZDYIN[i1][j1];
v12 = f1 * ( Elt[k].MetalZDYIN[i1p][j1p] - Elt[k].MetalZDYIN[i1][j1p] ) + Elt[k].MetalZDYIN[i1p][j1];
v1 = g1 * ( v12 - v11 ) + v11;
SingleMassFracDYIN[k] = v1;
/* ---------------------------- */
/* --------- Metals ---------- */
/* ---------------------------- */
k = 2;
/* find i1,i1p, index in m */
l1 = ( log10(m1) - Elt[k].MminDYIN) / Elt[k].StepDYIN ;
if (l1 < 0.0) l1 = 0.0;
i1 = (int)l1;
i1p = i1 + 1;
f1 = l1 - i1;
/* check (yr) */
if (i1<0) i1=0;
/* find j1,j1p, index in Z */
l1 = ( log10(Z) - Elt[k].MminZDYIN) / Elt[k].StepZDYIN ;
if (l1 < 0.0) l1 = 0.0;
j1 = (int)l1;
j1p = j1 + 1;
g1 = l1 - j1;
/* check (yr) */
if (j1<0) j1=0;
for (k=2;k<Cp->nelts+2;k++)
{
v11 = f1 * ( Elt[k].MetalZDYIN[i1p][j1] - Elt[k].MetalZDYIN[i1][j1] ) + Elt[k].MetalZDYIN[i1][j1];
v12 = f1 * ( Elt[k].MetalZDYIN[i1p][j1p] - Elt[k].MetalZDYIN[i1][j1p] ) + Elt[k].MetalZDYIN[i1p][j1];
v1 = g1 * ( v12 - v11 ) + v11;
SingleMassFracDYIN[k] = v1;
}
}
void SNII_mass_ejection(double m1,double m2)
{
/*
.. warning:: here, we we do not limit the computation to SNII !!!
Compute the mass fraction and yields of SNII stars with masses between m1 and m2.
Store the result in the global variable ``MassFracSNII``::
MassFracSNII[0] = total gas
MassFracSNII[1] = 1-helium core (i.e. non processed elts)
MassFracSNII[i] = frac mass elt i.
*/
double l1,l2;
int i1,i2,i1p,i2p,j;
double f1,f2;
double v1,v2;
/* convert m in msol */
m1 = m1*All.CMUtoMsol;
m2 = m2*All.CMUtoMsol;
/* this was not in Poirier... */
m1 = dmax(m1,Cp->SNII_Mmin);
m2 = dmin(m2,Cp->SNII_Mmax);
if ( m2<=m1 )
{
for (j=0;j<Cp->nelts+2;j++)
MassFracSNII[j] = 0;
return;
}
j = 0;
l1 = ( log10(m1) - Elt[j].MminSNII) / Elt[j].StepSNII ;
l2 = ( log10(m2) - Elt[j].MminSNII) / Elt[j].StepSNII ;
if (l1 < 0.0) l1 = 0.0;
if (l2 < 0.0) l2 = 0.0;
i1 = (int)l1;
i2 = (int)l2;
i1p = i1 + 1;
i2p = i2 + 1;
f1 = l1 - i1;
f2 = l2 - i2;
/* check (yr) */
if (i1<0) i1=0;
if (i2<0) i2=0;
/* --------- TOTAL GAS ---------- */
j = 0;
v1 = f1 * ( Elt[j].ArraySNII[i1p] - Elt[j].ArraySNII[i1] ) + Elt[j].ArraySNII[i1];
v2 = f2 * ( Elt[j].ArraySNII[i2p] - Elt[j].ArraySNII[i2] ) + Elt[j].ArraySNII[i2];
MassFracSNII[j] = v2-v1;
/* --------- He core therm ---------- */
j = 1;
v1 = f1 * ( Elt[j].ArraySNII[i1p] - Elt[j].ArraySNII[i1] ) + Elt[j].ArraySNII[i1];
v2 = f2 * ( Elt[j].ArraySNII[i2p] - Elt[j].ArraySNII[i2] ) + Elt[j].ArraySNII[i2];
MassFracSNII[j] = v2-v1;
/* ---------------------------- */
/* --------- Metals ---------- */
/* ---------------------------- */
j = 2;
l1 = ( log10(m1) - Elt[j].MminSNII) / Elt[j].StepSNII ;
l2 = ( log10(m2) - Elt[j].MminSNII) / Elt[j].StepSNII ;
if (l1 < 0.0) l1 = 0.0;
if (l2 < 0.0) l2 = 0.0;
i1 = (int)l1;
i2 = (int)l2;
i1p = i1 + 1;
i2p = i2 + 1;
f1 = l1 - i1;
f2 = l2 - i2;
/* check (yr) */
if (i1<0) i1=0;
if (i2<0) i2=0;
for (j=2;j<Cp->nelts+2;j++)
{
v1 = f1 * ( Elt[j].ArraySNII[i1p] - Elt[j].ArraySNII[i1] ) + Elt[j].ArraySNII[i1];
v2 = f2 * ( Elt[j].ArraySNII[i2p] - Elt[j].ArraySNII[i2] ) + Elt[j].ArraySNII[i2];
MassFracSNII[j] = v2-v1;
}
}
// void SNII_mass_ejection_Z(double m1,double m2, double Z)
// {
//
// /*
// Compute the mass fraction and yields of SNII with masses between m1 and m2.
// Store the result in the global variable`` MassFracSNII``::
//
// MassFracSNII[0] = total gas
// MassFracSNII[1] = helium core (i.e. alpha(m))
// MassFracSNII[i] = frac mass elt i.
//
// */
//
// double l1,l2;
// int i1,i2,i1p,i2p,k;
// int j1,j1p;
// double f1,f2,g1;
// double v1,v2,v11,v12;
//
// /* convert m in msol */
// m1 = m1*All.CMUtoMsol;
// m2 = m2*All.CMUtoMsol;
//
// /* this was not in Poirier... */
// m1 = dmax(m1,Cp->SNII_Mmin);
// m2 = dmin(m2,Cp->SNII_Mmax);
//
//
// if ( m2<=m1 )
// {
// for (k=0;k<Cp->nelts+2;k++)
// MassFracSNII[k] = 0;
// return;
// }
//
//
//
//
// /* find i1,i1p, index in m1 and m2 */
//
// k = 0;
// l1 = ( log10(m1) - Elt[k].MminSNII) / Elt[k].StepSNII ;
// l2 = ( log10(m2) - Elt[k].MminSNII) / Elt[k].StepSNII ;
//
// if (l1 < 0.0) l1 = 0.0;
// if (l2 < 0.0) l2 = 0.0;
//
// i1 = (int)l1;
// i2 = (int)l2;
//
// i1p = i1 + 1;
// i2p = i2 + 1;
//
// f1 = l1 - i1;
// f2 = l2 - i2;
//
// /* check (yr) */
// if (i1<0) i1=0;
// if (i2<0) i2=0;
//
//
// /* find j1,j1p, index in Z */
//
// l1 = ( log10(Z) - Elt[k].MminZSNII) / Elt[k].StepZSNII ;
//
// if (l1 < 0.0) l1 = 0.0;
//
// j1 = (int)l1;
// j1p = j1 + 1;
// g1 = l1 - j1;
//
// /* check (yr) */
// if (j1<0) j1=0;
//
//
//
// /* --------- TOTAL GAS ---------- */
// k = 0;
//
// /* mass 1 */
// v11 = f1 * ( Elt[k].ArrayZSNII[i1p][j1] - Elt[k].ArrayZSNII[i1][j1] ) + Elt[k].ArrayZSNII[i1][j1];
// v12 = f1 * ( Elt[k].ArrayZSNII[i1p][j1p] - Elt[k].ArrayZSNII[i1][j1p] ) + Elt[k].ArrayZSNII[i1p][j1];
// v1 = g1 * ( v12 - v11 ) + v11;
//
// /* mass 2 */
// v11 = f2 * ( Elt[k].ArrayZSNII[i2p][j1] - Elt[k].ArrayZSNII[i2][j1] ) + Elt[k].ArrayZSNII[i2][j1];
// v12 = f2 * ( Elt[k].ArrayZSNII[i2p][j1p] - Elt[k].ArrayZSNII[i2][j1p] ) + Elt[k].ArrayZSNII[i2p][j1];
// v2 = g1 * ( v12 - v11 ) + v11;
//
// MassFracSNII[k] = v2-v1;
//
// /* --------- He core therm ---------- */
// k = 1;
//
// /* mass 1 */
// v11 = f1 * ( Elt[k].ArrayZSNII[i1p][j1] - Elt[k].ArrayZSNII[i1][j1] ) + Elt[k].ArrayZSNII[i1][j1];
// v12 = f1 * ( Elt[k].ArrayZSNII[i1p][j1p] - Elt[k].ArrayZSNII[i1][j1p] ) + Elt[k].ArrayZSNII[i1p][j1];
// v1 = g1 * ( v12 - v11 ) + v11;
//
// /* mass 2 */
// v11 = f2 * ( Elt[k].ArrayZSNII[i2p][j1] - Elt[k].ArrayZSNII[i2][j1] ) + Elt[k].ArrayZSNII[i2][j1];
// v12 = f2 * ( Elt[k].ArrayZSNII[i2p][j1p] - Elt[k].ArrayZSNII[i2][j1p] ) + Elt[k].ArrayZSNII[i2p][j1];
// v2 = g1 * ( v12 - v11 ) + v11;
//
// MassFracSNII[k] = v2-v1;
//
// /* ---------------------------- */
// /* --------- Metals ---------- */
// /* ---------------------------- */
//
// k = 2;
//
// l1 = ( log10(m1) - Elt[k].MminSNII) / Elt[k].StepSNII ;
// l2 = ( log10(m2) - Elt[k].MminSNII) / Elt[k].StepSNII ;
//
// if (l1 < 0.0) l1 = 0.0;
// if (l2 < 0.0) l2 = 0.0;
//
// i1 = (int)l1;
// i2 = (int)l2;
//
// i1p = i1 + 1;
// i2p = i2 + 1;
//
// f1 = l1 - i1;
// f2 = l2 - i2;
//
// /* check (yr) */
// if (i1<0) i1=0;
// if (i2<0) i2=0;
//
// /* find j1,j1p, index in Z */
//
// l1 = ( log10(Z) - Elt[k].MminZSNII) / Elt[k].StepZSNII ;
//
// if (l1 < 0.0) l1 = 0.0;
//
// j1 = (int)l1;
// j1p = j1 + 1;
// g1 = l1 - j1;
//
// /* check (yr) */
// if (j1<0) j1=0;
//
// for (k=2;k<Cp->nelts+2;k++)
// {
//
// /* mass 1 */
// v11 = f1 * ( Elt[k].ArrayZSNII[i1p][j1] - Elt[k].ArrayZSNII[i1][j1] ) + Elt[k].ArrayZSNII[i1][j1];
// v12 = f1 * ( Elt[k].ArrayZSNII[i1p][j1p] - Elt[k].ArrayZSNII[i1][j1p] ) + Elt[k].ArrayZSNII[i1p][j1];
// v1 = g1 * ( v12 - v11 ) + v11;
//
// /* mass 2 */
// v11 = f2 * ( Elt[k].ArrayZSNII[i2p][j1] - Elt[k].ArrayZSNII[i2][j1] ) + Elt[k].ArrayZSNII[i2][j1];
// v12 = f2 * ( Elt[k].ArrayZSNII[i2p][j1p] - Elt[k].ArrayZSNII[i2][j1p] ) + Elt[k].ArrayZSNII[i2p][j1];
// v2 = g1 * ( v12 - v11 ) + v11;
//
// MassFracSNII[k] = v2-v1;
//
// }
//
// }
void SNII_single_mass_ejection(double m1)
{
/*
.. warning:: here, we we do not limit the computation to SNII !!!
Compute the mass fraction and yields of a SNII stars of masse m1.
Store the result in the global variable ``SingleMassFracSNII``::
SingleMassFracSNII[0] = total gas
SingleMassFracSNII[1] = 1-helium core (i.e. non processed elts)
SingleMassFracSNII[i] = frac mass elt i.
*/
double l1;
int i1,i1p,j;
double f1;
double v1;
/* convert m in msol */
m1 = m1*All.CMUtoMsol;
/* this was not in Poirier... */
if ( (m1<=Cp->SNII_Mmin) || (m1>=Cp->SNII_Mmax) )
{
for (j=0;j<Cp->nelts+2;j++)
SingleMassFracSNII[j] = 0;
return;
}
j = 0;
l1 = ( log10(m1) - Elt[j].MminSNII) / Elt[j].StepSNII ;
if (l1 < 0.0) l1 = 0.0;
i1 = (int)l1;
i1p = i1 + 1;
f1 = l1 - i1;
/* check (yr) */
if (i1<0) i1=0;
/* --------- TOTAL GAS ---------- */
j = 0;
v1 = f1 * ( Elt[j].MetalSNII[i1p] - Elt[j].MetalSNII[i1] ) + Elt[j].MetalSNII[i1];
SingleMassFracSNII[j] = v1;
/* --------- He core therm ---------- */
j = 1;
v1 = f1 * ( Elt[j].MetalSNII[i1p] - Elt[j].MetalSNII[i1] ) + Elt[j].MetalSNII[i1];
SingleMassFracSNII[j] = v1;
/* ---------------------------- */
/* --------- Metals ---------- */
/* ---------------------------- */
j = 2;
l1 = ( log10(m1) - Elt[j].MminSNII) / Elt[j].StepSNII ;
if (l1 < 0.0) l1 = 0.0;
i1 = (int)l1;
i1p = i1 + 1;
f1 = l1 - i1;
/* check (yr) */
if (i1<0) i1=0;
for (j=2;j<Cp->nelts+2;j++)
{
v1 = f1 * ( Elt[j].MetalSNII[i1p] - Elt[j].MetalSNII[i1] ) + Elt[j].MetalSNII[i1];
SingleMassFracSNII[j] = v1;
}
}
// void SNII_single_mass_ejection_Z(double m1,double Z)
// {
//
//
// /*
// Compute the mass fraction and yields of a SNII stars of masse m1.
// Store the result in the global variable ``SingleMassFracSNII``::
//
// SingleMassFracSNII[0] = total gas
// SingleMassFracSNII[1] = helium core (i.e. alpha(m))
// SingleMassFracSNII[i] = frac mass elt i.
// */
//
// double l1;
// int i1,i1p,k;
// int j1,j1p;
// double f1,g1;
// double v1,v11,v12;
//
// /* convert m in msol */
// m1 = m1*All.CMUtoMsol;
//
// /* this was not in Poirier... */
// if ( (m1<=Cp->SNII_Mmin) || (m1>=Cp->SNII_Mmax) )
// {
// for (k=0;k<Cp->nelts+2;k++)
// SingleMassFracSNII[k] = 0;
// return;
// }
//
//
// k = 0;
//
//
// /* find i1,i1p, index in m */
//
// l1 = ( log10(m1) - Elt[k].MminSNII) / Elt[k].StepSNII ;
//
// if (l1 < 0.0) l1 = 0.0;
//
// i1 = (int)l1;
// i1p = i1 + 1;
// f1 = l1 - i1;
//
// /* check (yr) */
// if (i1<0) i1=0;
//
//
// /* find j1,j1p, index in Z */
//
// l1 = ( log10(Z) - Elt[k].MminZSNII) / Elt[k].StepZSNII ;
//
// if (l1 < 0.0) l1 = 0.0;
//
// j1 = (int)l1;
// j1p = j1 + 1;
// g1 = l1 - j1;
//
// /* check (yr) */
// if (j1<0) j1=0;
//
//
//
// /* --------- TOTAL GAS ---------- */
// k = 0;
// v11 = f1 * ( Elt[k].MetalZSNII[i1p][j1] - Elt[k].MetalZSNII[i1][j1] ) + Elt[k].MetalZSNII[i1][j1];
// v12 = f1 * ( Elt[k].MetalZSNII[i1p][j1p] - Elt[k].MetalZSNII[i1][j1p] ) + Elt[k].MetalZSNII[i1p][j1];
// v1 = g1 * ( v12 - v11 ) + v11;
//
// SingleMassFracSNII[k] = v1;
//
// /* --------- He core therm ---------- */
// k = 1;
// v11 = f1 * ( Elt[k].MetalZSNII[i1p][j1] - Elt[k].MetalZSNII[i1][j1] ) + Elt[k].MetalZSNII[i1][j1];
// v12 = f1 * ( Elt[k].MetalZSNII[i1p][j1p] - Elt[k].MetalZSNII[i1][j1p] ) + Elt[k].MetalZSNII[i1p][j1];
// v1 = g1 * ( v12 - v11 ) + v11;
//
// SingleMassFracSNII[k] = v1;
//
// /* ---------------------------- */
// /* --------- Metals ---------- */
// /* ---------------------------- */
//
// k = 2;
//
// /* find i1,i1p, index in m */
//
// l1 = ( log10(m1) - Elt[k].MminSNII) / Elt[k].StepSNII ;
//
// if (l1 < 0.0) l1 = 0.0;
//
// i1 = (int)l1;
// i1p = i1 + 1;
// f1 = l1 - i1;
//
// /* check (yr) */
// if (i1<0) i1=0;
//
//
// /* find j1,j1p, index in Z */
//
// l1 = ( log10(Z) - Elt[k].MminZSNII) / Elt[k].StepZSNII ;
//
// if (l1 < 0.0) l1 = 0.0;
//
// j1 = (int)l1;
// j1p = j1 + 1;
// g1 = l1 - j1;
//
// /* check (yr) */
// if (j1<0) j1=0;
//
// for (k=2;k<Cp->nelts+2;k++)
// {
//
// v11 = f1 * ( Elt[k].MetalZSNII[i1p][j1] - Elt[k].MetalZSNII[i1][j1] ) + Elt[k].MetalZSNII[i1][j1];
// v12 = f1 * ( Elt[k].MetalZSNII[i1p][j1p] - Elt[k].MetalZSNII[i1][j1p] ) + Elt[k].MetalZSNII[i1p][j1];
// v1 = g1 * ( v12 - v11 ) + v11;
//
// SingleMassFracSNII[k] = v1;
// }
//
// }
void SNIa_mass_ejection(double m1,double m2)
{
/*
Compute the total mass and element mass per mass unit of SNIa stars with masses between m1 and m2.
Store the result in the global variable ``MassFracSNIa``::
MassFracSNIa[0] = total gas
MassFracSNIa[1] = unused
MassFracSNIa[i] = frac mass elt i.
*/
int j;
double NSNIa;
/* number of SNIa per mass unit between time and time+dt */
NSNIa = SNIa_rate(m1,m2);
/* ejected mass in gas per mass unit */
MassFracSNIa[0] = Cp->Mco * All.MsoltoCMU * NSNIa;
/* ejected elements in gas per mass unit */
for (j=2;j<Cp->nelts+2;j++)
MassFracSNIa[j] = NSNIa* Elt[j].MSNIa * All.MsoltoCMU;
/* unused */
MassFracSNIa[1]=-1;
}
void SNIa_single_mass_ejection(double m1)
{
/*
Compute the total mass mass of element of a SNIa stars of masse m1.
Store the result in the global variable ``SingleMassFracSNIa``::
SingleMassFracSNIa[0] = total gas
SingleMassFracSNIa[1] = unused
SingleMassFracSNIa[i] = frac mass elt i.
*/
int j;
/* total ejected gas mass */
SingleMassFracSNIa[0] = Cp->Mco * All.MsoltoCMU;
/* ejected mass per element */
for (j=2;j<Cp->nelts+2;j++)
SingleMassFracSNIa[j] = Elt[j].MSNIa * All.MsoltoCMU;
/* unused */
SingleMassFracSNIa[1] = -1;
}
void Total_mass_ejection(double m1,double m2,double M0,double *z)
{
/*
Sum the contribution in mass and yields of all stars in the mass range m1,m2.
Store the result in the global variable EjectedMass::
EjectedMass[0] = total gas
EjectedMass[1] = UNUSED
EjectedMass[i+2] = frac mass elt i.
FOR THE MOMENT::
- contrib of SNII (= all stars)
- contrib of SNIa
EjectedMass[0] = ejected Mass from SNII + Mco * number of SNIa
EjectedMass[i] = (SNII elts created ) + (SNII elts existing) + (SNIa elts)
*/
int j;
/* compute SNII mass ejection -> MassFracSNII */
SNII_mass_ejection(m1,m2);
/* compute SNIa mass ejection -> MassFracSNIa */ /* not really a mass fraction */
SNIa_mass_ejection(m1,m2);
/* compute DYIN mass ejection -> MassFracDYIN */ /* not really a mass fraction */
#ifdef CHIMIE_AGB
DYIN_mass_ejection(m1,m2);
#endif
/* total ejected gas mass */
#ifdef CHIMIE_AGB
EjectedMass[0] = M0 * ( MassFracDYIN[0] + MassFracSNII[0] + MassFracSNIa[0] );
#else
EjectedMass[0] = M0 * ( MassFracSNII[0] + MassFracSNIa[0] );
#endif
/* ejected mass per element */
for (j=2;j<Cp->nelts+2;j++)
#ifdef CHIMIE_AGB
EjectedMass[j] = M0*( MassFracDYIN[j] +z[j-2]*MassFracDYIN[1] + MassFracSNII[j] +z[j-2]*MassFracSNII[1] + MassFracSNIa[j] );
#else
EjectedMass[j] = M0*( MassFracSNII[j] +z[j-2]*MassFracSNII[1] + MassFracSNIa[j] );
#endif
/* not used */
EjectedMass[1] = -1;
}
void Total_mass_ejection_Z(double m1,double m2,double M0,double *z)
{
/*
Sum the contribution in mass and yields of all stars in the mass range m1,m2.
Store the result in the global variable EjectedMass::
EjectedMass[0] = total gas
EjectedMass[1] = UNUSED
EjectedMass[i+2] = frac mass elt i.
FOR THE MOMENT::
- contrib of SNII (= all stars)
- contrib of SNIa
EjectedMass[0] = ejected Mass from SNII + Mco * number of SNIa
EjectedMass[i] = (SNII elts created ) + (SNII elts existing) + (SNIa elts)
*/
int j;
float Z; /* metalicity */
Z = z[METALS];
/* compute SNII mass ejection -> MassFracSNII */
SNII_mass_ejection(m1,m2);
/* compute SNIa mass ejection -> MassFracSNIa */ /* not really a mass fraction */
SNIa_mass_ejection(m1,m2);
/* compute DYIN mass ejection -> MassFracDYIN */ /* not really a mass fraction */
#ifdef CHIMIE_AGB
DYIN_mass_ejection_Z(m1,m2,Z);
#endif
/* total ejected gas mass */
#ifdef CHIMIE_AGB
EjectedMass[0] = M0 * ( MassFracDYIN[0] + MassFracSNII[0] + MassFracSNIa[0] );
#else
EjectedMass[0] = M0 * ( MassFracSNII[0] + MassFracSNIa[0] );
#endif
/* ejected mass per element */
for (j=2;j<Cp->nelts+2;j++)
#ifdef CHIMIE_AGB
EjectedMass[j] = M0*( MassFracDYIN[j] +z[j-2]*MassFracDYIN[1] + MassFracSNII[j] +z[j-2]*MassFracSNII[1] + MassFracSNIa[j] );
#else
EjectedMass[j] = M0*( MassFracSNII[j] +z[j-2]*MassFracSNII[1] + MassFracSNIa[j] );
#endif
/* not used */
EjectedMass[1] = -1;
}
void DYIN_Total_single_mass_ejection(double m1,double *z)
{
/*
Mass and element ejected by a single dying stars of mass m1.
This takes into account processed and non processed gas
The results are stored in::
SingleEjectedMass[0] = gas mass
SingleEjectedMass[1] = unsued
SingleEjectedMass[i+2] = frac mass elt i
*/
int j;
float M0;
M0 = m1;
/* compute dying stars mass ejection -> SingleMassFracDYIN */
DYIN_single_mass_ejection(m1);
/* total ejected gas mass */
SingleEjectedMass[0] = M0 * SingleMassFracDYIN[0];
/* ejected mass per element */
for (j=2;j<Cp->nelts+2;j++)
SingleEjectedMass[j] = M0*(SingleMassFracDYIN[j] +z[j-2]*SingleMassFracDYIN[1]);
/* not used */
SingleEjectedMass[1] = -1;
}
void SNII_Total_single_mass_ejection(double m1,double *z)
{
/*
Mass and element ejected by a single SNII of mass m1.
This takes into account processed and non processed gas
The results are stored in::
SingleEjectedMass[0] = gas mass
SingleEjectedMass[1] = unsued
SingleEjectedMass[i+2] = frac mass elt i
*/
int j;
float M0;
M0 = m1;
/* compute SNII mass ejection -> SingleMassFracSNII */
SNII_single_mass_ejection(m1);
/* total ejected gas mass */
SingleEjectedMass[0] = M0 * SingleMassFracSNII[0];
/* ejected mass per element */
for (j=2;j<Cp->nelts+2;j++)
SingleEjectedMass[j] = M0*(SingleMassFracSNII[j] +z[j-2]*SingleMassFracSNII[1]);
/* not used */
SingleEjectedMass[1] = -1;
}
void SNIa_Total_single_mass_ejection(double m1, double *z)
{
int j;
/*
Mass and element ejected by a single SNIa of mass m1.
The results are stored in::
SingleEjectedMass[0] = gas mass
SingleEjectedMass[1] = unsued
SingleEjectedMass[i+2] = frac mass elt i
*/
/* compute SNIa mass ejection -> SingleMassFracSNIa */
SNIa_single_mass_ejection(m1);
/* total ejected gas mass */
SingleEjectedMass[0] = SingleMassFracSNIa[0];
/* ejected mass per element */
for (j=2;j<Cp->nelts+2;j++)
SingleEjectedMass[j] = SingleMassFracSNIa[j];
}
void Total_single_mass_ejection(double m1,double *z,double NSNII,double NSNIa,double NDYIN)
{
/*
Sum the contribution in mass and yields of one star for mass m1.
Store the result in the global variable EjectedMass::
SingleEjectedMass[0] = total gas
SingleEjectedMass[1] = UNUSED
SingleEjectedMass[i+2] = frac mass elt i.
FOR THE MOMENT::
- contrib of SNII (= all stars)
- contrib of SNIa
SingleEjectedMass[0] = ejected Mass from SNII + Mco * number of SNIa
SingleEjectedMass[i] = (SNII elts created ) + (SNII elts existing) + (SNIa elts)
*/
int j;
float M0;
M0 = m1;
/* compute SNII mass ejection -> SingleMassFracSNII */
SNII_single_mass_ejection(m1);
/* compute SNII mass ejection -> SingleMassFracSNIa */
SNIa_single_mass_ejection(m1);
/* compute DYIN mass ejection -> SingleMassFracDYIN */
#ifdef CHIMIE_AGB
DYIN_single_mass_ejection(m1);
#endif
/* total ejected gas mass */
#ifdef CHIMIE_AGB
SingleEjectedMass[0] = M0 * ( SingleMassFracDYIN[0]*NDYIN + SingleMassFracSNII[0]*NSNII ) + SingleMassFracSNIa[0]*NSNIa;
#else
SingleEjectedMass[0] = M0 * ( SingleMassFracSNII[0]*NSNII ) + SingleMassFracSNIa[0]*NSNIa;
#endif
/* ejected mass per element */
for (j=2;j<Cp->nelts+2;j++)
#ifdef CHIMIE_AGB
SingleEjectedMass[j] = M0*( SingleMassFracDYIN[j]*NDYIN +z[j-2]*SingleMassFracDYIN[1]*NDYIN + SingleMassFracSNII[j]*NSNII +z[j-2]*SingleMassFracSNII[1]*NSNII ) + SingleMassFracSNIa[j]*NSNIa;
#else
SingleEjectedMass[j] = M0*( SingleMassFracSNII[j]*NSNII +z[j-2]*SingleMassFracSNII[1]*NSNII ) + SingleMassFracSNIa[j]*NSNIa;
#endif
/* not used */
SingleEjectedMass[1] = -1;
}
void Total_single_mass_ejection_Z(double m1,double *z,double NSNII,double NSNIa,double NDYIN)
{
/*
Sum the contribution in mass and yields of one star for mass m1.
Store the result in the global variable EjectedMass::
SingleEjectedMass[0] = total gas
SingleEjectedMass[1] = UNUSED
SingleEjectedMass[i+2] = frac mass elt i.
FOR THE MOMENT::
- contrib of SNII (= all stars)
- contrib of SNIa
SingleEjectedMass[0] = ejected Mass from SNII + Mco * number of SNIa
SingleEjectedMass[i] = (SNII elts created ) + (SNII elts existing) + (SNIa elts)
*/
int j;
float M0;
float Z; /* metalicity */
M0 = m1;
Z = z[METALS];
//z[METALS]=0;
/* compute SNII mass ejection -> SingleMassFracSNII */
SNII_single_mass_ejection(m1);
/* compute SNII mass ejection -> SingleMassFracSNIa */
SNIa_single_mass_ejection(m1);
/* compute DYIN mass ejection -> SingleMassFracDYIN */
#ifdef CHIMIE_AGB
DYIN_single_mass_ejection_Z(m1,Z);
#endif
/* total ejected gas mass */
#ifdef CHIMIE_AGB
SingleEjectedMass[0] = M0 * ( SingleMassFracDYIN[0]*NDYIN + SingleMassFracSNII[0]*NSNII ) + SingleMassFracSNIa[0]*NSNIa;
#else
SingleEjectedMass[0] = M0 * ( SingleMassFracSNII[0]*NSNII ) + SingleMassFracSNIa[0]*NSNIa;
#endif
/* ejected mass per element */
for (j=2;j<Cp->nelts+2;j++)
#ifdef CHIMIE_AGB
SingleEjectedMass[j] = M0*( SingleMassFracDYIN[j]*NDYIN +z[j-2]*SingleMassFracDYIN[1]*NDYIN + SingleMassFracSNII[j]*NSNII +z[j-2]*SingleMassFracSNII[1]*NSNII ) + SingleMassFracSNIa[j]*NSNIa;
#else
SingleEjectedMass[j] = M0*( SingleMassFracSNII[j]*NSNII +z[j-2]*SingleMassFracSNII[1]*NSNII ) + SingleMassFracSNIa[j]*NSNIa;
#endif
/* not used */
SingleEjectedMass[1] = -1;
}
/****************************************************************************************/
/*
/*
/*
/* GADGET ONLY PART
/*
/*
/*
/****************************************************************************************/
static double hubble_a, atime, hubble_a2, fac_mu, fac_vsic_fix, a3inv, fac_egy;
#ifdef FEEDBACK
static double fac_pow;
#endif
#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
#if defined(CHIMIE_THERMAL_FEEDBACK) && defined(CHIMIE_COMPUTE_THERMAL_FEEDBACK_ENERGY)
void chimie_compute_energy_int(int mode)
{
int i;
double DeltaEgyInt;
double Tot_DeltaEgyInt;
DeltaEgyInt = 0;
Tot_DeltaEgyInt = 0;
if (mode==1)
{
LocalSysState.EnergyInt1 = 0;
LocalSysState.EnergyInt2 = 0;
}
for(i = 0; i < N_gas; i++)
{
if (P[i].Type==0)
{
if (mode==1)
#ifdef DENSITY_INDEPENDENT_SPH
LocalSysState.EnergyInt1 += P[i].Mass * SphP[i].EntropyPred / (GAMMA_MINUS1) * pow(SphP[i].EgyWtDensity*a3inv, GAMMA_MINUS1);
#else
LocalSysState.EnergyInt1 += P[i].Mass * SphP[i].EntropyPred / (GAMMA_MINUS1) * pow(SphP[i].Density*a3inv, GAMMA_MINUS1);
#endif
else
#ifdef DENSITY_INDEPENDENT_SPH
LocalSysState.EnergyInt2 += P[i].Mass * SphP[i].EntropyPred / (GAMMA_MINUS1) * pow(SphP[i].EgyWtDensity*a3inv, GAMMA_MINUS1);
#else
LocalSysState.EnergyInt2 += P[i].Mass * SphP[i].EntropyPred / (GAMMA_MINUS1) * pow(SphP[i].Density*a3inv, GAMMA_MINUS1);
#endif
}
}
if (mode==2)
{
DeltaEgyInt = LocalSysState.EnergyInt2 - LocalSysState.EnergyInt1;
MPI_Reduce(&DeltaEgyInt, &Tot_DeltaEgyInt, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
LocalSysState.EnergyThermalFeedback -= DeltaEgyInt;
}
}
#endif
#if defined(CHIMIE_KINETIC_FEEDBACK) && defined(CHIMIE_COMPUTE_KINETIC_FEEDBACK_ENERGY)
void chimie_compute_energy_kin(int mode)
{
int i;
double DeltaEgyKin;
double Tot_DeltaEgyKin;
DeltaEgyKin = 0;
Tot_DeltaEgyKin = 0;
if (mode==1)
{
LocalSysState.EnergyKin1 = 0;
LocalSysState.EnergyKin2 = 0;
}
for(i = 0; i < N_gas; i++)
{
if (P[i].Type==0)
{
if (mode==1)
LocalSysState.EnergyKin1 += 0.5 * P[i].Mass * (P[i].Vel[0]*P[i].Vel[0]+P[i].Vel[1]*P[i].Vel[1]+P[i].Vel[2]*P[i].Vel[2]);
else
LocalSysState.EnergyKin2 += 0.5 * P[i].Mass * (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 (mode==2)
{
DeltaEgyKin = LocalSysState.EnergyKin2 - LocalSysState.EnergyKin1;
MPI_Reduce(&DeltaEgyKin, &Tot_DeltaEgyKin, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
LocalSysState.EnergyKineticFeedback -= DeltaEgyKin;
}
}
#endif
#ifdef CHIMIE_THERMAL_FEEDBACK
void chimie_apply_thermal_feedback(void)
{
int i;
double EgySpec,NewEgySpec,DeltaEntropy;
for(i = 0; i < N_gas; i++)
{
if (P[i].Type==0)
{
if (SphP[i].DeltaEgySpec > 0)
{
//printf("(%d) Step=%d i=%08d particle receive feedback\n",ThisTask,All.NumCurrentTiStep,i);
/* spec energy at current step (allways compute energy budget based on predicted entropy) */
#ifdef DENSITY_INDEPENDENT_SPH
EgySpec = SphP[i].EntropyPred / GAMMA_MINUS1 * pow(SphP[i].EgyWtDensity*a3inv, GAMMA_MINUS1);
#else
EgySpec = SphP[i].EntropyPred / GAMMA_MINUS1 * pow(SphP[i].Density *a3inv, GAMMA_MINUS1);
#endif
/* new egyspec */
NewEgySpec = EgySpec + SphP[i].DeltaEgySpec;
LocalSysState.EnergyThermalFeedback -= SphP[i].DeltaEgySpec*P[i].Mass;
/* new entropy */
#ifdef DENSITY_INDEPENDENT_SPH
DeltaEntropy = GAMMA_MINUS1*NewEgySpec/pow(SphP[i].EgyWtDensity*a3inv, GAMMA_MINUS1) - SphP[i].EntropyPred;
#else
DeltaEntropy = GAMMA_MINUS1*NewEgySpec/pow(SphP[i].Density *a3inv, GAMMA_MINUS1) - SphP[i].EntropyPred;
#endif
SphP[i].EntropyPred += DeltaEntropy;
SphP[i].Entropy += DeltaEntropy;
#ifdef DENSITY_INDEPENDENT_SPH
SphP[i].EntVarPred = pow(SphP[i].EntropyPred, 1/GAMMA);
#endif
/* set the adiabatic period for SNIa */
if (SphP[i].NumberOfSNIa>0)
SphP[i].SNIaThermalTime = All.Time;
/* set the adiabatic period for SNII */
if (SphP[i].NumberOfSNII>0)
SphP[i].SNIIThermalTime = All.Time;
/* reset variables */
SphP[i].DeltaEgySpec = 0;
SphP[i].NumberOfSNIa = 0;
SphP[i].NumberOfSNII = 0;
}
}
}
}
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
void chimie_apply_wind(void)
{
/* apply wind */
int i;
double e1,e2;
double phi,costh,sinth,vx,vy,vz;
for(i = 0; i < N_gas; i++)
{
if (P[i].Type==0)
{
if (SphP[i].WindFlag)
{
phi = get_ChimieKineticFeedback_random_number(P[i].ID)*PI*2.;
costh = 1.-2.*get_ChimieKineticFeedback_random_number(P[i].ID+1);
sinth = sqrt(1.-pow(costh,2));
vx = All.ChimieWindSpeed*sinth*cos(phi);
vy = All.ChimieWindSpeed*sinth*sin(phi);
vz = All.ChimieWindSpeed*costh;
e1 = 0.5*P[i].Mass * ( SphP[i].VelPred[0]*SphP[i].VelPred[0] + SphP[i].VelPred[1]*SphP[i].VelPred[1] + SphP[i].VelPred[2]*SphP[i].VelPred[2]);
P[i].Vel[0] += vx;
P[i].Vel[1] += vy;
P[i].Vel[2] += vz;
SphP[i].VelPred[0] += vx;
SphP[i].VelPred[1] += vy;
SphP[i].VelPred[2] += vz;
e2 = 0.5*P[i].Mass * ( SphP[i].VelPred[0]*SphP[i].VelPred[0] + SphP[i].VelPred[1]*SphP[i].VelPred[1] + SphP[i].VelPred[2]*SphP[i].VelPred[2]);
LocalSysState.EnergyKineticFeedback -= e2-e1;
SphP[i].WindFlag = 0;
}
}
}
}
#endif
/*! This function is the driver routine for the calculation of chemical evolution
*/
void chimie(void)
{
double t0, t1;
t0 = second(); /* measure the time for the full chimie computation */
#ifdef CHIMIE_TIMEBET
if((All.Time - All.ChimieTimeLastChimie) >= All.ChimieTimeBetChimie)
{
#endif
if (ThisTask==0)
printf("Start Chimie computation.\n");
if(All.ComovingIntegrationOn)
{
/* Factors for comoving integration of hydro */
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);
hubble_a2 = All.Time * All.Time * hubble_a;
fac_mu = pow(All.Time, 3 * (GAMMA - 1) / 2) / All.Time;
fac_egy = pow(All.Time, 3 * (GAMMA - 1));
fac_vsic_fix = hubble_a * pow(All.Time, 3 * GAMMA_MINUS1);
a3inv = 1 / (All.Time * All.Time * All.Time);
atime = All.Time;
#ifdef FEEDBACK
fac_pow = fac_egy*atime*atime;
#endif
}
else
{
hubble_a = hubble_a2 = atime = fac_mu = fac_vsic_fix = a3inv = fac_egy = 1.0;
#ifdef FEEDBACK
fac_pow = 1.0;
#endif
}
stars_density(); /* compute density */
#ifdef CHIMIE_ONE_SN_ONLY
if(All.ChimieOneSN==0) /* explode only if not one sn only*/
#endif
do_chimie(); /* chimie */
#ifdef CHIMIE_TIMEBET
All.ChimieTimeLastChimie += All.ChimieTimeBetChimie;
All.ChimieTi_begstep = All.Ti_Current;
if (ThisTask==0)
printf("Chimie: next Chimie=%g \n",All.ChimieTimeLastChimie);
#endif
if (ThisTask==0)
printf("Chimie computation done.\n");
t1 = second();
All.CPU_Chimie += timediff(t0, t1);
#ifdef CHIMIE_TIMEBET
}
#endif
}
/*! This function is the driver routine for the calculation of chemical evolution
*/
void do_chimie(void)
{
long long ntot, ntotleft;
int i, j, k, n, m, ngrp, maxfill, source, ndone;
int *nbuffer, *noffset, *nsend_local, *nsend, *numlist, *ndonelist;
int level, sendTask, recvTask, nexport, place;
double tstart, tend, sumt, sumcomm;
double timecomp = 0, timecommsumm = 0, timeimbalance = 0, sumimbalance;
int flag_chimie;
MPI_Status status;
int do_it;
int Ti0,Ti1,Ti2;
double t1,t2,t01,t02;
double tmin,tmax;
double minlivetime,maxlivetime;
double m1,m2,M0;
double NSNIa,NSNII,NDYIN;
double NSNIa_tot,NSNII_tot,NDYIN_tot,NSNIa_totlocal,NSNII_totlocal,NDYIN_totlocal;
double EgySN,EgySNlocal;
double EgySNThermal,EgySNKinetic;
int Nchim,Nchimlocal;
int Nwind,Nwindlocal;
int Nflag,Nflaglocal;
int Noldwind,Noldwindlocal;
double metals[NELEMENTS];
double FeH;
float MinRelMass=1e-3;
#ifdef DETAILED_CPU_OUTPUT_IN_CHIMIE
double *timecomplist;
double *timecommsummlist;
double *timeimbalancelist;
#endif
#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
#ifdef COMPUTE_VELOCITY_DISPERSION
double v1m,v2m;
#endif
/* `NumStUpdate' gives the number of particles on this processor that want a chimie computation */
for(n = 0, NumStUpdate = 0; n < N_gas+N_stars; n++)
{
#ifndef CHIMIE_TIMEBET
if(P[n].Ti_endstep == All.Ti_Current)
#else
/*nothing*/ /* as this is performed every ChimieTimeBetChimie, do it over all particles */
#endif
if(P[n].Type == ST)
{
m = P[n].StPIdx;
#ifdef FOF_SFR
if (StP[m].NStars != 0)
#endif
if ( (P[n].Mass/StP[m].InitialMass) > MinRelMass)
NumStUpdate++;
}
if(P[n].Type == 0)
SphP[n].dMass = 0.;
}
numlist = malloc(NTask * sizeof(int) * NTask);
MPI_Allgather(&NumStUpdate, 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);
i = 0; /* first gas particle, because stars may be hidden among gas particles */
ntotleft = ntot; /* particles left for all tasks together */
NSNIa_tot = 0;
NSNII_tot = 0;
NDYIN_tot = 0;
NSNIa_totlocal = 0;
NSNII_totlocal = 0;
NDYIN_totlocal = 0;
EgySN = 0;
EgySNlocal =0;
Nchimlocal = 0;
Nchim = 0;
Nwindlocal = 0;
Nwind = 0;
Noldwindlocal = 0;
Noldwind = 0;
Nflaglocal = 0;
Nflag = 0;
while(ntotleft > 0)
{
for(j = 0; j < NTask; j++)
nsend_local[j] = 0;
/* do local particles and prepare export list */
tstart = second();
for(nexport = 0, ndone = 0; i < N_gas+N_stars && nexport < All.BunchSizeChimie - NTask; i++)
{
/* only active particles and stars */
#ifndef CHIMIE_TIMEBET
if((P[i].Ti_endstep == All.Ti_Current)&&(P[i].Type == ST))
#else
if(P[i].Type == ST) /* as this is performed every ChimieTimeBetChimie, do it over all particles */
#endif
{
if(P[i].Type != ST)
{
printf("P[i].Type != ST, we better stop.\n");
printf("N_gas=%d (type=%d) i=%d (type=%d)\n",N_gas,P[N_gas].Type,i,P[i].Type);
printf("Please, check that you do not use PEANOHILBERT\n");
endrun(777001);
}
m = P[i].StPIdx;
#ifdef FOF_SFR
if (StP[m].NStars != 0)
#endif
if ( (P[i].Mass/StP[m].InitialMass) > MinRelMass)
{
flag_chimie = 0;
/******************************************/
/* do chimie */
/******************************************/
/*****************************************************/
/* look if a SN may have explode during the last step
/*****************************************************/
/***********************************************/
/***********************************************/
/* set the right table base of the metallicity */
set_table(0);
/***********************************************/
/***********************************************/
#ifdef FOF_SFR
/* minimum live time for a given metallicity */
minlivetime = star_lifetime(StP[m].Metal[NELEMENTS-1],StP[m].MassMax);
/* maximum live time for a given metallicity */
maxlivetime = star_lifetime(StP[m].Metal[NELEMENTS-1],StP[m].MassMin);
#else
/* minimum live time for a given metallicity */
minlivetime = star_lifetime(StP[m].Metal[NELEMENTS-1],Cp->Mmax*All.MsoltoCMU);
/* maximum live time for a given metallicity */
maxlivetime = star_lifetime(StP[m].Metal[NELEMENTS-1],Cp->Mmin*All.MsoltoCMU);
#endif
if (All.ComovingIntegrationOn)
{
/* FormationTime on the time line */
Ti0 = log(StP[m].FormationTime/All.TimeBegin) / All.Timebase_interval;
/* Beginning of time step on the time line */
#ifndef CHIMIE_TIMEBET
Ti1 = P[i].Ti_begstep;
#else
Ti1 = All.ChimieTi_begstep;
#endif
/* End of time step on the time line */
Ti2 = All.Ti_Current;
#ifdef COSMICTIME
t01 = get_cosmictime_difference(Ti0,Ti1);
t02 = get_cosmictime_difference(Ti0,Ti2);
#endif
}
else
{
#ifndef CHIMIE_TIMEBET
t1 = All.TimeBegin + (P[i].Ti_begstep * All.Timebase_interval);
#else
t1 = All.TimeBegin + (All.ChimieTi_begstep * All.Timebase_interval);
#endif
t2 = All.TimeBegin + (All.Ti_Current * All.Timebase_interval);
t01 = t1-StP[m].FormationTime;
t02 = t2-StP[m].FormationTime;
}
/* now treat all cases */
do_it=1;
#ifdef CHIMIE_ONE_SN_ONLY
if (All.Time<0.1)
do_it=0;
else
m1=m2=1; /* fix to 1 in order numerical problems with lifetime */
#else
/* beginning of interval */
if (t01>=minlivetime)
if (t01>=maxlivetime)
do_it=0; /* nothing to do */
else
m2 = star_mass_from_age(StP[m].Metal[NELEMENTS-1],t01);
else
m2 = Cp->Mmax*All.MsoltoCMU;
/* end of interval */
if (t02<=maxlivetime)
if (t02<=minlivetime)
do_it=0; /* nothing to do */
else
m1 = star_mass_from_age(StP[m].Metal[NELEMENTS-1],t02);
else
m1 = Cp->Mmin*All.MsoltoCMU;
#endif
//printf("Time=%g t01=%g t02=%g id=%d minlivetime=%g maxlivetime=%g \n",All.Time,t01,t02,P[i].ID,minlivetime,maxlivetime);
/* if some of the stars in the SSP explode between t1 and t2 */
if (do_it)
{
Nchimlocal++;
StP[m].Flag = 1; /* mark it as active */
if (m1>m2)
{
printf("m1=%g (%g Msol) > m2=%g (%g Msol) !!!\n\n",m1,m1*All.CMUtoMsol,m2,m2*All.CMUtoMsol);
endrun(777002);
}
M0 = StP[m].InitialMass;
for (k=0;k<NELEMENTS;k++)
metals[k] = StP[m].Metal[k];
#ifdef FOF_SFR
float current_mass;
NSNII = 0;
NSNIa = 0;
NDYIN = 0;
/* initialize */
StP[m].TotalEjectedGasMass = 0;
for (k=0;k<NELEMENTS;k++)
StP[m].TotalEjectedEltMass[k] = 0;
/**************************************************************************
first case: we are dealing with a particle containing individual stars
**************************************************************************/
if (StP[m].NStars>0)
{
- current_mass = StP[m].MassMax;
+ current_mass = StP[m].MassMax; /* start by the most massive star represented by the stellar particle */
- printf("(%d) FOF_SFR : INDIVIDUAL STARS id=%8d %8.4g %8.4g %8d current_mass=%g Mass=%g MassSSP\n",ThisTask,P[i].ID,StP[m].MassMin*All.CMUtoMsol,StP[m].MassMax*All.CMUtoMsol,StP[m].NStars,current_mass*All.CMUtoMsol,P[i].Mass*All.CMUtoMsol,StP[m].MassSSP*All.CMUtoMsol);
+ printf("(%d) FOF_SFR : INDIVIDUAL STARS id=%8d %8.4g %8.4g %8d current_mass=%g MassSSP=%g\n",ThisTask,P[i].ID,StP[m].MassMin*All.CMUtoMsol,StP[m].MassMax*All.CMUtoMsol,StP[m].NStars,current_mass*All.CMUtoMsol,P[i].Mass*All.CMUtoMsol,StP[m].MassSSP*All.CMUtoMsol);
+ fprintf(FdFOF_Chimie,"%15g : id=%8d INDIVIDUAL STARS %8.4g %8.4g %8d current_mass=%g MassSSP=%g %g\n",All.Time,P[i].ID,StP[m].MassMin*All.CMUtoMsol,StP[m].MassMax*All.CMUtoMsol,StP[m].NStars,current_mass*All.CMUtoMsol,P[i].Mass*All.CMUtoMsol,StP[m].MassSSP*All.CMUtoMsol);
if(current_mass > m2)
{
printf(" current_mass = %g > m2 = %g, this seems odd (id=%d)!!!\n ",current_mass*All.CMUtoMsol,m2*All.CMUtoMsol,P[i].ID);
+ fprintf(FdFOF_Chimie,"%15g : id=%8d !!! current_mass = %g > m2 = %g, this seems odd !!!\n ",All.Time,P[i].ID,current_mass*All.CMUtoMsol,m2*All.CMUtoMsol);
endrun(888029);
}
while ( (current_mass > m1) && (StP[m].NStars>0))
{
/* stop the loop if the mass goes beyond the minimum stellar mass responsible of ejetas */
if (current_mass < Cp->MassMinForEjecta*All.MsoltoCMU)
{
StP[m].NStars=0;
printf("(%d) FOF_SFR : id=%8d current_mass=%g ---> mass below MassMinForEjecta=%g\n",ThisTask,P[i].ID,current_mass*All.CMUtoMsol,Cp->MassMinForEjecta);
+ fprintf(FdFOF_Chimie,"%15g : id=%8d current_mass=%g ---> mass below MassMinForEjecta=%g\n",All.Time,P[i].ID,current_mass*All.CMUtoMsol,Cp->MassMinForEjecta);
break;
}
/****************
SNII
****************/
printf("(%d) FOF_SFR : id=%8d current_mass=%g m1=%g\n",ThisTask,P[i].ID,current_mass*All.CMUtoMsol,m1*All.CMUtoMsol);
+ fprintf(FdFOF_Chimie,"%15g : id=%8d current_mass=%g m1=%g\n",All.Time,P[i].ID,current_mass*All.CMUtoMsol,m1*All.CMUtoMsol);
if ( (Cp->SNII_Mmin*All.MsoltoCMU <= current_mass) && (current_mass <= Cp->SNII_Mmax*All.MsoltoCMU) )
{
NSNII++;
//StP[m].NStars--;
- printf("(%d) FOF_SFR : id=%8d one SNII\n",ThisTask,P[i].ID);
+ printf("(%d) FOF_SFR : id=%8d one SNII\n",ThisTask,P[i].ID);
+ fprintf(FdFOF_Chimie,"%15g : id=%8d one SNII\n",All.Time,P[i].ID);
SNII_Total_single_mass_ejection(current_mass,metals);
StP[m].TotalEjectedGasMass += SingleEjectedMass[0]; /* gas mass */
for (k=0;k<NELEMENTS;k++)
StP[m].TotalEjectedEltMass[k] += SingleEjectedMass[k+2]; /* metal mass */
}
#ifdef CHIMIE_AGB
else
{
/****************
DYIN
****************/
if ( (Cp->DYIN_Mmin*All.MsoltoCMU <= current_mass) && (current_mass <= Cp->DYIN_Mmax*All.MsoltoCMU) )
{
NDYIN++;
//StP[m].NStars--;
printf("(%d) FOF_SFR : id=%8d one DYIN\n",ThisTask,P[i].ID);
+ fprintf(FdFOF_Chimie,"%15g : id=%8d one DYIN\n",All.Time,P[i].ID);
DYIN_Total_single_mass_ejection(current_mass,metals);
StP[m].TotalEjectedGasMass += SingleEjectedMass[0]; /* gas mass */
for (k=0;k<NELEMENTS;k++)
StP[m].TotalEjectedEltMass[k] += SingleEjectedMass[k+2]; /* metal mass */
}
}
#endif /* CHIMIE_AGB */
/****************
SNIa
****************/
- NSNIa = NSNIa + SNIa_single_rate(current_mass);
+ NSNIa = NSNIa + SNIa_single_rate(current_mass);
+
/* find the next mass */
current_mass = optimal_get_next_mass_for_one_particle(m)*All.MsoltoCMU;
StP[m].OptIMF_CurrentMass = current_mass*All.CMUtoMsol;
StP[m].MassMax = current_mass;
/* remove the star */
StP[m].NStars--;
}
- printf("(%d) FOF_SFR : id=%8d %8d \n",ThisTask,P[i].ID,StP[m].NStars);
+ printf("(%d) FOF_SFR : id=%8d remaining stars= %8d \n",ThisTask,P[i].ID,StP[m].NStars);
+ fprintf(FdFOF_Chimie,"%15g : id=%8d remaining stars= %8d \n",All.Time,P[i].ID,StP[m].NStars);
// this is the standard way of doing
//NSNIa = SNIa_rate(m1,m2)*M0;
#ifdef CHIMIE_MC_SUPERNOVAE
double fNSNIa = NSNIa-floor(NSNIa);
NSNIa = floor(NSNIa);
if (get_Chimie_random_number(P[i].ID) < fNSNIa)
NSNIa = NSNIa+1;
#endif
/* compute ejectas for SNIa */
SNIa_Total_single_mass_ejection(0.5*(m1+m2),metals);
StP[m].TotalEjectedGasMass += SingleEjectedMass[0]*NSNIa; /* gas mass */
for (k=0;k<NELEMENTS;k++)
StP[m].TotalEjectedEltMass[k] += SingleEjectedMass[k+2]*NSNIa; /* metal mass */
-
+
+ if (NSNIa>0)
+ fprintf(FdFOF_Chimie,"%15g : id=%8d NSNIa=%d, m1=%g m2=%g\n",All.Time,P[i].ID,NSNIa,m1/All.MsoltoCMU,m2/All.MsoltoCMU);
}
/**************************************************************************
second case: we are dealing with a particle containing a portion of IMF
**************************************************************************/
else
{
m2 = dmin(m2,StP[m].MassMax);
m1 = dmax(m1,StP[m].MassMin);
/* number of SNIa */
NSNIa = SNIa_rate(m1,m2)*StP[m].MassSSP;
/* number of SNII */
NSNII = SNII_rate(m1,m2)*StP[m].MassSSP;
/* number of DYIN */
#ifdef CHIMIE_AGB
NDYIN = DYIN_rate(m1,m2)*StP[m].MassSSP;
#endif
printf("(%d) FOF_SFR : IMF PORTION id=%8d Mass=%g MassSSP=%g NSNII=%g NDYIN=%g NSNIa=%g\n",ThisTask,P[i].ID,P[i].Mass*All.CMUtoMsol,StP[m].MassSSP*All.CMUtoMsol,NSNII,NDYIN,NSNIa);
+ fprintf(FdFOF_Chimie,"%15g : id=%8d IMF PORTION Mass=%g MassSSP=%g NSNII=%g NDYIN=%g NSNIa=%g\n",All.Time,P[i].ID,P[i].Mass*All.CMUtoMsol,StP[m].MassSSP*All.CMUtoMsol,NSNII,NDYIN,NSNIa);
#ifdef CHIMIE_MC_SUPERNOVAE
double fNSNIa,fNSNII,fNDYIN;
/* discretize SNIa */
fNSNIa = NSNIa-floor(NSNIa);
NSNIa = floor(NSNIa);
if (get_Chimie_random_number(P[i].ID) < fNSNIa)
NSNIa = NSNIa+1;
/* discretize SNII */
fNSNII = NSNII-floor(NSNII);
NSNII = floor(NSNII);
//if (get_Chimie_random_number(P[i].ID) < fNSNII)
// NSNII = NSNII+1;
/* discretize DYIN */
#ifdef CHIMIE_AGB
fNDYIN = NDYIN-floor(NDYIN);
NDYIN = floor(NDYIN);
//if (get_Chimie_random_number(P[i].ID) < fNDYIN)
// NDYIN = NDYIN+1;
#endif /* CHIMIE_AGB */
#endif
/* compute ejectas */
Total_single_mass_ejection(0.5*(m1+m2),metals,NSNII,NSNIa,NDYIN);
StP[m].TotalEjectedGasMass = SingleEjectedMass[0]; /* gas mass */
for (k=0;k<NELEMENTS;k++)
StP[m].TotalEjectedEltMass[k] = SingleEjectedMass[k+2]; /* metal mass */
printf("(%d) FOF_SFR : IMF PORTION id=%8d NSNII=%g NDYIN=%g NSNIa=%g\n",ThisTask,P[i].ID,NSNII,NDYIN,NSNIa);
-
+ fprintf(FdFOF_Chimie,"%15g : id=%8d IMF PORTION NSNII=%g NDYIN=%g NSNIa=%g\n",All.Time,P[i].ID,NSNII,NDYIN,NSNIa);
}
#else /* FOF_SFR */
#ifdef CHIMIE_OPTIMAL_SAMPLING /* no FOF_SFR */
float current_mass;
NSNII = 0;
NSNIa = 0;
NDYIN = 0;
/* initialize */
StP[m].TotalEjectedGasMass = 0;
for (k=0;k<NELEMENTS;k++)
StP[m].TotalEjectedEltMass[k] = 0;
current_mass = StP[m].OptIMF_CurrentMass*All.MsoltoCMU;
if(current_mass > m2)
{
printf(" current_mass = %g > m2 = %g, this seems odd (id=%d)!!!\n ",current_mass*All.CMUtoMsol,m2*All.CMUtoMsol,P[i].ID);
endrun(888027);
}
while (current_mass > m1)
{
/****************
SNII
****************/
if ( (Cp->SNII_Mmin*All.MsoltoCMU <= current_mass) && (current_mass <= Cp->SNII_Mmax*All.MsoltoCMU) )
{
NSNII++;
SNII_Total_single_mass_ejection(current_mass,metals);
StP[m].TotalEjectedGasMass += SingleEjectedMass[0]; /* gas mass */
for (k=0;k<NELEMENTS;k++)
StP[m].TotalEjectedEltMass[k] += SingleEjectedMass[k+2]; /* metal mass */
}
#ifdef CHIMIE_AGB
else
{
/****************
DYIN
****************/
if ( (Cp->DYIN_Mmin*All.MsoltoCMU <= current_mass) && (current_mass <= Cp->DYIN_Mmax*All.MsoltoCMU) )
{
NDYIN++;
DYIN_Total_single_mass_ejection(current_mass,metals);
StP[m].TotalEjectedGasMass += SingleEjectedMass[0]; /* gas mass */
for (k=0;k<NELEMENTS;k++)
StP[m].TotalEjectedEltMass[k] += SingleEjectedMass[k+2]; /* metal mass */
}
}
#endif
/* find the next mass */
current_mass = optimal_get_next_mass_for_one_particle(m)*All.MsoltoCMU;
StP[m].OptIMF_CurrentMass = current_mass*All.CMUtoMsol;
}
/****************
SNIa (similar than whith CHIMIE_MC_SUPERNOVAE)
****************/
/* compute the number of SNIa (this remains the same) */
NSNIa = SNIa_rate(m1,m2)*M0;
double fNSNIa = NSNIa-floor(NSNIa);
NSNIa = floor(NSNIa);
if (get_Chimie_random_number(P[i].ID) < fNSNIa)
NSNIa = NSNIa+1;
/* compute ejectas for SNIa */
SNIa_Total_single_mass_ejection(0.5*(m1+m2),metals);
StP[m].TotalEjectedGasMass += SingleEjectedMass[0]*NSNIa; /* gas mass */
for (k=0;k<NELEMENTS;k++)
StP[m].TotalEjectedEltMass[k] += SingleEjectedMass[k+2]*NSNIa; /* metal mass */
#else /* no CHIMIE_OPTIMAL_SAMPLING */
/* number of SNIa */
NSNIa = SNIa_rate(m1,m2)*M0;
/* number of SNII */
NSNII = SNII_rate(m1,m2)*M0;
/* number of DYIN */
#ifdef CHIMIE_AGB
NDYIN = DYIN_rate(m1,m2)*M0;
#endif
#ifdef CHIMIE_MC_SUPERNOVAE
double fNSNIa,fNSNII,fNDYIN;
/* discretize SNIa */
fNSNIa = NSNIa-floor(NSNIa);
NSNIa = floor(NSNIa);
if (get_Chimie_random_number(P[i].ID) < fNSNIa)
NSNIa = NSNIa+1;
/* discretize SNII */
fNSNII = NSNII-floor(NSNII);
NSNII = floor(NSNII);
if (get_Chimie_random_number(P[i].ID) < fNSNII)
NSNII = NSNII+1;
/* discretize DYIN */
#ifdef CHIMIE_AGB
fNDYIN = NDYIN-floor(NDYIN);
NDYIN = floor(NDYIN);
if (get_Chimie_random_number(P[i].ID) < fNDYIN)
NDYIN = NDYIN+1;
#endif
#ifdef CHIMIE_ONE_SN_ONLY
/* here, we force to explode one and only one */
NSNIa=0;
NSNII=1;
NDYIN=0;
m1 = m2 = All.ChimieOneSNMass;
printf("CHIMIE_ONE_SN_ONLY : explode %g Msol SN.\n",m1*All.CMUtoMsol);
#endif
/* compute ejectas */
Total_single_mass_ejection(0.5*(m1+m2),metals,NSNII,NSNIa,NDYIN);
StP[m].TotalEjectedGasMass = SingleEjectedMass[0]; /* gas mass */
for (k=0;k<NELEMENTS;k++)
StP[m].TotalEjectedEltMass[k] = SingleEjectedMass[k+2]; /* metal mass */
#else /* no CHIMIE_MC_SUPERNOVAE */
/* compute ejectas */
Total_mass_ejection(m1,m2,M0,metals);
StP[m].TotalEjectedGasMass = EjectedMass[0]; /* gas mass */
for (k=0;k<NELEMENTS;k++)
StP[m].TotalEjectedEltMass[k] = EjectedMass[k+2]; /* metal mass */
#endif /* CHIMIE_MC_SUPERNOVAE */
#endif /* CHIMIE_OPTIMAL_SAMPLING */
#endif /* FOF_SFR */
if (P[i].Mass-StP[m].TotalEjectedGasMass>0)
{
#ifdef CHIMIE_STATS
if (StP[m].TotalEjectedGasMass>0)
{
fprintf(FdChimieStatsSNs,"%4d %10d %8.4f %8d %10.3g %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f ",ThisTask,All.NumCurrentTiStep,All.Time, P[i].ID,P[i].Mass,NSNII,NSNIa,0.5*(m1+m2)*All.CMUtoMsol,P[i].Pos[0],P[i].Pos[1],P[i].Pos[2]);
fprintf(FdChimieStatsSNs,"%10.3g ",StP[m].TotalEjectedGasMass);
for (k=0;k<NELEMENTS;k++)
fprintf(FdChimieStatsSNs,"%10.3g ",StP[m].TotalEjectedEltMass[k]);
fprintf(FdChimieStatsSNs,"\n");
}
#endif
if (StP[m].TotalEjectedGasMass>0)
flag_chimie=1;
/* compute injected energy */
StP[m].TotalEjectedEgySpec = All.ChimieSupernovaEnergy* (NSNIa + NSNII) /StP[m].TotalEjectedGasMass;
StP[m].NumberOfSNIa = NSNIa;
StP[m].NumberOfSNII = NSNII;
EgySNlocal += All.ChimieSupernovaEnergy* (NSNIa + NSNII);
NSNIa_totlocal += NSNIa;
NSNII_totlocal += NSNII;
NDYIN_totlocal += NDYIN;
/* correct mass particle */
P[i].Mass = P[i].Mass-StP[m].TotalEjectedGasMass;
if(P[i].Mass<0)
endrun(777023);
}
else
{
printf("CHIMIE : mass wants to be less than zero...\n");
printf("CHIMIE : ID=%d Mass=%g StP[m].TotalEjectedGasMass=%g\n",P[i].ID,P[i].Mass*All.CMUtoMsol,StP[m].TotalEjectedGasMass*All.CMUtoMsol);
}
}
/******************************************/
/* end do chimie */
/******************************************/
ndone++;
if (flag_chimie)
{
for(j = 0; j < NTask; j++)
Exportflag[j] = 0;
chimie_evaluate(i, 0);
for(j = 0; j < NTask; j++)
{
if(Exportflag[j])
{
for(k = 0; k < 3; k++)
{
ChimieDataIn[nexport].Pos[k] = P[i].Pos[k];
ChimieDataIn[nexport].Vel[k] = P[i].Vel[k];
}
ChimieDataIn[nexport].ID = P[i].ID;
ChimieDataIn[nexport].Timestep = P[i].Ti_endstep - P[i].Ti_begstep;
ChimieDataIn[nexport].Hsml = StP[m].Hsml;
ChimieDataIn[nexport].Density = StP[m].Density;
ChimieDataIn[nexport].Y = StP[m].Y;
#ifdef CHIMIE_KINETIC_FEEDBACK
ChimieDataIn[nexport].NgbMass = StP[m].NgbMass;
#endif
ChimieDataIn[nexport].TotalEjectedGasMass = StP[m].TotalEjectedGasMass;
for(k = 0; k < NELEMENTS; k++)
ChimieDataIn[nexport].TotalEjectedEltMass[k] = StP[m].TotalEjectedEltMass[k];
ChimieDataIn[nexport].TotalEjectedEgySpec = StP[m].TotalEjectedEgySpec;
ChimieDataIn[nexport].NumberOfSNIa = StP[m].NumberOfSNIa;
ChimieDataIn[nexport].NumberOfSNII = StP[m].NumberOfSNII;
#ifdef WITH_ID_IN_HYDRA
ChimieDataIn[nexport].ID = P[i].ID;
#endif
#if CHIMIE_EJECTA_RADIUS == 2
ChimieDataIn[nexport].Pressure = StP[m].Pressure;
#endif
ChimieDataIn[nexport].Index = i;
ChimieDataIn[nexport].Task = j;
nexport++;
nsend_local[j]++;
}
}
}
}
}
}
tend = second();
timecomp += timediff(tstart, tend);
qsort(ChimieDataIn, nexport, sizeof(struct chimiedata_in), chimie_compare_key);
for(j = 1, noffset[0] = 0; j < NTask; j++)
noffset[j] = noffset[j - 1] + nsend_local[j - 1];
tstart = second();
MPI_Allgather(nsend_local, NTask, MPI_INT, nsend, NTask, MPI_INT, MPI_COMM_WORLD);
tend = second();
timeimbalance += timediff(tstart, tend);
/* now do the particles that need to be exported */
for(level = 1; level < (1 << PTask); level++)
{
tstart = 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.BunchSizeChimie)
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(&ChimieDataIn[noffset[recvTask]],
nsend_local[recvTask] * sizeof(struct chimiedata_in), MPI_BYTE,
recvTask, TAG_CHIMIE_A,
&ChimieDataGet[nbuffer[ThisTask]],
nsend[recvTask * NTask + ThisTask] * sizeof(struct chimiedata_in), MPI_BYTE,
recvTask, TAG_CHIMIE_A, MPI_COMM_WORLD, &status);
}
}
for(j = 0; j < NTask; j++)
if((j ^ ngrp) < NTask)
nbuffer[j] += nsend[(j ^ ngrp) * NTask + j];
}
tend = second();
timecommsumm += timediff(tstart, tend);
/* now do the imported particles */
tstart = second();
for(j = 0; j < nbuffer[ThisTask]; j++)
chimie_evaluate(j, 1);
tend = second();
timecomp += timediff(tstart, tend);
/* do a block to measure imbalance */
tstart = second();
MPI_Barrier(MPI_COMM_WORLD);
tend = second();
timeimbalance += timediff(tstart, tend);
/* get the result */
tstart = 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.BunchSizeChimie)
break;
sendTask = ThisTask;
recvTask = ThisTask ^ ngrp;
if(recvTask < NTask)
{
if(nsend[ThisTask * NTask + recvTask] > 0 || nsend[recvTask * NTask + ThisTask] > 0)
{
/* send the results */
MPI_Sendrecv(&ChimieDataResult[nbuffer[ThisTask]],
nsend[recvTask * NTask + ThisTask] * sizeof(struct chimiedata_out),
MPI_BYTE, recvTask, TAG_CHIMIE_B,
&ChimieDataPartialResult[noffset[recvTask]],
nsend_local[recvTask] * sizeof(struct chimiedata_out),
MPI_BYTE, recvTask, TAG_CHIMIE_B, MPI_COMM_WORLD, &status);
/* add the result to the particles */
for(j = 0; j < nsend_local[recvTask]; j++)
{
source = j + noffset[recvTask];
place = ChimieDataIn[source].Index;
// for(k = 0; k < 3; k++)
// SphP[place].HydroAccel[k] += HydroDataPartialResult[source].Acc[k];
//
// SphP[place].DtEntropy += HydroDataPartialResult[source].DtEntropy;
//#ifdef FEEDBACK
// SphP[place].DtEgySpecFeedback += HydroDataPartialResult[source].DtEgySpecFeedback;
//#endif
// if(SphP[place].MaxSignalVel < HydroDataPartialResult[source].MaxSignalVel)
// SphP[place].MaxSignalVel = HydroDataPartialResult[source].MaxSignalVel;
//#ifdef COMPUTE_VELOCITY_DISPERSION
// for(k = 0; k < VELOCITY_DISPERSION_SIZE; k++)
// SphP[place].VelocityDispersion[k] += HydroDataPartialResult[source].VelocityDispersion[k];
//#endif
}
}
}
for(j = 0; j < NTask; j++)
if((j ^ ngrp) < NTask)
nbuffer[j] += nsend[(j ^ ngrp) * NTask + j];
}
tend = second();
timecommsumm += timediff(tstart, tend);
level = ngrp - 1;
}
MPI_Allgather(&ndone, 1, MPI_INT, ndonelist, 1, MPI_INT, MPI_COMM_WORLD);
for(j = 0; j < NTask; j++)
ntotleft -= ndonelist[j];
}
free(ndonelist);
free(nsend);
free(nsend_local);
free(nbuffer);
free(noffset);
/* do final operations on results */
tstart = second();
for(i = 0; i < N_gas; i++)
{
if (P[i].Type==0)
{
P[i].Mass += SphP[i].dMass;
SphP[i].dMass = 0.;
}
}
tend = second();
timecomp += timediff(tstart, tend);
/* collect some timing information */
MPI_Reduce(&timecomp, &sumt, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
MPI_Reduce(&timecommsumm, &sumcomm, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
MPI_Reduce(&timeimbalance, &sumimbalance, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
if(ThisTask == 0)
{
All.CPU_ChimieCompWalk += sumt / NTask;
All.CPU_ChimieCommSumm += sumcomm / NTask;
All.CPU_ChimieImbalance += sumimbalance / NTask;
}
#ifdef DETAILED_CPU_OUTPUT_IN_CHIMIE
numlist = malloc(sizeof(int) * NTask);
timecomplist = malloc(sizeof(double) * NTask);
timecommsummlist = malloc(sizeof(double) * NTask);
timeimbalancelist = malloc(sizeof(double) * NTask);
MPI_Gather(&NumStUpdate, 1, MPI_INT, numlist, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Gather(&timecomp, 1, MPI_DOUBLE, timecomplist, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
MPI_Gather(&timecommsumm, 1, MPI_DOUBLE, timecommsummlist, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
MPI_Gather(&timeimbalance, 1, MPI_DOUBLE, timeimbalancelist, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
if(ThisTask == 0)
{
fprintf(FdTimings, "\n chimie\n\n");
fprintf(FdTimings, "Nupdate ");
for (i=0;i<NTask;i++)
fprintf(FdTimings, "%12d ",numlist[i]); /* nombre de part par proc */
fprintf(FdTimings, "\n");
fprintf(FdTimings, "timecomp ");
for (i=0;i<NTask;i++)
fprintf(FdTimings, "%12g ",timecomplist[i]);
fprintf(FdTimings, "\n");
fprintf(FdTimings, "timecommsumm ");
for (i=0;i<NTask;i++)
fprintf(FdTimings, "%12g ",timecommsummlist[i]);
fprintf(FdTimings, "\n");
fprintf(FdTimings, "timeimbalance ");
for (i=0;i<NTask;i++)
fprintf(FdTimings, "%12g ",timeimbalancelist[i]);
fprintf(FdTimings, "\n");
fprintf(FdTimings, "\n");
}
free(timeimbalancelist);
free(timecommsummlist);
free(timecomplist);
free(numlist);
#endif
/* collect some chimie informations */
MPI_Reduce(&NSNIa_totlocal, &NSNIa_tot, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
MPI_Reduce(&NSNII_totlocal, &NSNII_tot, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
MPI_Reduce(&NDYIN_totlocal, &NDYIN_tot, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
MPI_Reduce(&EgySNlocal, &EgySN, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
MPI_Reduce(&Nchimlocal, &Nchim, 1, MPI_INT , MPI_SUM, 0, MPI_COMM_WORLD);
#ifdef CHIMIE_THERMAL_FEEDBACK
EgySNThermal = EgySN*(1-All.ChimieKineticFeedbackFraction);
#else
EgySNThermal = 0;
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
EgySNKinetic = EgySN*All.ChimieKineticFeedbackFraction;
/* count number of wind particles */
for(i = 0; i < N_gas; i++)
{
if (P[i].Type==0)
{
if (SphP[i].WindTime >= (All.Time-All.ChimieWindTime))
Nwindlocal++;
//else
// if (SphP[i].WindTime > All.TimeBegin-2*All.ChimieWindTime)
// Noldwindlocal++;
if (SphP[i].WindFlag)
Nflaglocal++;
}
}
MPI_Reduce(&Nwindlocal, &Nwind, 1, MPI_INT , MPI_SUM, 0, MPI_COMM_WORLD);
MPI_Reduce(&Noldwindlocal, &Noldwind, 1, MPI_INT , MPI_SUM, 0, MPI_COMM_WORLD);
MPI_Allreduce(&Nflaglocal, &Nflag, 1, MPI_INT , MPI_SUM, MPI_COMM_WORLD);
#else
EgySNKinetic = 0;
#endif
/* write some info */
if (ThisTask==0)
{
fprintf(FdChimie, "%15g %10d %15g %15g %15g %15g %15g %10d %10d %10d\n",All.Time,Nchim,NSNIa_tot,NSNII_tot,EgySN,EgySNThermal,EgySNKinetic,Nwind,Noldwind,Nflag);
fflush(FdChimie);
}
/* this is no longer used */
// if (Nflag>0)
// {
// SetMinTimeStepForActives=1;
// if (ThisTask==0)
// fprintf(FdLog,"%g : !!! set min timestep for active particles !!!\n",All.Time);
// }
#ifdef CHIMIE_ONE_SN_ONLY
if (EgySN>0)
All.ChimieOneSN=1;
MPI_Bcast(&All.ChimieOneSN, 1, MPI_INT, 0, MPI_COMM_WORLD);
#endif
}
/*! This function is the 'core' of the Chemie computation. A target
* particle is specified which may either be local, or reside in the
* communication buffer.
*/
void chimie_evaluate(int target, int mode)
{
int j, n, startnode, numngb,numngb_inbox,k;
FLOAT *pos,*vel;
//FLOAT *vel;
//FLOAT mass;
double h, h2;
double acc[3];
double dx, dy, dz;
double wk, r, r2, u=0;
double hinv=1, hinv3;
int target_stp;
double density;
double Y;
#ifdef CHIMIE_KINETIC_FEEDBACK
double ngbmass;
double p;
#endif
double aij;
double ejectedGasMass;
double ejectedEltMass[NELEMENTS];
double ejectedEgySpec;
double NumberOfSNIa;
double NumberOfSNII;
double mass_k;
double NewMass;
double fv,vi2,vj2;
double EgySpec,NewEgySpec;
double DeltaEntropy;
double DeltaVel[3];
#ifndef LONGIDS
unsigned int id; /*!< particle identifier */
#else
unsigned long long id; /*!< particle identifier */
#endif
#if CHIMIE_EJECTA_RADIUS == 2
double rho,E51,n0,P04,pressure,P0;
#endif
if(mode == 0)
{
pos = P[target].Pos;
vel = P[target].Vel;
id = P[target].ID;
target_stp = P[target].StPIdx;
h = StP[target_stp].Hsml;
density = StP[target_stp].Density;
Y = StP[target_stp].Y;
#ifdef CHIMIE_KINETIC_FEEDBACK
ngbmass = StP[target_stp].NgbMass;
#endif
ejectedGasMass = StP[target_stp].TotalEjectedGasMass;
for(k=0;k<NELEMENTS;k++)
ejectedEltMass[k] = StP[target_stp].TotalEjectedEltMass[k];
ejectedEgySpec = StP[target_stp].TotalEjectedEgySpec;
NumberOfSNIa = StP[target_stp].NumberOfSNIa;
NumberOfSNII = StP[target_stp].NumberOfSNII;
#if CHIMIE_EJECTA_RADIUS == 2
pressure = StP[target_stp].Pressure;
#endif
}
else
{
pos = ChimieDataGet[target].Pos;
vel = ChimieDataGet[target].Vel;
id = ChimieDataGet[target].ID;
h = ChimieDataGet[target].Hsml;
density = ChimieDataGet[target].Density;
Y = ChimieDataGet[target].Y;
#ifdef CHIMIE_KINETIC_FEEDBACK
ngbmass = ChimieDataGet[target].NgbMass;
#endif
ejectedGasMass = ChimieDataGet[target].TotalEjectedGasMass;
for(k=0;k<NELEMENTS;k++)
ejectedEltMass[k] = ChimieDataGet[target].TotalEjectedEltMass[k];
ejectedEgySpec = ChimieDataGet[target].TotalEjectedEgySpec;
NumberOfSNIa = ChimieDataGet[target].NumberOfSNIa;
NumberOfSNII = ChimieDataGet[target].NumberOfSNII;
#if CHIMIE_EJECTA_RADIUS == 2
pressure = ChimieDataGet[target].Pressure;
#endif
}
#if CHIMIE_EJECTA_RADIUS == 1
h = All.ChimieEjectaRadius;
#elif CHIMIE_EJECTA_RADIUS == 2 /* Maximum Blast radius computed according to Chevalier 1974 */
/* density in cgs */
rho = density *All.UnitDensity_in_cgs*(All.HubbleParam*All.HubbleParam);
/* pressure in cgs */
P0 = pressure * All.UnitDensity_in_cgs*(All.HubbleParam*All.HubbleParam) * All.UnitEnergy_in_cgs/All.UnitMass_in_g;
E51 = 1.0;
n0 = rho/PROTONMASS;
P04 = 1e-4 * P0/BOLTZMANN;
h = pow(10,1.74) * pow(E51,0.32) * pow(n0,-0.16) * pow(P04,-0.2); /* [in pc] Chevalier 1974 */
h = h/1e3; /* [in kpc] */
h = dmin(h,1);
h = h* KPC_IN_CM/All.UnitLength_in_cm * All.HubbleParam; /* [in code unit length] */
#endif
/* initialize variables before SPH loop is started */
acc[0] = acc[1] = acc[2] = 0;
vi2 = 0;
for(k=0;k<3;k++)
vi2 += vel[k]*vel[k];
h2 = h * h;
hinv = 1.0 / h;
#ifndef TWODIMS
hinv3 = hinv * hinv * hinv;
#else
hinv3 = hinv * hinv / boxSize_Z;
#endif
/* Now start the actual SPH computation for this particle */
startnode = All.MaxPart;
numngb = 0;
do
{
numngb_inbox = ngb_treefind_variable_for_chimie(&pos[0], h, &startnode);
for(n = 0; n < numngb_inbox; n++)
{
j = Ngblist[n];
dx = pos[0] - P[j].Pos[0];
dy = pos[1] - P[j].Pos[1];
dz = pos[2] - P[j].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)
{
numngb++;
r = sqrt(r2);
u = r * hinv;
if(u < 0.5)
{
wk = hinv3 * (KERNEL_COEFF_1 + KERNEL_COEFF_2 * (u - 1) * u * u);
}
else
{
wk = hinv3 * KERNEL_COEFF_5 * (1.0 - u) * (1.0 - u) * (1.0 - u);
}
/* normalisation using mass */
//aij = P[j].Mass*wk/density;
/* normalisation using volume */
/* !!! si on utilise, il faut stoquer une nouvelle variable : OldDensity, car density est modifié plus bas... */
//aij = P[j].Mass/SphP[j].Density*wk/volume;
/* !!! we shoud better use an OldDensity here, as .Density may slighly change after */
#if CHIMIE_ELTS_WEIGHTING == 0
aij = P[j].Mass * wk; // 0: mass + kernel weighting (default, Revaz & Jablonka 2012)
#elif CHIMIE_ELTS_WEIGHTING == 1
aij = P[j].Mass/SphP[j].Density * wk; // 1: volume + kernel weighting
#elif CHIMIE_ELTS_WEIGHTING == 2
aij = wk; // 2: number + kernel weighting
#elif CHIMIE_ELTS_WEIGHTING == 3
aij = P[j].Mass; // 3: mass weighting
#elif CHIMIE_ELTS_WEIGHTING == 4
aij = P[j].Mass/SphP[j].Density; // 4: volume weighting
#elif CHIMIE_ELTS_WEIGHTING == 5
aij = 1; // 5: number weighting
#endif
aij = aij/Y; // normalisation
#ifdef CHIMIE_STATS /* before the interaction */
fprintf(FdChimieStatsGas,"%4d %10d %8.4f %8d %8d %10.3g %10.3g %10.3g %10.3g ",ThisTask,All.NumCurrentTiStep,All.Time, P[j].ID,id,aij,P[j].Pos[0],P[j].Pos[1],P[j].Pos[2]);
fprintf(FdChimieStatsGas,"%10.3g ",P[j].Mass);
#ifdef CHIMIE_SMOOTH_METALS
for (k=0;k<NELEMENTS;k++)
fprintf(FdChimieStatsGas,"%10.3g ",SphP[j].MassMetal[k]*P[j].Mass);
#else
for (k=0;k<NELEMENTS;k++)
fprintf(FdChimieStatsGas,"%10.3g ",SphP[j].Metal[k]*P[j].Mass);
#endif
fprintf(FdChimieStatsGas," ");
#endif
/* metal injection */
for(k=0;k<NELEMENTS;k++)
{
#ifdef CHIMIE_SMOOTH_METALS
mass_k = SphP[j].MassMetal[k]*P[j].Mass; /* mass of elt k */
SphP[j].MassMetal[k] = ( mass_k + aij*ejectedEltMass[k] )/( P[j].Mass + aij*ejectedGasMass );
#else
mass_k = SphP[j].Metal[k]*P[j].Mass; /* mass of elt k */
SphP[j].Metal[k] = ( mass_k + aij*ejectedEltMass[k] )/( P[j].Mass + aij*ejectedGasMass );
#endif
}
/* new mass */
NewMass = P[j].Mass + aij*ejectedGasMass;
#ifdef CHIMIE_STATS /* after the interaction !!! slighly wrong, as the mass is not the final ones (could receive mass from other particles) */
fprintf(FdChimieStatsGas,"%10.3g ",NewMass);
#ifdef CHIMIE_SMOOTH_METALS
for (k=0;k<NELEMENTS;k++)
fprintf(FdChimieStatsGas,"%10.3g ",SphP[j].MassMetal[k]*NewMass);
#else
for (k=0;k<NELEMENTS;k++)
fprintf(FdChimieStatsGas,"%10.3g ",SphP[j].Metal[k]*NewMass);
#endif
fprintf(FdChimieStatsGas,"\n");
#endif
/* new velocity */
vj2 = 0;
for(k=0;k<3;k++)
vj2 += SphP[j].VelPred[k]*SphP[j].VelPred[k];
fv = sqrt( (P[j].Mass/NewMass) + aij*(ejectedGasMass/NewMass) * (vi2/vj2) );
for(k=0;k<3;k++)
{
DeltaVel[k] = fv*SphP[j].VelPred[k] - SphP[j].VelPred[k];
SphP[j].VelPred[k] += DeltaVel[k];
P[j].Vel [k] += DeltaVel[k];
}
/* spec energy at current step */
#ifdef DENSITY_INDEPENDENT_SPH
EgySpec = SphP[j].EntropyPred / GAMMA_MINUS1 * pow(SphP[j].EgyWtDensity*a3inv, GAMMA_MINUS1);
#else
EgySpec = SphP[j].EntropyPred / GAMMA_MINUS1 * pow(SphP[j].Density*a3inv, GAMMA_MINUS1);
#endif
/* new egyspec */
NewEgySpec = (EgySpec )*(P[j].Mass/NewMass);
#ifdef CHIMIE_TIMEBET
/* avoid problematic values */ /* added with the new chimie timing */
if(NewEgySpec<All.MinEgySpec)
NewEgySpec = All.MinEgySpec;
#endif
/* new density */
#ifdef DENSITY_INDEPENDENT_SPH
SphP[j].Density = SphP[j].Density*NewMass/P[j].Mass;
SphP[j].EgyWtDensity = SphP[j].EgyWtDensity*NewMass/P[j].Mass;
#else
SphP[j].Density = SphP[j].Density*NewMass/P[j].Mass;
#endif
/* new entropy */
#ifdef DENSITY_INDEPENDENT_SPH
DeltaEntropy = GAMMA_MINUS1*NewEgySpec/pow(SphP[j].EgyWtDensity*a3inv, GAMMA_MINUS1) - SphP[j].EntropyPred;
#else
DeltaEntropy = GAMMA_MINUS1*NewEgySpec/pow(SphP[j].Density*a3inv, GAMMA_MINUS1) - SphP[j].EntropyPred;
#endif
SphP[j].EntropyPred += DeltaEntropy;
SphP[j].Entropy += DeltaEntropy;
#ifdef CHIMIE_THERMAL_FEEDBACK
SphP[j].DeltaEgySpec += (1.-All.ChimieKineticFeedbackFraction)*(ejectedGasMass*ejectedEgySpec)* aij/NewMass;
SphP[j].NumberOfSNII += NumberOfSNII*aij;
SphP[j].NumberOfSNIa += NumberOfSNIa*aij;
#ifdef TIMESTEP_UPDATE_FOR_FEEDBACK
if(P[j].Ti_endstep != All.Ti_Current)
make_particle_active(j);
#endif
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
p = (All.ChimieKineticFeedbackFraction*ejectedEgySpec*ejectedGasMass)/(0.5*ngbmass*All.ChimieWindSpeed*All.ChimieWindSpeed);
double r;
r = get_Chimie_random_number(P[j].ID+id);
if ( r < p) /* we should maybe have a 2d table here... */
{
if (SphP[j].WindTime < (All.Time-All.ChimieWindTime)) /* not a wind particle */
{
SphP[j].WindFlag = 1;
SphP[j].WindTime = All.Time;
}
}
#endif
#ifdef CHECK_ENTROPY_SIGN
if ((SphP[j].EntropyPred < 0)||(SphP[j].Entropy < 0))
{
printf("\ntask=%d: entropy less than zero in chimie_evaluate !\n", ThisTask);
printf("ID=%d Entropy=%g EntropyPred=%g DeltaEntropy=%g\n",P[j].ID,SphP[j].Entropy,SphP[j].EntropyPred,DeltaEntropy);
fflush(stdout);
endrun(777003);
}
#endif
/* store mass diff. */
SphP[j].dMass += NewMass-P[j].Mass;
}
}
}
while(startnode >= 0);
/* Now collect the result at the right place */
if(mode == 0)
{
// for(k = 0; k < 3; k++)
// SphP[target].HydroAccel[k] = acc[k];
// SphP[target].DtEntropy = dtEntropy;
//#ifdef FEEDBACK
// SphP[target].DtEgySpecFeedback = dtEgySpecFeedback;
//#endif
// SphP[target].MaxSignalVel = maxSignalVel;
//#ifdef COMPUTE_VELOCITY_DISPERSION
// for(k = 0; k < VELOCITY_DISPERSION_SIZE; k++)
// SphP[target].VelocityDispersion[k] = VelocityDispersion[k];
//#endif
}
else
{
// for(k = 0; k < 3; k++)
// HydroDataResult[target].Acc[k] = acc[k];
// HydroDataResult[target].DtEntropy = dtEntropy;
//#ifdef FEEDBACK
// HydroDataResult[target].DtEgySpecFeedback = dtEgySpecFeedback;
//#endif
// HydroDataResult[target].MaxSignalVel = maxSignalVel;
//#ifdef COMPUTE_VELOCITY_DISPERSION
// for(k = 0; k < VELOCITY_DISPERSION_SIZE; k++)
// HydroDataResult[target].VelocityDispersion[k] = VelocityDispersion[k];
//#endif
}
}
/*! 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 chimie_compare_key(const void *a, const void *b)
{
if(((struct chimiedata_in *) a)->Task < (((struct chimiedata_in *) b)->Task))
return -1;
if(((struct chimiedata_in *) a)->Task > (((struct chimiedata_in *) b)->Task))
return +1;
return 0;
}
/****************************************************************************************/
/*
/*
/*
/* PYTHON INTERFACE
/*
/*
/*
/****************************************************************************************/
#ifdef PYCHEM
static PyObject *
chemistry_CodeUnits_to_SolarMass_Factor(PyObject *self, PyObject *args)
{
return Py_BuildValue("d",All.CMUtoMsol);
}
static PyObject *
chemistry_SolarMass_to_CodeUnits_Factor(PyObject *self, PyObject *args)
{
return Py_BuildValue("d",All.MsoltoCMU);
}
static PyObject *
chemistry_SetVerbosityOn(PyObject *self, PyObject *args)
{
verbose=1;
return Py_BuildValue("i",0);
}
static PyObject *
chemistry_SetVerbosityOff(PyObject *self, PyObject *args)
{
verbose=0;
return Py_BuildValue("i",0);
}
static PyObject * chemistry_InitDefaultParameters(void)
{
/* list of Gadget parameters */
/* System of units */
All.UnitLength_in_cm = 3.085e+21; /* 1.0 kpc */
All.UnitMass_in_g = 1.989e+43; /* 1.0e10 solar masses */
All.UnitVelocity_in_cm_per_s = 20725573.785998672; /* 207 km/sec */
All.GravityConstantInternal = 0;
All.HubbleParam = 1;
/* other usefull constants */
All.UnitTime_in_s = All.UnitLength_in_cm / All.UnitVelocity_in_cm_per_s;
All.UnitTime_in_Megayears=All.UnitTime_in_s / SEC_PER_MEGAYEAR;
All.CMUtoMsol = All.UnitMass_in_g/SOLAR_MASS/All.HubbleParam; /* convertion factor from Code Mass Unit to Solar Mass */
All.MsoltoCMU = 1/All.CMUtoMsol; /* convertion factor from Solar Mass to Code Mass Unit */
return Py_BuildValue("i",1);
}
static PyObject * SetParameters(PyObject *dict)
{
PyObject *key;
PyObject *value;
int ivalue;
float fvalue;
double dvalue;
/* check that it is a PyDictObject */
if(!PyDict_Check(dict))
{
PyErr_SetString(PyExc_AttributeError, "argument is not a dictionary.");
return NULL;
}
if (PyDict_Size(dict)==0)
return Py_BuildValue("i",0);
Py_ssize_t pos=0;
while(PyDict_Next(dict,&pos,&key,&value))
{
if(PyString_Check(key))
{
/* System of units */
if(strcmp(PyString_AsString(key), "UnitLength_in_cm")==0)
{
if(PyInt_Check(value)||PyLong_Check(value)||PyFloat_Check(value))
All.UnitLength_in_cm = PyFloat_AsDouble(value);
}
if(strcmp(PyString_AsString(key), "UnitMass_in_g")==0)
{
if(PyInt_Check(value)||PyLong_Check(value)||PyFloat_Check(value))
All.UnitMass_in_g = PyFloat_AsDouble(value);
}
if(strcmp(PyString_AsString(key), "UnitVelocity_in_cm_per_s")==0)
{
if(PyInt_Check(value)||PyLong_Check(value)||PyFloat_Check(value))
All.UnitVelocity_in_cm_per_s = PyFloat_AsDouble(value);
}
if(strcmp(PyString_AsString(key), "HubbleParam")==0)
{
if(PyInt_Check(value)||PyLong_Check(value)||PyFloat_Check(value))
All.HubbleParam = PyFloat_AsDouble(value);
}
if(strcmp(PyString_AsString(key), "GravityConstantInternal")==0)
{
if(PyInt_Check(value)||PyLong_Check(value)||PyFloat_Check(value))
All.GravityConstantInternal = PyFloat_AsDouble(value);
}
}
}
/* other usefull constants */
All.UnitTime_in_s = All.UnitLength_in_cm / All.UnitVelocity_in_cm_per_s;
All.UnitTime_in_Megayears=All.UnitTime_in_s / SEC_PER_MEGAYEAR;
All.CMUtoMsol = All.UnitMass_in_g/SOLAR_MASS/All.HubbleParam; /* convertion factor from Code Mass Unit to Solar Mass */
All.MsoltoCMU = 1/All.CMUtoMsol; /* convertion factor from Solar Mass to Code Mass Unit */
return Py_BuildValue("i",1);
}
static PyObject * chemistry_SetParameters(PyObject *self, PyObject *args)
{
PyObject *dict;
/* here, we can have either arguments or dict directly */
if(PyDict_Check(args))
{
dict = args;
}
else
{
if (! PyArg_ParseTuple(args, "O",&dict))
return NULL;
}
SetParameters(dict);
return Py_BuildValue("i",1);
}
static PyObject * chemistry_GetParameters(void)
{
PyObject *dict;
PyObject *key;
PyObject *value;
dict = PyDict_New();
/* System of units */
key = PyString_FromString("UnitLength_in_cm");
value = PyFloat_FromDouble(All.UnitLength_in_cm);
PyDict_SetItem(dict,key,value);
key = PyString_FromString("UnitMass_in_g");
value = PyFloat_FromDouble(All.UnitMass_in_g);
PyDict_SetItem(dict,key,value);
key = PyString_FromString("UnitVelocity_in_cm_per_s");
value = PyFloat_FromDouble(All.UnitVelocity_in_cm_per_s);
PyDict_SetItem(dict,key,value);
key = PyString_FromString("HubbleParam");
value = PyFloat_FromDouble(All.HubbleParam);
PyDict_SetItem(dict,key,value);
key = PyString_FromString("GravityConstantInternal");
value = PyFloat_FromDouble(All.GravityConstantInternal);
PyDict_SetItem(dict,key,value);
return Py_BuildValue("O",dict);
}
/*********************************/
/* */
/*********************************/
static PyObject *
chemistry_init_chimie(PyObject *self, PyObject *args, PyObject *kwds)
{
int NumberOfTables=1;
int DefaultTable=0;
PyObject *paramsDict=NULL;
paramsDict= PyDict_New();
//PyObject *filename;
//if (! PyArg_ParseTuple(args, "Oii",&filename,&NumberOfTables,&DefaultTable))
// {
// PyErr_SetString(PyExc_ValueError,"init_chimie, error in parsing.");
// return NULL;
// }
static char *kwlist[] = {"filename","NumberOfTables","DefaultTable","params", NULL};
PyObject *filename=PyString_FromString("chimie.yr.dat");
/* this fails with python2.6, I do not know why ??? */
if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OiiO",kwlist,&filename,&NumberOfTables,&DefaultTable,&paramsDict))
{
PyErr_SetString(PyExc_ValueError,"init_chimie, error in parsing arguments.");
return NULL;
}
if (!PyString_Check(filename))
{
PyErr_SetString(PyExc_ValueError,"Argument must be a string.");
return NULL;
}
/* copy filename */
All.ChimieParameterFile = PyString_AsString(filename);
/* set number of tables */
All.ChimieNumberOfParameterFiles = NumberOfTables;
/* check if the file exists */
if(!(fopen(All.ChimieParameterFile, "r")))
{
PyErr_SetString(PyExc_ValueError,"The parameter file does not exists.");
return NULL;
}
/* use default parameters */
chemistry_InitDefaultParameters();
/* check if units are given */
/* check that it is a PyDictObject */
if(!PyDict_Check(paramsDict))
{
PyErr_SetString(PyExc_AttributeError, "argument is not a dictionary.");
return NULL;
}
else
{
SetParameters(paramsDict);
}
init_chimie();
/* by default, set the first one */
set_table(DefaultTable);
return Py_BuildValue("O",Py_None);
}
/*********************************/
/* */
/*********************************/
static PyObject *
chemistry_info(PyObject *self, PyObject *args, PyObject *kwds)
{
int DefaultTable=0;
static char *kwlist[] = {"DefaultTable", NULL};
/* this fails with python2.6, I do not know why ??? */
if (! PyArg_ParseTupleAndKeywords(args, kwds, "|i",kwlist,&DefaultTable))
{
PyErr_SetString(PyExc_ValueError,"init_chimie, error in parsing arguments.");
return NULL;
}
info(0);
return Py_BuildValue("O",Py_None);
}
/*********************************/
/* */
/*********************************/
static PyObject *
chemistry_set_table(PyObject *self, PyObject *args, PyObject *kwds)
{
int i;
if (! PyArg_ParseTuple(args, "i",&i))
return PyString_FromString("error");
/* set the table */
set_table(i);
return Py_BuildValue("d",0);
}
/*********************************/
/* */
/*********************************/
static PyObject *
chemistry_get_imf(self, args)
PyObject *self;
PyObject *args;
{
PyArrayObject *m,*imf;
int i;
if (! PyArg_ParseTuple(args, "O",&m))
return PyString_FromString("error");
m = TO_DOUBLE(m);
/* create an output */
imf = (PyArrayObject *) PyArray_SimpleNew(m->nd,m->dimensions,PyArray_DOUBLE);
//printf("--> %g\n",Cp->bs[0]);
//for (i=0;i<Cp->n;i++)
// printf("%g %g\n",Cp->ms[i],Cp->as[i]);
for(i = 0; i < m->dimensions[0]; i++)
{
*(double *)(imf->data + i*(imf->strides[0])) = get_imf(*(double *)(m->data + i*(m->strides[0])));
}
return PyArray_Return(imf);
}
/*********************************/
/* */
/*********************************/
static PyObject *
chemistry_get_imf_M(self, args)
PyObject *self;
PyObject *args;
{
PyArrayObject *m1,*m2,*imf;
int i;
if (! PyArg_ParseTuple(args, "OO",&m1,&m2))
return PyString_FromString("error");
m1 = TO_DOUBLE(m1);
m2 = TO_DOUBLE(m2);
/* create an output */
imf = (PyArrayObject *) PyArray_SimpleNew(m1->nd,m1->dimensions,PyArray_DOUBLE);
for(i = 0; i < imf->dimensions[0]; i++)
{
*(double *)(imf->data + i*(imf->strides[0])) = get_imf_M( *(double *)(m1->data + i*(m1->strides[0])), *(double *)(m2->data + i*(m2->strides[0])) );
}
return PyArray_Return(imf);
}
/*********************************/
/* */
/*********************************/
static PyObject *
chemistry_get_imf_N(self, args)
PyObject *self;
PyObject *args;
{
PyArrayObject *m1,*m2,*imf;
int i;
if (! PyArg_ParseTuple(args, "OO",&m1,&m2))
return PyString_FromString("error");
m1 = TO_DOUBLE(m1);
m2 = TO_DOUBLE(m2);
/* create an output */
imf = (PyArrayObject *) PyArray_SimpleNew(m1->nd,m1->dimensions,PyArray_DOUBLE);
for(i = 0; i < imf->dimensions[0]; i++)
{
*(double *)(imf->data + i*(imf->strides[0])) = get_imf_N( *(double *)(m1->data + i*(m1->strides[0])), *(double *)(m2->data + i*(m2->strides[0])) );
}
return PyArray_Return(imf);
}
/*********************************/
/* */
/*********************************/
static PyObject *
chemistry_star_lifetime(self, args)
PyObject *self;
PyObject *args;
{
/* z is the mass fraction of metals, ie, the metallicity */
/* m is the star mass in code unit */
/* Return t in time unit */
double time,z,m;
if (!PyArg_ParseTuple(args, "dd", &z, &m))
return NULL;
time = star_lifetime(z,m);
return Py_BuildValue("d",time);
}
static PyObject *
chemistry_star_mass_from_age(self, args)
PyObject *self;
PyObject *args;
{
/* t : life time (in code unit) */
/* return the stellar mass (in code unit) that has a lifetime equal to t */
double time,z,m;
if (!PyArg_ParseTuple(args, "dd", &z, &time))
return NULL;
m = star_mass_from_age(z,time);
return Py_BuildValue("d",m);
}
static PyObject *
chemistry_DYIN_rate(self, args)
PyObject *self;
PyObject *args;
{
double m1,m2;
double RDYIN;
/* parse arguments */
if (!PyArg_ParseTuple(args, "dd", &m1,&m2))
return NULL;
RDYIN = DYIN_rate(m1,m2);
return Py_BuildValue("d",RDYIN);
}
static PyObject *
chemistry_SNII_rate(self, args)
PyObject *self;
PyObject *args;
{
double m1,m2;
double RSNII;
/* parse arguments */
if (!PyArg_ParseTuple(args, "dd", &m1,&m2))
return NULL;
RSNII = SNII_rate(m1,m2);
return Py_BuildValue("d",RSNII);
}
static PyObject *
chemistry_SNIa_rate(self, args)
PyObject *self;
PyObject *args;
{
double m1,m2;
double RSNIa;
/* parse arguments */
if (!PyArg_ParseTuple(args, "dd", &m1,&m2))
return NULL;
RSNIa = SNIa_rate(m1,m2);
return Py_BuildValue("d",RSNIa);
}
static PyObject *
chemistry_SNIa_single_rate(self, args)
PyObject *self;
PyObject *args;
{
double m;
double RSNIa;
/* parse arguments */
if (!PyArg_ParseTuple(args, "d", &m))
return NULL;
RSNIa = SNIa_single_rate(m);
return Py_BuildValue("d",RSNIa);
}
static PyObject *
chemistry_DYIN_mass_ejection(self, args)
PyObject *self;
PyObject *args;
{
double m1,m2;
PyArrayObject *ArrMassDYIN;
npy_intp ld[1];
int i;
/* parse arguments */
if (!PyArg_ParseTuple(args, "dd", &m1,&m2))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
ArrMassDYIN = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* compute dying stars ejection */
DYIN_mass_ejection(m1,m2);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(ArrMassDYIN->data + (i)*(ArrMassDYIN->strides[0])) = MassFracDYIN[i];
/* convert in array */
return PyArray_Return(ArrMassDYIN);
}
static PyObject *
chemistry_DYIN_mass_ejection_Z(self, args)
PyObject *self;
PyObject *args;
{
double m1,m2,Z;
PyArrayObject *ArrMassDYIN;
npy_intp ld[1];
int i;
/* parse arguments */
if (!PyArg_ParseTuple(args, "ddd", &m1,&m2,&Z))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
ArrMassDYIN = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* compute dying stars ejection */
DYIN_mass_ejection_Z(m1,m2, Z);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(ArrMassDYIN->data + (i)*(ArrMassDYIN->strides[0])) = MassFracDYIN[i];
/* convert in array */
return PyArray_Return(ArrMassDYIN);
}
static PyObject *
chemistry_DYIN_single_mass_ejection(self, args)
PyObject *self;
PyObject *args;
{
double m1;
PyArrayObject *ArrMassDYIN;
npy_intp ld[1];
int i;
/* parse arguments */
if (!PyArg_ParseTuple(args, "d", &m1))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
ArrMassDYIN = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* compute SN ejection */
DYIN_single_mass_ejection(m1);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(ArrMassDYIN->data + (i)*(ArrMassDYIN->strides[0])) = SingleMassFracDYIN[i];
/* convert in array */
return PyArray_Return(ArrMassDYIN);
}
static PyObject *
chemistry_DYIN_single_mass_ejection_Z(self, args)
PyObject *self;
PyObject *args;
{
double m1,Z;
PyArrayObject *ArrMassDYIN;
npy_intp ld[1];
int i;
/* parse arguments */
if (!PyArg_ParseTuple(args, "dd", &m1, &Z))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
ArrMassDYIN = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* compute SN ejection */
DYIN_single_mass_ejection_Z(m1,Z);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(ArrMassDYIN->data + (i)*(ArrMassDYIN->strides[0])) = SingleMassFracDYIN[i];
/* convert in array */
return PyArray_Return(ArrMassDYIN);
}
static PyObject *
chemistry_SNII_mass_ejection(self, args)
PyObject *self;
PyObject *args;
{
double m1,m2;
PyArrayObject *ArrMassSNII;
npy_intp ld[1];
int i;
/* parse arguments */
if (!PyArg_ParseTuple(args, "dd", &m1,&m2))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
ArrMassSNII = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* compute SN ejection */
SNII_mass_ejection(m1,m2);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(ArrMassSNII->data + (i)*(ArrMassSNII->strides[0])) = MassFracSNII[i];
/* convert in array */
return PyArray_Return(ArrMassSNII);
}
static PyObject *
chemistry_SNII_mass_ejection_Z(self, args)
PyObject *self;
PyObject *args;
{
double m1,m2,Z;
PyArrayObject *ArrMassSNII;
npy_intp ld[1];
int i;
/* parse arguments */
if (!PyArg_ParseTuple(args, "ddd", &m1,&m2,&Z))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
ArrMassSNII = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* compute SNII stars ejection */
SNII_mass_ejection_Z(m1,m2, Z);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(ArrMassSNII->data + (i)*(ArrMassSNII->strides[0])) = MassFracSNII[i];
/* convert in array */
return PyArray_Return(ArrMassSNII);
}
static PyObject *
chemistry_SNII_single_mass_ejection(self, args)
PyObject *self;
PyObject *args;
{
double m1;
PyArrayObject *ArrMassSNII;
npy_intp ld[1];
int i;
/* parse arguments */
if (!PyArg_ParseTuple(args, "d", &m1))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
ArrMassSNII = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* compute SN ejection */
SNII_single_mass_ejection(m1);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(ArrMassSNII->data + (i)*(ArrMassSNII->strides[0])) = SingleMassFracSNII[i];
/* convert in array */
return PyArray_Return(ArrMassSNII);
}
static PyObject *
chemistry_SNII_single_mass_ejection_Z(self, args)
PyObject *self;
PyObject *args;
{
double m1,Z;
PyArrayObject *ArrMassSNII;
npy_intp ld[1];
int i;
/* parse arguments */
if (!PyArg_ParseTuple(args, "dd", &m1, &Z))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
ArrMassSNII = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* compute SN ejection */
SNII_single_mass_ejection_Z(m1,Z);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(ArrMassSNII->data + (i)*(ArrMassSNII->strides[0])) = SingleMassFracSNII[i];
/* convert in array */
return PyArray_Return(ArrMassSNII);
}
static PyObject *
chemistry_SNIa_mass_ejection(self, args)
PyObject *self;
PyObject *args;
{
double m1,m2;
PyArrayObject *ArrMassSNIa;
npy_intp ld[1];
int i;
/* parse arguments */
if (!PyArg_ParseTuple(args, "dd", &m1,&m2))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
ArrMassSNIa = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* compute SN ejection */
SNIa_mass_ejection(m1,m2);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(ArrMassSNIa->data + (i)*(ArrMassSNIa->strides[0])) = MassFracSNIa[i];
/* convert in array */
return PyArray_Return(ArrMassSNIa);
}
static PyObject *
chemistry_SNIa_single_mass_ejection(self, args)
PyObject *self;
PyObject *args;
{
double m1;
PyArrayObject *ArrMassSNIa;
npy_intp ld[1];
int i;
/* parse arguments */
if (!PyArg_ParseTuple(args, "d", &m1))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
ArrMassSNIa = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* compute SN ejection */
SNIa_single_mass_ejection(m1);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(ArrMassSNIa->data + (i)*(ArrMassSNIa->strides[0])) = SingleMassFracSNIa[i];
/* convert in array */
return PyArray_Return(ArrMassSNIa);
}
static PyObject *
chemistry_Total_mass_ejection(self, args)
PyObject *self;
PyObject *args;
{
double m1,m2,M;
PyArrayObject *zs;
PyArrayObject *EMass;
npy_intp ld[1];
int i;
double *z;
/* parse arguments */
if (!PyArg_ParseTuple(args, "dddO", &m1,&m2,&M,&zs))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
EMass = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* allocate memory for the metallicity array */
z = malloc((Cp->nelts) * sizeof(double));
/* export values */
for (i=0;i<Cp->nelts;i++)
z[i]= *(double *)(zs->data + (i)*(zs->strides[0]));
/* compute SN ejection */
Total_mass_ejection(m1,m2,M,z);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(EMass->data + (i)*(EMass->strides[0])) = EjectedMass[i];
free(z);
/* convert in array */
return PyArray_Return(EMass);
}
static PyObject *
chemistry_Total_mass_ejection_Z(self, args)
PyObject *self;
PyObject *args;
{
double m1,m2,M;
PyArrayObject *zs;
PyArrayObject *EMass;
npy_intp ld[1];
int i;
double *z;
/* parse arguments */
if (!PyArg_ParseTuple(args, "dddO", &m1,&m2,&M,&zs))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
EMass = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* allocate memory for the metallicity array */
z = malloc((Cp->nelts) * sizeof(double));
/* export values */
for (i=0;i<Cp->nelts;i++)
z[i]= *(double *)(zs->data + (i)*(zs->strides[0]));
/* compute SN ejection */
Total_mass_ejection_Z(m1,m2,M,z);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(EMass->data + (i)*(EMass->strides[0])) = EjectedMass[i];
free(z);
/* convert in array */
return PyArray_Return(EMass);
}
static PyObject *
chemistry_DYIN_Total_single_mass_ejection(self, args)
PyObject *self;
PyObject *args;
{
double m1;
PyArrayObject *zs;
PyArrayObject *EMass;
npy_intp ld[1];
int i;
double *z;
/* parse arguments */
if (!PyArg_ParseTuple(args, "dO", &m1,&zs))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
EMass = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* allocate memory for the metallicity array */
z = malloc((Cp->nelts) * sizeof(double));
/* export values */
for (i=0;i<Cp->nelts;i++)
z[i]= *(double *)(zs->data + (i)*(zs->strides[0]));
/* compute dying stars ejection */
DYIN_Total_single_mass_ejection(m1,z);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(EMass->data + (i)*(EMass->strides[0])) = SingleEjectedMass[i];
free(z);
/* convert in array */
return PyArray_Return(EMass);
}
static PyObject *
chemistry_SNII_Total_single_mass_ejection(self, args)
PyObject *self;
PyObject *args;
{
double m1;
PyArrayObject *zs;
PyArrayObject *EMass;
npy_intp ld[1];
int i;
double *z;
/* parse arguments */
if (!PyArg_ParseTuple(args, "dO", &m1,&zs))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
EMass = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* allocate memory for the metallicity array */
z = malloc((Cp->nelts) * sizeof(double));
/* export values */
for (i=0;i<Cp->nelts;i++)
z[i]= *(double *)(zs->data + (i)*(zs->strides[0]));
/* compute SN ejection */
SNII_Total_single_mass_ejection(m1,z);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(EMass->data + (i)*(EMass->strides[0])) = SingleEjectedMass[i];
free(z);
/* convert in array */
return PyArray_Return(EMass);
}
static PyObject *
chemistry_SNIa_Total_single_mass_ejection(self, args)
PyObject *self;
PyObject *args;
{
double m1;
PyArrayObject *zs;
PyArrayObject *EMass;
npy_intp ld[1];
int i;
double *z;
/* parse arguments */
if (!PyArg_ParseTuple(args, "dO", &m1,&zs))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
EMass = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* allocate memory for the metallicity array */
z = malloc((Cp->nelts) * sizeof(double));
/* export values */
for (i=0;i<Cp->nelts;i++)
z[i]= *(double *)(zs->data + (i)*(zs->strides[0]));
/* compute SN ejection */
SNIa_Total_single_mass_ejection(m1,z);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(EMass->data + (i)*(EMass->strides[0])) = SingleEjectedMass[i];
free(z);
/* convert in array */
return PyArray_Return(EMass);
}
static PyObject *
chemistry_Total_single_mass_ejection(self, args)
PyObject *self;
PyObject *args;
{
double m1;
double NSNII,NSNIa,NDYIN;
PyArrayObject *zs;
PyArrayObject *EMass;
npy_intp ld[1];
int i;
double *z;
/* parse arguments */
if (!PyArg_ParseTuple(args, "dOddd", &m1,&zs,&NSNII,&NSNIa,&NDYIN))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
EMass = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* allocate memory for the metallicity array */
z = malloc((Cp->nelts) * sizeof(double));
/* export values */
for (i=0;i<Cp->nelts;i++)
z[i]= *(double *)(zs->data + (i)*(zs->strides[0]));
/* compute SN ejection */
Total_single_mass_ejection(m1,z,NSNII,NSNIa,NDYIN);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(EMass->data + (i)*(EMass->strides[0])) = SingleEjectedMass[i];
free(z);
/* convert in array */
return PyArray_Return(EMass);
}
static PyObject *
chemistry_Total_single_mass_ejection_Z(self, args)
PyObject *self;
PyObject *args;
{
double m1;
double NSNII,NSNIa,NDYIN;
PyArrayObject *zs;
PyArrayObject *EMass;
npy_intp ld[1];
int i;
double *z;
/* parse arguments */
if (!PyArg_ParseTuple(args, "dOddd", &m1,&zs,&NSNII,&NSNIa,&NDYIN))
return NULL;
/* create output array */
ld[0]= Cp->nelts+2;
EMass = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* allocate memory for the metallicity array */
z = malloc((Cp->nelts) * sizeof(double));
/* export values */
for (i=0;i<Cp->nelts;i++)
z[i]= *(double *)(zs->data + (i)*(zs->strides[0]));
/* compute SN ejection */
Total_single_mass_ejection_Z(m1,z,NSNII,NSNIa,NDYIN);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(EMass->data + (i)*(EMass->strides[0])) = SingleEjectedMass[i];
free(z);
/* convert in array */
return PyArray_Return(EMass);
}
/*********************************/
/* */
/*********************************/
static PyObject *
chemistry_cooling_function(self, args)
PyObject *self;
PyObject *args;
{
/*
on gives :
u_energy
metal = metal(i,2)
parameters
t_const,zmin,zmax,slz,tmin,tmax,slt,FeHSolar,cooling_data_max
*/
PyArrayObject *cooling_data;
double u_energy,metal;
double t_const,zmin,zmax,slz,tmin,tmax,slt,FeHSolar,cooling_data_max;
double cooling,u_cutoff,T,Z;
double rt, rz, ft, fz, v1, v2, v;
int it,iz,itp,izp;
/* parse arguments */
if (!PyArg_ParseTuple(args, "ddOddddddddd", &u_energy, &metal, &cooling_data,&t_const,&zmin,&zmax,&slz,&tmin,&tmax,&slt,&FeHSolar,&cooling_data_max))
return NULL;
u_cutoff=(100)/t_const;
cooling = 0.0;
if (u_energy > u_cutoff)
{
T = log10( t_const*u_energy );
Z = log10( metal/FeHSolar + 1.e-10 );
if (Z>zmax)
{
/*print *,'Warning: Z>Zmax for',i*/
Z=zmax;
}
if (Z < zmin)
{
rt = (T-tmin)/slt;
it = (int)rt;
if (it < cooling_data_max )
it = (int)rt;
else
it = cooling_data_max;
itp = it+1;
ft = rt - it;
fz = ( 10. + Z )/( 10. + zmin);
//v1 = ft*(cooling_data( 1, itp)-cooling_data( 1,it) ) + cooling_data( 1,it );
v1 = ft * (*(double *) (cooling_data->data + 1*(cooling_data->strides[0]) + itp*cooling_data->strides[1])
- *(double *) (cooling_data->data + 1*(cooling_data->strides[0]) + it *cooling_data->strides[1]))
+ *(double *) (cooling_data->data + 1*(cooling_data->strides[0]) + it *cooling_data->strides[1]);
//v2 = ft*(cooling_data( 0,itp )-cooling_data( 0, it ) ) + cooling_data( 0, it );
v2 = ft * (*(double *) (cooling_data->data + 0*(cooling_data->strides[0]) + itp*cooling_data->strides[1])
- *(double *) (cooling_data->data + 0*(cooling_data->strides[0]) + it *cooling_data->strides[1]))
+ *(double *) (cooling_data->data + 0*(cooling_data->strides[0]) + it *cooling_data->strides[1]);
v = v2 + fz*(v1-v2);
}
else
{
rt = (T-tmin)/slt;
rz = (Z-zmin)/slz+1.0;
if (it < cooling_data_max )
it = (int)rt;
else
it = cooling_data_max;
iz = (int)rz;
itp = it+1;
izp = iz+1;
ft = rt - it;
fz = rz - iz;
//v1 = ft*(cooling_data( izp, itp)-cooling_data(izp,it)) + cooling_data( izp, it );
v1 = ft * (*(double *) (cooling_data->data + izp*(cooling_data->strides[0]) + itp*cooling_data->strides[1])
- *(double *) (cooling_data->data + izp*(cooling_data->strides[0]) + it *cooling_data->strides[1]))
+ *(double *) (cooling_data->data + izp*(cooling_data->strides[0]) + it *cooling_data->strides[1]);
//v2 = ft*(cooling_data( iz, itp )-cooling_data(iz,it )) + cooling_data( iz, it );
v2 = ft * (*(double *) (cooling_data->data + iz *(cooling_data->strides[0]) + itp*cooling_data->strides[1])
- *(double *) (cooling_data->data + iz *(cooling_data->strides[0]) + it *cooling_data->strides[1]))
+ *(double *) (cooling_data->data + iz *(cooling_data->strides[0]) + it *cooling_data->strides[1]);
v = v2 + fz*(v1-v2);
}
cooling = pow(10,v);
}
return Py_BuildValue("d",cooling);
}
/*********************************/
/* */
/*********************************/
static PyObject *
chemistry_get_Mmax(self, args)
PyObject *self;
PyObject *args;
{
return Py_BuildValue("d",(double)Cp->Mmax * All.MsoltoCMU);
}
static PyObject *
chemistry_get_Mmin(self, args)
PyObject *self;
PyObject *args;
{
return Py_BuildValue("d",(double)Cp->Mmin * All.MsoltoCMU);
}
static PyObject *
chemistry_get_Mco(self, args)
PyObject *self;
PyObject *args;
{
return Py_BuildValue("d",(double)Cp->Mco * All.MsoltoCMU);
}
static PyObject *
chemistry_get_SNIa_Mpl(self, args)
PyObject *self;
PyObject *args;
{
return Py_BuildValue("d",(double)Cp->SNIa_Mpl * All.MsoltoCMU);
}
static PyObject *
chemistry_get_SNIa_Mpu(self, args)
PyObject *self;
PyObject *args;
{
return Py_BuildValue("d",(double)Cp->SNIa_Mpu * All.MsoltoCMU);
}
static PyObject *
chemistry_get_SNII_Mmin(self, args)
PyObject *self;
PyObject *args;
{
return Py_BuildValue("d",(double)Cp->SNII_Mmin * All.MsoltoCMU);
}
static PyObject *
chemistry_get_SNII_Mmax(self, args)
PyObject *self;
PyObject *args;
{
return Py_BuildValue("d",(double)Cp->SNII_Mmax * All.MsoltoCMU);
}
static PyObject *
chemistry_get_DYIN_Mmin(self, args)
PyObject *self;
PyObject *args;
{
return Py_BuildValue("d",(double)Cp->DYIN_Mmin * All.MsoltoCMU);
}
static PyObject *
chemistry_get_DYIN_Mmax(self, args)
PyObject *self;
PyObject *args;
{
return Py_BuildValue("d",(double)Cp->DYIN_Mmax * All.MsoltoCMU);
}
static PyObject *
chemistry_get_imf_Ntot(self, args)
PyObject *self;
PyObject *args;
{
return Py_BuildValue("d",(double)Cp->imf_Ntot*All.CMUtoMsol); /* in code mass unit */
}
static PyObject *
chemistry_get_as(self, args)
PyObject *self;
PyObject *args;
{
PyArrayObject *as;
npy_intp ld[1];
int i;
/* create output array */
ld[0]= Cp->n+1;
as = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* import values */
for (i=0;i<Cp->n+1;i++)
*(double *)(as->data + (i)*(as->strides[0])) = Cp->as[i];
return PyArray_Return(as);
}
static PyObject *
chemistry_get_bs(self, args)
PyObject *self;
PyObject *args;
{
PyArrayObject *bs;
npy_intp ld[1];
int i;
/* create output array */
ld[0]= Cp->n+1;
bs = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* import values */
for (i=0;i<Cp->n+1;i++)
*(double *)(bs->data + (i)*(bs->strides[0])) = Cp->bs[i];
return PyArray_Return(bs);
}
static PyObject *
chemistry_get_fs(self, args)
PyObject *self;
PyObject *args;
{
PyArrayObject *fs;
npy_intp ld[1];
int i;
/* create output array */
ld[0]= Cp->n;
fs = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* import values */
for (i=0;i<Cp->n;i++)
*(double *)(fs->data + (i)*(fs->strides[0])) = Cp->fs[i];
return PyArray_Return(fs);
}
static PyObject *
chemistry_get_allnelts(self, args)
PyObject *self;
PyObject *args;
{
return Py_BuildValue("i",(int)Cp->nelts+2);
}
static PyObject *
chemistry_get_nelts(self, args)
PyObject *self;
PyObject *args;
{
return Py_BuildValue("i",(int)Cp->nelts);
}
static PyObject *
chemistry_get_allelts_labels(self, args)
PyObject *self;
PyObject *args;
{
int i;
PyObject *LabelList,*LabelString;
LabelList = PyList_New((Py_ssize_t)Cp->nelts+2);
for(i=0;i<Cp->nelts+2;i++)
{
LabelString = PyString_FromString(Elt[i].label);
PyList_SetItem(LabelList, (Py_ssize_t)i,LabelString);
}
return Py_BuildValue("O",LabelList);
}
static PyObject *
chemistry_get_elts_labels(self, args)
PyObject *self;
PyObject *args;
{
int i;
PyObject *LabelList,*LabelString;
LabelList = PyList_New((Py_ssize_t)Cp->nelts);
for(i=2;i<Cp->nelts+2;i++)
{
LabelString = PyString_FromString(Elt[i].label);
PyList_SetItem(LabelList, (Py_ssize_t)i-2,LabelString);
}
return Py_BuildValue("O",LabelList);
}
/* static PyObject *
chemistry_get_elts_SolarMassAbundances(self, args)
PyObject *self;
PyObject *args;
{
int i;
npy_intp ld[1];
PyArrayObject *AbList;
ld[0] = Cp->nelts;
AbList = (PyArrayObject *) PyArray_SimpleNew(1,ld,NPY_FLOAT);
for(i=2;i<Cp->nelts+2;i++)
*(float*)(AbList->data + (i-2)*(AbList->strides[0])) = (float) Elt[i].SolarMassAbundance;
return PyArray_Return(AbList);
} */
static PyObject *
chemistry_get_elts_SolarMassAbundances(self, args)
PyObject *self;
PyObject *args;
{
int i;
PyObject *AbDict,*LabelString,*AbVal;
AbDict = PyDict_New();
for(i=2;i<Cp->nelts+2;i++)
{
AbVal = PyFloat_FromDouble(Elt[i].SolarMassAbundance);
LabelString = PyString_FromString(Elt[i].label);
PyDict_SetItem(AbDict,LabelString, AbVal);
}
return Py_BuildValue("O",AbDict);
}
static PyObject *
chemistry_get_MSNIa(self, args)
PyObject *self;
PyObject *args;
{
PyArrayObject *MSNIa;
npy_intp ld[1];
int i;
/* create output array */
ld[0]= Cp->nelts;
MSNIa = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* import values */
for (i=0;i<Cp->nelts;i++)
*(double *)(MSNIa->data + (i)*(MSNIa->strides[0])) = Elt[i+2].MSNIa*All.MsoltoCMU;
return PyArray_Return(MSNIa);
}
static PyObject *
chemistry_get_MassFracSNII(self, args)
PyObject *self;
PyObject *args;
{
PyArrayObject *MassFrac;
npy_intp ld[1];
int i;
/* create output array */
ld[0]= Cp->nelts+2;
MassFrac = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(MassFrac->data + (i)*(MassFrac->strides[0])) = MassFracSNII[i];
return PyArray_Return(MassFrac);
}
static PyObject *
chemistry_get_SingleMassFracSNII(self, args)
PyObject *self;
PyObject *args;
{
PyArrayObject *MassFrac;
npy_intp ld[1];
int i;
/* create output array */
ld[0]= Cp->nelts+2;
MassFrac = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
/* import values */
for (i=0;i<Cp->nelts+2;i++)
*(double *)(MassFrac->data + (i)*(MassFrac->strides[0])) = SingleMassFracSNII[i];
return PyArray_Return(MassFrac);
}
static PyObject *
chemistry_imf_sampling(self, args)
PyObject *self;
PyObject *args;
{
PyArrayObject *ms;
npy_intp ld[1];
int i;
int n,seed;
/* parse arguments */
if (!PyArg_ParseTuple(args, "ii", &n,&seed))
return NULL;
/* create output array */
ld[0]= n;
ms = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
srandom(seed);
/* import values */
for (i=0;i<n;i++)
*(double *)(ms->data + (i)*(ms->strides[0])) = imf_sampling();
return PyArray_Return(ms);
}
static PyObject *
chemistry_imf_init_seed(self, args)
PyObject *self;
PyObject *args;
{
int n,seed;
/* parse arguments */
if (!PyArg_ParseTuple(args, "i",&seed))
return NULL;
srandom(seed);
return Py_BuildValue("i",1);
}
static PyObject *
chemistry_imf_sampling_single(self, args)
PyObject *self;
PyObject *args;
{
return Py_BuildValue("f",imf_sampling());
}
static PyObject *
chemistry_imf_sampling_single_from_random(self, args)
PyObject *self;
PyObject *args;
{
double f;
if (!PyArg_ParseTuple(args, "f",&f))
return NULL;
return Py_BuildValue("f",imf_sampling_from_random(f));
}
/*********************************/
/* */
/*********************************/
static PyObject *
chemistry_SNII_rate_P(self, args)
PyObject *self;
PyObject *args;
{
PyArrayObject *ConstSN,*Msn;
double m1,m2,md;
double powSN1,powSN2;
double RSNII;
RSNII = 0.0;
/* parse arguments */
if (!PyArg_ParseTuple(args, "ddddOO", &m1,&m2,&powSN1,&powSN2,&ConstSN,&Msn))
return NULL;
if ( m1 < *(double *) (Msn->data + 2*(Msn->strides[0]) + 1*(Msn->strides[1])) )
md = *(double *) (Msn->data + 2*(Msn->strides[0]) + 1*(Msn->strides[1]));
else
md = m1;
if (md >= m2)
RSNII = 0;
else
RSNII = *(double *) (ConstSN->data + 2*ConstSN->strides[0]) *(pow(m2,powSN1)-pow(md,powSN1));
return Py_BuildValue("d",RSNII);
}
/*********************************/
/* */
/*********************************/
static PyObject *
chemistry_SNIa_rate_P(self, args)
PyObject *self;
PyObject *args;
{
PyArrayObject *ConstSN,*Msn;
double m1,m2,md,mu;
double powSN1,powSN2;
double RSNIa;
double rate;
int i;
/* parse arguments */
if (!PyArg_ParseTuple(args, "ddddOO", &m1,&m2,&powSN1,&powSN2,&ConstSN,&Msn))
return NULL;
RSNIa = 0.0;
for (i=0;i<2;i++)
{
if ( m1 < *(double *) (Msn->data + i*(Msn->strides[0]) + 0*(Msn->strides[1])) )
md = *(double *) (Msn->data + i*(Msn->strides[0]) + 0*(Msn->strides[1]));
else
md = m1;
if ( m2 > *(double *) (Msn->data + i*(Msn->strides[0]) + 1*(Msn->strides[1])) )
mu = *(double *) (Msn->data + i*(Msn->strides[0]) + 1*(Msn->strides[1]));
else
mu = m2;
if (md<mu)
RSNIa = RSNIa+ *(double *) (ConstSN->data + i*ConstSN->strides[0])*(pow(mu,powSN2)-pow(md,powSN2));
}
if ( m1 < *(double *) (Msn->data + 2*(Msn->strides[0]) + 0*(Msn->strides[1])) )
md = *(double *) (Msn->data + 2*(Msn->strides[0]) + 0*(Msn->strides[1]));
else
md = m1;
mu = *(double *) (Msn->data + 2*(Msn->strides[0]) + 1*(Msn->strides[1]));
if (md >= mu)
RSNIa = 0.0;
else
RSNIa = RSNIa*(pow(mu,powSN1)-pow(md,powSN1));
if (RSNIa<0)
RSNIa = 0;
return Py_BuildValue("d",RSNIa);
}
/*********************************/
/* */
/*********************************/
static PyObject *
chemistry_SNII_mass_ejection_P(self, args)
PyObject *self;
PyObject *args;
{
PyArrayObject *ArrayOrigin,*ArrayStep,*ChemArray;
double m1,m2;
int NbElement;
double l1,l2;
int i1,i2,i1p,i2p,j;
double f1,f2;
double v1,v2;
PyArrayObject *ArrMassSNII;
npy_intp ld[1];
/* parse arguments */
if (!PyArg_ParseTuple(args, "ddOOOi", &m1,&m2,&ArrayOrigin,&ArrayStep,&ChemArray,&NbElement))
return NULL;
/* create output array */
ld[0]= NbElement+2;
ArrMassSNII = (PyArrayObject *) PyArray_SimpleNew(1,ld,PyArray_DOUBLE);
l1 = ( log10(m1) - *(double *)(ArrayOrigin->data + 0*(ArrayOrigin->strides[0])) ) / *(double *)(ArrayStep->data + 0*(ArrayStep->strides[0])) ;
l2 = ( log10(m2) - *(double *)(ArrayOrigin->data + 0*(ArrayOrigin->strides[0])) ) / *(double *)(ArrayStep->data + 0*(ArrayStep->strides[0])) ;
if (l1 < 0.0) l1 = 0.0;
if (l2 < 0.0) l2 = 0.0;
i1 = (int)l1;
i2 = (int)l2;
i1p = i1 + 1;
i2p = i2 + 1;
f1 = l1 - i1;
f2 = l2 - i2;
/* check (yr) */
if (i1<1) i1=1;
if (i2<1) i2=1;
/* --------- TOTAL GAS ---------- */
j = NbElement;
v1=f1* (*(double *)(ChemArray->data + (i1p)*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1]))
- *(double *)(ChemArray->data + (i1 )*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1])))
+ *(double *)(ChemArray->data + (i1 )*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1]));
v2=f2* (*(double *)(ChemArray->data + (i2p)*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1]))
- *(double *)(ChemArray->data + (i2 )*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1])))
+ *(double *)(ChemArray->data + (i2 )*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1]));
*(double *)(ArrMassSNII->data + (j)*(ArrMassSNII->strides[0])) = v2-v1;
/* --------- He core therm ---------- */
j = NbElement+1;
v1=f1* (*(double *)(ChemArray->data + (i1p)*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1]))
- *(double *)(ChemArray->data + (i1 )*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1])))
+ *(double *)(ChemArray->data + (i1 )*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1]));
v2=f2* (*(double *)(ChemArray->data + (i2p)*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1]))
- *(double *)(ChemArray->data + (i2 )*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1])))
+ *(double *)(ChemArray->data + (i2 )*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1]));
*(double *)(ArrMassSNII->data + (j)*(ArrMassSNII->strides[0])) = v2-v1;
/* --------- Metals ---------- */
l1 = ( log10(m1) - *(double *)(ArrayOrigin->data + 1*(ArrayOrigin->strides[0])) ) / *(double *)(ArrayStep->data + 1*(ArrayStep->strides[0])) ;
l2 = ( log10(m2) - *(double *)(ArrayOrigin->data + 1*(ArrayOrigin->strides[0])) ) / *(double *)(ArrayStep->data + 1*(ArrayStep->strides[0])) ;
if (l1 < 0.0) l1 = 0.0;
if (l2 < 0.0) l2 = 0.0;
i1 = (int)l1;
i2 = (int)l2;
i1p = i1 + 1;
i2p = i2 + 1;
f1 = l1 - i1;
f2 = l2 - i2;
/* check (yr) */
if (i1<1) i1=1;
if (i2<1) i2=1;
for (j=0;j<NbElement;j++)
{
v1=f1* (*(double *)(ChemArray->data + (i1p)*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1]))
- *(double *)(ChemArray->data + (i1 )*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1])))
+ *(double *)(ChemArray->data + (i1 )*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1]));
v2=f2* (*(double *)(ChemArray->data + (i2p)*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1]))
- *(double *)(ChemArray->data + (i2 )*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1])))
+ *(double *)(ChemArray->data + (i2 )*(ChemArray->strides[0]) + (j)*(ChemArray->strides[1]));
*(double *)(ArrMassSNII->data + (j)*(ArrMassSNII->strides[0])) = v2-v1;
}
return PyArray_Return(ArrMassSNII);
}
#ifdef CHIMIE_OPTIMAL_SAMPLING
static PyObject *
chemistry_optimal_init_norm(self, args)
PyObject *self;
PyObject *args;
{
double m_max,Mecl;
if (!PyArg_ParseTuple(args, "d", &Mecl))
return NULL;
m_max = optimal_init_norm(Mecl);
return Py_BuildValue("d",m_max);
}
static PyObject *
chemistry_optimal_get_next_mass(self, args)
PyObject *self;
PyObject *args;
{
double m;
double m_next;
/* parse arguments */
if (!PyArg_ParseTuple(args, "d", &m))
return NULL;
m_next = optimal_get_next_mass(m);
return Py_BuildValue("d",m_next);
}
static PyObject *
chemistry_stop_loop(self, args)
PyObject *self;
PyObject *args;
{
double m;
int bool;
/* parse arguments */
if (!PyArg_ParseTuple(args, "d", &m))
return NULL;
bool = optimal_stop_loop(m);
return Py_BuildValue("i",bool);
}
static PyObject *
chemistry_optimal_get_m1_from_m2(self, args)
PyObject *self;
PyObject *args;
{
double m1,m2,mp;
/* parse arguments */
if (!PyArg_ParseTuple(args, "dd", &m2,&mp))
return NULL;
m1 = optimal_get_m1_from_m2(m2,mp);
return Py_BuildValue("d",m1);
}
#endif
/* definition of the method table */
static PyMethodDef chemistryMethods[] = {
{"CodeUnits_to_SolarMass_Factor", chemistry_CodeUnits_to_SolarMass_Factor, METH_VARARGS,
"convertion factor : CodeUnits -> SolarMass"},
{"SolarMass_to_CodeUnits_Factor", chemistry_SolarMass_to_CodeUnits_Factor, METH_VARARGS,
"convertion factor : SolarMass -> CodeUnits"},
{"SetVerbosityOn", (PyCFunction)chemistry_SetVerbosityOn, METH_VARARGS,
"Set verbosity to on"},
{"SetVerbosityOff", (PyCFunction)chemistry_SetVerbosityOff, METH_VARARGS,
"Set verbosity to off"},
{"InitDefaultParameters", (PyCFunction)chemistry_InitDefaultParameters, METH_VARARGS,
"Init default parameters"},
{"SetParameters", (PyCFunction)chemistry_SetParameters, METH_VARARGS,
"Set gadget parameters"},
{"GetParameters", (PyCFunction)chemistry_GetParameters, METH_VARARGS,
"get some gadget parameters"},
{"init_chimie", chemistry_init_chimie, METH_VARARGS| METH_KEYWORDS,
"Init chimie."},
{"info", chemistry_info, METH_VARARGS| METH_KEYWORDS,
"Get info on tables."},
{"set_table", chemistry_set_table, METH_VARARGS,
"Set the chimie table."},
{"get_imf", chemistry_get_imf, METH_VARARGS,
"Compute corresponding imf value."},
{"get_imf_M", chemistry_get_imf_M, METH_VARARGS,
"Compute the mass fraction between m1 and m2."},
{"get_imf_N", chemistry_get_imf_N, METH_VARARGS,
"Compute the fraction number between m1 and m2."},
{"star_lifetime", chemistry_star_lifetime, METH_VARARGS,
"Compute star life time."},
{"star_mass_from_age", chemistry_star_mass_from_age, METH_VARARGS,
"Return the stellar mass that has a lifetime equal to t."},
{"DYIN_rate", chemistry_DYIN_rate, METH_VARARGS,
"Return the number of dying stars per unit mass with masses between m1 and m2."},
{"SNII_rate", chemistry_SNII_rate, METH_VARARGS,
"Return the number of SNII per unit mass with masses between m1 and m2."},
{"SNIa_rate", chemistry_SNIa_rate, METH_VARARGS,
"Return the number of SNIa per unit mass with masses between m1 and m2."},
{"SNIa_single_rate", chemistry_SNIa_single_rate, METH_VARARGS,
"Return the number of SNIa per unit mass for a star of mass m."},
{"DYIN_mass_ejection", chemistry_DYIN_mass_ejection, METH_VARARGS,
"Mass fraction of ejected elements, per unit mass due to the explotion of dying stars with masses between m1 and m2."},
{"DYIN_mass_ejection_Z", chemistry_DYIN_mass_ejection_Z, METH_VARARGS,
"Mass fraction of ejected elements, per unit mass due to the explotion of dying stars with masses between m1 and m2 (metallicity dependency)."},
{"DYIN_single_mass_ejection", chemistry_DYIN_single_mass_ejection, METH_VARARGS,
"Mass fraction of ejected elements due to the explotion of one dying star of mass m."},
{"DYIN_single_mass_ejection_Z", chemistry_DYIN_single_mass_ejection_Z, METH_VARARGS,
"Mass fraction of ejected elements due to the explotion of one dying star of mass m (metallicity dependency)."},
{"SNII_mass_ejection", chemistry_SNII_mass_ejection, METH_VARARGS,
"Mass fraction of ejected elements, per unit mass due to the explotion of SNII with masses between m1 and m2."},
//{"SNII_mass_ejection_Z", chemistry_SNII_mass_ejection_Z, METH_VARARGS,
// "Mass fraction of ejected elements, per unit mass due to the explotion of SNII with masses between m1 and m2 (metallicity dependency)."},
{"SNII_single_mass_ejection", chemistry_SNII_single_mass_ejection, METH_VARARGS,
"Mass fraction of ejected elements due to the explotion of one SNII of mass m."},
//{"SNII_single_mass_ejection_Z", chemistry_SNII_single_mass_ejection_Z, METH_VARARGS,
// "Mass fraction of ejected elements due to the explotion of one SNII star of mass m (metallicity dependency)."},
{"SNIa_mass_ejection", chemistry_SNIa_mass_ejection, METH_VARARGS,
"Mass fraction of ejected elements, per unit mass due to the explotion of SNIa with masses between m1 and m2."},
{"SNIa_single_mass_ejection", chemistry_SNIa_single_mass_ejection, METH_VARARGS,
"Mass fraction of ejected elements due to the explotion of one SNIa of mass m."},
{"Total_mass_ejection", chemistry_Total_mass_ejection, METH_VARARGS,
"Mass fraction of ejected elements, per unit mass due to the explotion of SNIa and SNII with masses between m1 and m2."},
{"Total_mass_ejection_Z", chemistry_Total_mass_ejection_Z, METH_VARARGS,
"Mass fraction of ejected elements, per unit mass due to the explotion of SNIa and SNII with masses between m1 and m2 (metallicity dependency)."},
{"DYIN_Total_single_mass_ejection", chemistry_DYIN_Total_single_mass_ejection, METH_VARARGS,
"Mass fraction of ejected elements (including processed and non processed elements) due to the explotion of one dying star of mass m."},
{"SNII_Total_single_mass_ejection", chemistry_SNII_Total_single_mass_ejection, METH_VARARGS,
"Mass fraction of ejected elements (including processed and non processed elements) due to the explotion of one SNII of mass m."},
{"SNIa_Total_single_mass_ejection", chemistry_SNIa_Total_single_mass_ejection, METH_VARARGS,
"Mass fraction of ejected elements (including processed and non processed elements) due to the explotion of one SNIa of mass m."},
{"Total_single_mass_ejection", chemistry_Total_single_mass_ejection, METH_VARARGS,
"Mass fraction of ejected elements, per unit mass due to the explotion of one dying star of mass m1."},
{"Total_single_mass_ejection_Z", chemistry_Total_single_mass_ejection_Z, METH_VARARGS,
"Mass fraction of ejected elements, per unit mass due to the explotion of one dying star of mass m1 (metallicity dependency)."},
{"get_Mmax", chemistry_get_Mmax, METH_VARARGS,
"Get max star mass of the IMF, in code unit."},
{"get_Mmin", chemistry_get_Mmin, METH_VARARGS,
"Get min star mass of the IMF, in code unit."},
{"get_Mco", chemistry_get_Mco, METH_VARARGS,
"Get mean WD mass, in code unit."},
{"get_SNIa_Mpl", chemistry_get_SNIa_Mpl, METH_VARARGS,
"Get min mass of SNIa, in code unit."},
{"get_SNIa_Mpu", chemistry_get_SNIa_Mpu, METH_VARARGS,
"Get max mass of SNIa, in code unit."},
{"get_SNII_Mmin", chemistry_get_SNII_Mmin, METH_VARARGS,
"Get min mass of SNII, in code unit."},
{"get_SNII_Mmax", chemistry_get_SNII_Mmax, METH_VARARGS,
"Get max mass of SNII, in code unit."},
{"get_DYIN_Mmin", chemistry_get_DYIN_Mmin, METH_VARARGS,
"Get min mass of DYIN, in code unit."},
{"get_DYIN_Mmax", chemistry_get_DYIN_Mmax, METH_VARARGS,
"Get max mass of DYIN, in code unit."},
{"get_imf_Ntot", chemistry_get_imf_Ntot, METH_VARARGS,
"Get number of stars in the imf, per unit mass."},
{"get_as", chemistry_get_as, METH_VARARGS,
"Get power coefficients."},
{"get_bs", chemistry_get_bs, METH_VARARGS,
"Get normalisation coefficients."},
{"get_fs", chemistry_get_fs, METH_VARARGS,
"Get fs, mass fraction at ms."},
{"get_allnelts", chemistry_get_allnelts, METH_VARARGS,
"Get the number of element considered, including ejected mass (Ej) and non processed ejected mass (Ejnp).."},
{"get_nelts", chemistry_get_nelts, METH_VARARGS,
"Get the number of element considered."},
{"get_allelts_labels", chemistry_get_allelts_labels, METH_VARARGS,
"Get the labels of elements, including ejected mass (Ej) and non processed ejected mass (Ejnp)."},
{"get_elts_labels", chemistry_get_elts_labels, METH_VARARGS,
"Get the labels of elements."},
{"get_elts_SolarMassAbundances", chemistry_get_elts_SolarMassAbundances, METH_VARARGS,
"Get the solar mass abundance of elements."},
{"get_MassFracSNII", chemistry_get_MassFracSNII, METH_VARARGS,
"Get the mass fraction per element ejected by a set of SNII."},
{"get_SingleMassFracSNII", chemistry_get_SingleMassFracSNII, METH_VARARGS,
"Get the mass fraction per element ejected by a SNII."},
{"get_MSNIa", chemistry_get_MSNIa, METH_VARARGS,
"Get the mass per element ejected by a SNIa."},
{"cooling_function", chemistry_cooling_function, METH_VARARGS,
"Compute cooling."},
{"imf_sampling", chemistry_imf_sampling, METH_VARARGS,
"Sample imf with n points."},
{"imf_sampling_single", chemistry_imf_sampling_single, METH_VARARGS,
"Sample imf with a single point."},
{"imf_init_seed", chemistry_imf_init_seed, METH_VARARGS,
"Init the random seed."},
{"imf_sampling_single_from_random", chemistry_imf_sampling_single_from_random, METH_VARARGS,
"Sample imf with a single point from a given random number."},
/* old poirier */
{"SNIa_rate_P", chemistry_SNIa_rate_P, METH_VARARGS,
"Return the number of SNIa per unit mass and time. (Poirier version)"},
{"SNII_rate_P", chemistry_SNII_rate_P, METH_VARARGS,
"Return the number of SNII per unit mass and time. (Poirier version)"},
{"SNII_mass_ejection_P", chemistry_SNII_mass_ejection_P, METH_VARARGS,
"Mass ejection due to SNII per unit mass and time. (Poirier version)"},
#ifdef CHIMIE_OPTIMAL_SAMPLING
{"optimal_sampling_init_norm", chemistry_optimal_init_norm, METH_VARARGS,
"init normalistation"},
{"optimal_sampling_get_next_mass", chemistry_optimal_get_next_mass, METH_VARARGS,
"next star mass"},
{"optimal_sampling_stop_loop", chemistry_stop_loop, METH_VARARGS,
"return 1 if the loop for optimal sampling must be stopped "},
{"optimal_sampling_get_m1_from_m2", chemistry_optimal_get_m1_from_m2, METH_VARARGS,
"for a givent mass m2, return m1, such that the mass in the IMF between m1 and m2 is mp."},
#endif
{NULL, NULL, 0, NULL} /* Sentinel */
};
void initchemistry(void)
{
(void) Py_InitModule("chemistry", chemistryMethods);
import_array();
}
#endif /* PYCHEM */
#endif /* CHIMIE */
diff --git a/src/fof.c b/src/fof.c
index 544a729..8d64def 100644
--- a/src/fof.c
+++ b/src/fof.c
@@ -1,3388 +1,4304 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <mpi.h>
#include <gsl/gsl_math.h>
#include "allvars.h"
#include "proto.h"
#ifdef FOF
#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
#define MAX_STARS_PER_PART 100
+
+
+#ifdef PERIODIC
+/*! Macro that maps a distance to the nearest periodic neighbour */
+#define NEAREST(x) (((x)>boxhalf)?((x)-boxsize):(((x)<-boxhalf)?((x)+boxsize):(x)))
+/*! Size of 3D lock-up table for Ewald correction force */
+#define EN 64
+/*! 3D lock-up table for Ewald correction to force and potential. Only one
+ * octant is stored, the rest constructed by using the symmetry
+ */
+static FLOAT fcorrx[EN + 1][EN + 1][EN + 1];
+static FLOAT fcorry[EN + 1][EN + 1][EN + 1];
+static FLOAT fcorrz[EN + 1][EN + 1][EN + 1];
+static FLOAT potcorr[EN + 1][EN + 1][EN + 1];
+static double fac_intp;
+#endif
+
+
static int NpHead;
static int NHead;
static double a3,a3inv,hubble_a,DeltaTime;
static struct fof_phdata
{
int index;
int prev;
int cpuprev;
FLOAT density;
}
*fofd;
static struct fof_topgroups_exchange
{
int Head; /*!< head index */
int Task; /*!< task hosting the true head */
}
*TopTSfrGroups,*TopTSfrGroups_local;
void fof(void)
{
double dt,dt_Myr;
int do_FOF;
int Ti1,Ti2;
/* check if it is time to do an fof */
if (All.ComovingIntegrationOn)
{
Ti1 = log(All.FoF_TimeLastFoF/All.TimeBegin) / All.Timebase_interval;
Ti2 = All.Ti_Current;
dt = get_cosmictime_difference(Ti1,Ti2);
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);
a3 = All.Time * All.Time * All.Time;
a3inv = 1/a3;
}
else
{
dt = All.Time-All.FoF_TimeLastFoF;
hubble_a = a3 = a3inv = 1;
}
if (ThisTask==0)
{
dt_Myr = dt/3.1536e13*All.UnitTime_in_s/All.HubbleParam;
printf("FoF: Time=%g LastTime=%g dt=%g (%g Myr, hubble_a=%g)\n",All.Time,All.FoF_TimeLastFoF,dt,dt_Myr,hubble_a);
}
DeltaTime = dt;
//if((All.Time - All.FoF_TimeLastFoF) >= All.FoF_TimeBetFoF)
if(dt>=All.FoF_TimeBetFoF)
{
if(ThisTask == 0)
{
printf("FoF: Starting...\n");
printf("FoF: last FoF=%g\n",All.FoF_TimeLastFoF);
fflush(stdout);
}
fof_init();
//fof_write_particles_id_and_indicies();
fof_find_densest_neighbour();
fof_find_local_heads();
fof_link_particles_to_local_head();
fof_clean_local_groups();
fof_compute_local_tails();
//printf("(%d) NHead=%08d NpHead=%08d\n",ThisTask,NHead,NpHead);
fof_regroup_pseudo_heads();
//fof_group_info();
//printf("(%d) NHead=%08d NpHead=%08d\n",ThisTask,NHead,NpHead);
//fof_write_local_groups();
fof_send_and_link_pseudo_heads();
fof_regroup_exported_pseudo_heads();
//fof_write_all_groups();
fof_allocate_groups();
fof_compute_groups_properties();
#ifdef SFR
//fof_star_formation();
fof_star_formation_and_IMF_sampling();
#endif
//fof_write_groups_properties();
fof_free_groups();
All.FoF_TimeLastFoF = All.Time;
if(ThisTask == 0)
{
printf("FoF: next FoF=%g \n",All.FoF_TimeLastFoF+All.FoF_TimeBetFoF);
printf("FoF: done.\n");
fflush(stdout);
}
}
}
void fof_init(void)
{
#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
}
void fof_find_densest_neighbour(void)
{
if(ThisTask == 0)
{
printf("FoF: find densest neighbour\n");
fflush(stdout);
}
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 tstart, tend, sumt, sumcomm;
MPI_Status status;
/*
for(n = 0, NumSphUpdate = 0; n < N_gas; n++)
{
if(P[n].Type == 0)
{
SphP[n].FOF_Head=n;
SphP[n].FOF_DensMax=-1;
SphP[n].FOF_CPUHead=-1;
}
}
N_gas=10;
*/
//compute_potential();
/* `NumSphUpdate' gives the number of particles on this processor that want a force update */
for(n = 0, NumSphUpdate = 0; n < N_gas; n++)
{
if ( (P[n].Type == 0) && (SphP[n].Density*a3inv>All.FoF_ThresholdDensity) )
{
NumSphUpdate++;
SphP[n].FOF_Len=1;
SphP[n].FOF_Head=-1;
SphP[n].FOF_Tail=-1;
SphP[n].FOF_Next=-1;
SphP[n].FOF_Prev=-1;
SphP[n].FOF_CPUHead=-1;
SphP[n].FOF_CPUTail=-1;
SphP[n].FOF_CPUNext=-1;
SphP[n].FOF_CPUPrev=-1;
SphP[n].FOF_DensMax=-1;
SphP[n].FOF_Done=0;
}
}
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);
if (ThisTask==0)
printf("FoF: Number of gas particles above threshold : %d\n",ntot);
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);
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 */
for(nexport = 0, ndone = 0; i < N_gas && nexport < All.BunchSizeFOF - NTask; i++)
if((P[i].Type == 0) && (SphP[i].Density*a3inv>All.FoF_ThresholdDensity))
{
ndone++;
for(j = 0; j < NTask; j++)
Exportflag[j] = 0;
fof_evaluate(i, 0);
for(j = 0; j < NTask; j++)
{
if(Exportflag[j])
{
for(k = 0; k < 3; k++)
{
FOFDataIn[nexport].Pos[k] = P[i].Pos[k];
}
FOFDataIn[nexport].Hsml = SphP[i].Hsml;
FOFDataIn[nexport].FOF_Prev = SphP[i].FOF_Prev;
FOFDataIn[nexport].FOF_DensMax = SphP[i].FOF_DensMax;
FOFDataIn[nexport].FOF_CPUPrev = SphP[i].FOF_CPUPrev;
FOFDataIn[nexport].Index = i;
FOFDataIn[nexport].Task = j;
nexport++;
nsend_local[j]++;
}
}
}
qsort(FOFDataIn, nexport, sizeof(struct FOFdata_in), fof_compare_key);
for(j = 1, noffset[0] = 0; j < NTask; j++)
noffset[j] = noffset[j - 1] + nsend_local[j - 1];
MPI_Allgather(nsend_local, NTask, MPI_INT, nsend, NTask, MPI_INT, MPI_COMM_WORLD);
/* now do the particles that need to be exported */
for(level = 1; level < (1 << PTask); level++)
{
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.BunchSizeFOF)
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(&FOFDataIn[noffset[recvTask]],
nsend_local[recvTask] * sizeof(struct FOFdata_in), MPI_BYTE,
recvTask, TAG_HYDRO_A,
&FOFDataGet[nbuffer[ThisTask]],
nsend[recvTask * NTask + ThisTask] * sizeof(struct FOFdata_in), MPI_BYTE,
recvTask, TAG_HYDRO_A, MPI_COMM_WORLD, &status);
}
}
for(j = 0; j < NTask; j++)
if((j ^ ngrp) < NTask)
nbuffer[j] += nsend[(j ^ ngrp) * NTask + j];
}
/* now do the imported particles */
for(j = 0; j < nbuffer[ThisTask]; j++)
fof_evaluate(j, 1);
/* do a block to measure imbalance */
MPI_Barrier(MPI_COMM_WORLD);
/* get the result */
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.BunchSizeFOF)
break;
sendTask = ThisTask;
recvTask = ThisTask ^ ngrp;
if(recvTask < NTask)
{
if(nsend[ThisTask * NTask + recvTask] > 0 || nsend[recvTask * NTask + ThisTask] > 0)
{
/* send the results */
MPI_Sendrecv(&FOFDataResult[nbuffer[ThisTask]],
nsend[recvTask * NTask + ThisTask] * sizeof(struct FOFdata_out),
MPI_BYTE, recvTask, TAG_HYDRO_B,
&FOFDataPartialResult[noffset[recvTask]],
nsend_local[recvTask] * sizeof(struct FOFdata_out),
MPI_BYTE, recvTask, TAG_HYDRO_B, MPI_COMM_WORLD, &status);
/* add the result to the particles */
for(j = 0; j < nsend_local[recvTask]; j++)
{
source = j + noffset[recvTask];
place = FOFDataIn[source].Index;
if (FOFDataPartialResult[source].FOF_DensMax>SphP[place].FOF_DensMax)
{
SphP[place].FOF_DensMax = FOFDataPartialResult[source].FOF_DensMax;
SphP[place].FOF_Prev = FOFDataPartialResult[source].FOF_Prev;
SphP[place].FOF_CPUPrev = FOFDataPartialResult[source].FOF_CPUPrev;
}
}
}
}
for(j = 0; j < NTask; j++)
if((j ^ ngrp) < NTask)
nbuffer[j] += nsend[(j ^ ngrp) * NTask + j];
}
level = ngrp - 1;
}
MPI_Allgather(&ndone, 1, MPI_INT, ndonelist, 1, MPI_INT, MPI_COMM_WORLD);
for(j = 0; j < NTask; j++)
ntotleft -= ndonelist[j];
}
free(ndonelist);
free(nsend);
free(nsend_local);
free(nbuffer);
free(noffset);
}
/*! This function is the 'core' of the FOF computation.
*
* For each particle, we find its densest neighboring particle
* and store its index and cpu where its reside in the variables
*
* FOF_Prev = j;
* FOF_CPUPrev = ThisTask;
*
*/
void fof_evaluate(int target, int mode)
{
int j, n, startnode, numngb;
FLOAT *pos;
FLOAT h_i;
int phase=0;
double dx, dy, dz;
double r2, h2;
int FOF_Prev;
FLOAT FOF_DensMax;
int FOF_CPUPrev;
int id;
if(mode == 0)
{
pos = P[target].Pos;
h_i = SphP[target].Hsml;
FOF_Prev = SphP[target].FOF_Prev;
FOF_DensMax = SphP[target].FOF_DensMax;
FOF_CPUPrev = SphP[target].FOF_CPUPrev;
id = P[target].ID;
}
else
{
pos = FOFDataGet[target].Pos;
h_i = FOFDataGet[target].Hsml;
FOF_Prev = FOFDataGet[target].FOF_Prev;
FOF_DensMax = FOFDataGet[target].FOF_DensMax;
FOF_CPUPrev = FOFDataGet[target].FOF_CPUPrev;
id = FOFDataGet[target].ID;
}
h_i = h_i*All.FoF_HsmlSearchRadiusFactor;
h2 = h_i*h_i;
/* Now start the actual SPH computation for this particle */
startnode = All.MaxPart;
do
{
numngb = ngb_treefind_variable(&pos[0], h_i, phase, &startnode);
for(n = 0; n < numngb; n++)
{
j = Ngblist[n];
dx = pos[0] - P[j].Pos[0];
dy = pos[1] - P[j].Pos[1];
dz = pos[2] - P[j].Pos[2];
#ifdef PERIODIC /* 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 (SphP[j].Density>FOF_DensMax)
{
FOF_DensMax = SphP[j].Density;
FOF_Prev = j;
FOF_CPUPrev = ThisTask;
}
}
}
}
while(startnode >= 0);
/* Now collect the result at the right place */
if(mode == 0)
{
SphP[target].FOF_DensMax = FOF_DensMax;
SphP[target].FOF_Prev = FOF_Prev;
SphP[target].FOF_CPUPrev = FOF_CPUPrev;
}
else
{
FOFDataResult[target].FOF_DensMax = FOF_DensMax;
FOFDataResult[target].FOF_Prev = FOF_Prev;
FOFDataResult[target].FOF_CPUPrev = FOF_CPUPrev;
}
}
/*! Compute the number of true head and pseudo head
*
* A true head is a particle for which the densest neighboring particle
* is itself (residing in the same cpu).
*
* (SphP[i].FOF_Prev==i) && (SphP[i].FOF_CPUPrev==ThisTask)
*
* -> SphP[i].FOF_Head = i;
* -> SphP[i].FOF_CPUHead = ThisTask;
*
* A pseudo head is a particle for which the densest neighboring particle
* is on another CPU
*
* SphP[i].FOF_CPUPrev!=ThisTask
*
* -> SphP[i].FOF_Head = i;
* -> SphP[i].FOF_CPUHead = SphP[i].FOF_CPUPrev;
*
*
* New definitions FROM HERE:
*
* a head is : SphP[i].FOF_Head==i
* a true head is : (SphP[i].FOF_Head==i) && (SphP[i].FOF_CPUHead==ThisTask)
* a pseudo head is : (SphP[i].FOF_Head==i) && (SphP[i].FOF_CPUHead!=ThisTask)
*
*/
void fof_find_local_heads(void)
{
int i;
NHead=0;
NpHead=0;
for(i = 0; i < N_gas; i++)
if ( (P[i].Type == 0) && (SphP[i].Density*a3inv>All.FoF_ThresholdDensity) )
{
if ( (SphP[i].FOF_Prev==i) && (SphP[i].FOF_CPUPrev==ThisTask) ) /* a true head */
{
SphP[i].FOF_Head = i;
SphP[i].FOF_CPUHead = ThisTask;
NHead++;
}
if ( (SphP[i].FOF_CPUPrev!=ThisTask) && (SphP[i].FOF_CPUPrev>=0) ) /* if paticles needs to be exported */
{
SphP[i].FOF_Head = i; /* assume these particles to be (local) head */
SphP[i].FOF_CPUHead = SphP[i].FOF_CPUPrev;
NpHead++;
}
}
else
{
SphP[i].FOF_Head = -1;
SphP[i].FOF_Prev = -1;
}
}
/*! Link each particle to a head
*
*
*/
void fof_link_particles_to_local_head(void)
{
int i;
for(i = 0; i < N_gas; i++)
if ( (P[i].Type == 0) && (SphP[i].Density*a3inv>All.FoF_ThresholdDensity) )
{
fof_link_to_local_head(i);
}
}
/*! Link each particle to a head
*
* Each particle i try to find recursively
* a particle that is a head.
*
* The variable SphP[i].FOF_Next is used here
* to link particles with their descendents.
*
*/
void fof_link_to_local_head(int i)
{
/*
FOF_Prev==-1 : dead end
FOF_Prev==i : head particle
FOF_Head==i : head particle
FOF_Next==-1 : particle at the queue
*/
int k;
int n;
double dx,dy,dz,r2;
if (SphP[i].FOF_Head!=-1) /* the particle is already in a list */
return;
if (SphP[i].FOF_Prev==-1) /* mark it as a dead end */
return;
/* some physical restrictions */
if (SphP[i].Density*a3inv<All.FoF_ThresholdDensity)
{
SphP[i].FOF_Prev==-1; /* mark it as a dead end */
SphP[i].FOF_Head==-1;
return;
}
/* now, look for previous particle */
k = SphP[i].FOF_Prev;
/* the previous particle is ok, but is not included in a list */
if (SphP[k].FOF_Head==-1)
fof_link_to_local_head(k); /* find a head for this particle */
/* at this point k has a head or is a dead end */
if (SphP[k].FOF_Prev==-1) /* dead end */
{
SphP[i].FOF_Prev=-1;
SphP[i].FOF_Head=-1;
return;
}
else /* we can include it to the queue */
{
if (SphP[k].FOF_Head==-1)
endrun(1953);
/* !!! particle-particle comparison is not allowed here, as that may not be respected with multiple cpu !!! */
// if(All.FoF_HsmlMaxDistFactor>=0)
// {
//
// /* check the distance */
//
// dx = P[i].Pos[0] - P[k].Pos[0];
// dy = P[i].Pos[1] - P[k].Pos[1];
// dz = P[i].Pos[2] - P[k].Pos[2];
//
//
//#ifdef PERIODIC
// 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 > pow(All.FoF_HsmlMaxDistFactor* SphP[i].Hsml,2)) /* the particle is too far away */
// {
// SphP[i].FOF_Prev=-1; /* mark it as a dead end */
// SphP[i].FOF_Head=-1;
// return;
// }
// }
/* now, everything is ok, add it to the list */
SphP[i].FOF_Head = SphP[k].FOF_Head;
/* deal with next */
n = SphP[k].FOF_Next;
SphP[k].FOF_Next = i;
SphP[i].FOF_Prev = k;
if (n!=-1) /* correct links with next particle */
{
SphP[i].FOF_Next = n;
SphP[n].FOF_Prev = i;
}
}
}
/*! Remove true heads based on some physical critteria
*
* Particles from groups that does not fit some physical critteria
* are marked as dead end, i.e.:
*
* SphP[next].FOF_Prev=-1;
* SphP[next].FOF_Head=-1;
*
*/
void fof_clean_local_groups(void)
{
int i;
int next;
for(i = 0; i < N_gas; i++)
if ( (P[i].Type == 0) && (SphP[i].Density*a3inv>All.FoF_ThresholdDensity) )
if ( (SphP[i].FOF_Head==i) && (SphP[i].FOF_CPUHead==ThisTask) ) /* a true head */
{
//printf("a head : i=%d id=%08d (%g %g %g) rho=%g next=%d\n",i,P[i].ID,P[i].Pos[0],P[i].Pos[1],P[i].Pos[2],SphP[i].Density,SphP[i].FOF_Next);
/* here, we could select a group according to its central density or the number of particles linked to it */
if (SphP[i].Density*a3inv<All.FoF_MinHeadDensity)
{
SphP[i].FOF_Prev=-1; /* flag as dead end */
SphP[i].FOF_Head=-1;
NHead--;
next=i;
while(next!=-1)
{
SphP[next].FOF_Prev=-1; /* flag as dead end */
SphP[next].FOF_Head=-1;
next=SphP[next].FOF_Next;
}
}
}
}
/*! Compute local tails
*
* For each head (true or pseudo), loop over particles from the groups
* and record the tail into the variable :
*
* SphP[i].FOF_Tail
*
*/
void fof_compute_local_tails(void)
{
int i;
int tail;
int next;
FLOAT Density;
for(i = 0; i < N_gas; i++)
if ( (P[i].Type == 0) && (SphP[i].Density*a3inv>All.FoF_ThresholdDensity) )
if ( (SphP[i].FOF_Head==i) ) /* a head or pseudo head */
{
next=i;
Density = SphP[next].Density;
while(next!=-1)
{
if (SphP[next].Density>Density)
{
printf("(%d) i=%d iID=%d next=%d nextID=%d Density=%g SphP[next].Density=%g\n",ThisTask,i,P[i].ID,next,P[next].ID,Density,SphP[next].Density);
endrun(1255);
}
tail = next;
next=SphP[next].FOF_Next;
}
SphP[i].FOF_Tail = tail;
}
}
/*! Regroups pseudo head
*
* Pseudo heads that points towards the same distant particle
* are grouped
*
* SphP[i].FOF_Tail
*
*/
void fof_regroup_pseudo_heads(void)
{
int i,it;
int head,prev,cpuprev,tail,next;
int OldNpHead;
if (ThisTask==0)
printf("FoF: regroup pseudo heads\n");
printf("FoF: (%d) NpHead = %d\n",ThisTask,NpHead);
if (NpHead>0)
{
fofd = malloc(sizeof(struct fof_phdata) * NpHead);
for(i = 0,it = 0; i < N_gas; i++)
if ( (P[i].Type == 0) && (SphP[i].Density*a3inv>All.FoF_ThresholdDensity) )
{
if ((SphP[i].FOF_Head==i) && (SphP[i].FOF_CPUHead!=ThisTask)) /* a pseudo head */
{
fofd[it].index = i;
fofd[it].prev = SphP[i].FOF_Prev;
fofd[it].cpuprev = SphP[i].FOF_CPUPrev;
fofd[it].density = SphP[i].Density;
it++;
}
}
qsort(fofd, NpHead, sizeof(struct fof_phdata), fof_compare_phdata);
/* now, loop over the sorted structure */
head = fofd[0].index;
prev = fofd[0].prev;
cpuprev = fofd[0].cpuprev;
OldNpHead = NpHead;
for(it = 1; it < OldNpHead; it++)
{
if( (fofd[it].prev != prev) || (fofd[it].cpuprev != cpuprev)) /* the pseudo head points towards another particle */
{
head = fofd[it].index; /* it becomes the new head */
prev = fofd[it].prev;
cpuprev = fofd[it].cpuprev;
}
else
{
NpHead--;
i = fofd[it].index;
if ( SphP[i].Density > SphP[head].Density) /* this allow the particle to be in density order */
{
/* the particle becomes the head */
i = head;
head = fofd[it].index;
prev = fofd[it].prev;
}
/* we can add the particle (i) to the tail of the pseudo head (head) */
/* change the head */
next = i;
while(next!=-1)
{
SphP[next].FOF_Head = head;
next = SphP[next].FOF_Next;
}
tail = SphP[head].FOF_Tail; /* !!! here, the density order is no longer conserved !!! */
SphP[head].FOF_Tail = SphP[i].FOF_Tail;
/* deal with tail */
SphP[tail].FOF_Next = i;
SphP[i].FOF_Prev = tail;
}
}
free(fofd);
}
}
/*! Regroups exported pseudo head
*
* 1) Link Pseudo heads (that have been exported) to local groups if needed
* 2) Pseudo heads (that have been exported) that points towards the same distant head
* are grouped
*
* SphP[i].FOF_Tail
*
*/
void fof_regroup_exported_pseudo_heads(void)
{
int i,it;
int head,prev,cpuprev,tail,next;
int OldNpHead;
if (ThisTask==0)
printf("FoF: regroup exported pseudo heads\n");
for(i = 0,it = 0; i < N_gas; i++)
if ( (P[i].Type == 0) && (SphP[i].Density*a3inv>All.FoF_ThresholdDensity) )
{
if ((SphP[i].FOF_Head==i) && (SphP[i].FOF_CPUPrev==-2)) /* a true head, but among them, some may be old spseudo head */
{
if ( (SphP[i].FOF_CPUHead==ThisTask) ) /* its new head is now local, so, link it to local head */
{
NpHead--;
/* link it to the local true head */
head = SphP[i].FOF_Prev; /* as it is still a pseudo head */
/* change the head */
next = i;
while(next!=-1)
{
SphP[next].FOF_Head = head;
next = SphP[next].FOF_Next;
}
tail = SphP[head].FOF_Tail; /* !!! here, the density order is no longer conserved !!! */
SphP[head].FOF_Tail = SphP[i].FOF_Tail;
/* deal with tail */
SphP[tail].FOF_Next = i;
SphP[i].FOF_Prev = tail;
}
else
{
SphP[i].FOF_CPUPrev = SphP[i].FOF_CPUHead;
}
}
}
if (NpHead>0)
{
fofd = malloc(sizeof(struct fof_phdata) * NpHead);
NpHead = 0; /* re-count as some pHead have change their status after exportation */
for(i = 0,it = 0; i < N_gas; i++)
if ( (P[i].Type == 0) && (SphP[i].Density*a3inv>All.FoF_ThresholdDensity) )
{
if ((SphP[i].FOF_Head==i) && (SphP[i].FOF_CPUHead!=ThisTask)) /* a pseudo head */
{
fofd[it].index = i;
fofd[it].prev = SphP[i].FOF_Prev;
fofd[it].cpuprev = SphP[i].FOF_CPUPrev;
fofd[it].density = SphP[i].Density;
it++;
NpHead++;
}
}
qsort(fofd, NpHead, sizeof(struct fof_phdata), fof_compare_phdata);
/* now, loop over the sorted structure */
head = fofd[0].index;
prev = fofd[0].prev;
cpuprev = fofd[0].cpuprev;
OldNpHead = NpHead;
for(it = 1; it < OldNpHead; it++)
{
if( (fofd[it].prev != prev) || (fofd[it].cpuprev != cpuprev)) /* the pseudo head points towards another particle */
{
head = fofd[it].index; /* it becomes the new head */
prev = fofd[it].prev;
cpuprev = fofd[it].cpuprev;
}
else /* the particle share the same head */
{
NpHead--;
i = fofd[it].index;
if ( SphP[i].Density > SphP[head].Density) /* this allow the particle to be in density order */
{
/* the particle becomes the head */
i = head;
head = fofd[it].index;
prev = fofd[it].prev;
}
/* we can add the particle (i) to the tail of the pseudo head (head) */
/* change the head */
next = i;
while(next!=-1)
{
SphP[next].FOF_Head = head;
next = SphP[next].FOF_Next;
}
tail = SphP[head].FOF_Tail; /* !!! here, the density order is no longer conserved !!! */
SphP[head].FOF_Tail = SphP[i].FOF_Tail;
/* deal with tail */
SphP[tail].FOF_Next = i;
SphP[i].FOF_Prev = tail;
}
}
free(fofd);
}
}
void fof_write_particles_id_and_indicies(void)
{
FILE *fd;
char fname[500];
int i;
sprintf(fname, "%d_snap.lst",ThisTask);
fd = fopen(fname, "w");
printf(".... writing particles...\n");
for(i = 0; i < N_gas; i++)
if ( (P[i].Type == 0) && (SphP[i].Density*a3inv>All.FoF_ThresholdDensity) )
{
fprintf(fd,"%08d %08d\n",P[i].ID,i);
}
fclose(fd);
}
void fof_write_local_groups(void)
{
int i;
FILE *fd;
char fname[500];
int next;
for(i = 0; i < N_gas; i++)
if ( (P[i].Type == 0) && (SphP[i].Density*a3inv>All.FoF_ThresholdDensity) )
if ( (SphP[i].FOF_Head==i) && (SphP[i].FOF_CPUHead==ThisTask) ) /* a true head */
{
printf("(%d) a head : i=%d id=%08d (%g %g %g) rho=%g next=%d\n",ThisTask,i,P[i].ID,P[i].Pos[0],P[i].Pos[1],P[i].Pos[2],SphP[i].Density,SphP[i].FOF_Next);
sprintf(fname, "groups/%d_group%08d.lst",ThisTask,P[i].ID);
fd = fopen(fname, "w");
next=i;
while(next!=-1)
{
fprintf(fd,"%08d\n",P[next].ID);
next=SphP[next].FOF_Next;
}
fclose(fd);
}
}
void fof_write_all_groups(void)
{
int i;
FILE *fd;
char fname[500];
int next;
if (ThisTask==0)
printf("FoF: write all groups\n");
for(i = 0; i < N_gas; i++)
if ( (P[i].Type == 0) && (SphP[i].Density*a3inv>All.FoF_ThresholdDensity) )
if (SphP[i].FOF_Head==i)
{
if (SphP[i].FOF_CPUHead==ThisTask) /* a true head */
{
//printf("(%d) a head : i=%d head=%d on %d \n",ThisTask,i,SphP[i].FOF_Head,SphP[i].FOF_CPUHead);
sprintf(fname, "groups/%08dat%02d_group%08dat%02d.lst",i,ThisTask,SphP[i].FOF_Head,SphP[i].FOF_CPUHead);
}
else
{ /* a pseudo head */
//printf("(%d) a head (p) : i=%d head=%d on %d \n",ThisTask,i,SphP[i].FOF_Prev,SphP[i].FOF_CPUHead,SphP[i].FOF_CPUHead);
sprintf(fname, "groups/%08dat%02d_group%08dat%02d.lst",i,ThisTask,SphP[i].FOF_Prev,SphP[i].FOF_CPUHead);
}
fd = fopen(fname, "w");
next=i;
while(next!=-1)
{
fprintf(fd,"%08d\n",P[next].ID);
next=SphP[next].FOF_Next;
}
fclose(fd);
}
}
void fof_compute_groups_properties(void)
{
int i,j,k;
int ng;
int next;
int level,ngrp;
int sendTask,recvTask;
int *nsend_local, *nsend,*noffset;
int place;
- int maxig,gid;
+ int maxig,gidx;
int ntg, npg;
MPI_Status status;
if (ThisTask==0)
printf("FoF: compute groups properties\n");
noffset = malloc(sizeof(int) * NTask); /* offsets of bunches in common list */
nsend_local = malloc(sizeof(int) * NTask);
nsend = malloc(sizeof(int) * NTask * NTask);
for(j = 0; j < NTask; j++)
nsend_local[j] = 0;
ng=0;
ntg = 0;
npg = 0;
+ /* loop over heads and create the groups */
+
for(i = 0; i < N_gas; i++)
- if ( (P[i].Type == 0) && (SphP[i].Density*a3inv>All.FoF_ThresholdDensity) )
- if (SphP[i].FOF_Head==i)
- {
+ {
+
+ SphP[i].FOF_gidx=-1; /* local indice of the group */
+ SphP[i].FOF_gid=-1; /* id of the group */
+
+
+ if ( (P[i].Type == 0) && (SphP[i].Density*a3inv>All.FoF_ThresholdDensity) )
+ if (SphP[i].FOF_Head==i) /* the particle is a head */
+ {
- if (ng==(NpHead+NHead))
- {
- printf("(%d) FoF: warning g=%d >= %d+%d !\n",ThisTask,ng,NpHead,NHead);
- endrun(1961);
- }
+ if (ng==(NpHead+NHead))
+ {
+ printf("(%d) FoF: warning g=%d >= %d+%d !\n",ThisTask,ng,NpHead,NHead);
+ endrun(1961);
+ }
- if (SphP[i].FOF_CPUHead==ThisTask) /* a true head */
- {
- //printf("(%d) a head : head i=%d on %d \n",ThisTask,SphP[i].FOF_Head,SphP[i].FOF_CPUHead);
- Groups[ng].Head = SphP[i].FOF_Head;
-
- Groups[ng].HeadID = P[i].ID;
- for (k=0;k<3;k++)
- Groups[ng].HeadPos[k] = P[i].Pos[k];
-
- Groups[ng].HeadPotential = P[i].Potential * P[i].Mass;
+ if (SphP[i].FOF_CPUHead==ThisTask) /* a true head */
+ {
+ //printf("(%d) a head : head i=%d on %d \n",ThisTask,SphP[i].FOF_Head,SphP[i].FOF_CPUHead);
+ Groups[ng].Head = SphP[i].FOF_Head;
- ntg++;
+ Groups[ng].HeadID = P[i].ID;
+ for (k=0;k<3;k++)
+ Groups[ng].HeadPos[k] = P[i].Pos[k];
+
+ ntg++;
- }
- else
- { /* a pseudo head */
- //printf("(%d) a head (p) : head i=%d on %d \n",ThisTask,SphP[i].FOF_Prev,SphP[i].FOF_CPUHead,SphP[i].FOF_CPUHead);
- Groups[ng].Head = SphP[i].FOF_Prev;
- Groups[ng].HeadID = -1; /* don't know the ID */
+ }
+ else
+ { /* a pseudo head */
+ //printf("(%d) a head (p) : head i=%d on %d \n",ThisTask,SphP[i].FOF_Prev,SphP[i].FOF_CPUHead,SphP[i].FOF_CPUHead);
+ Groups[ng].Head = SphP[i].FOF_Prev;
+ Groups[ng].HeadID = -1; /* don't know the ID */
- npg++;
- }
+ npg++;
+ }
- Groups[ng].Task = SphP[i].FOF_CPUHead;
- Groups[ng].LocalHead = i;
+ Groups[ng].Task = SphP[i].FOF_CPUHead;
+ Groups[ng].LocalHead = i;
- nsend_local[SphP[i].FOF_CPUHead]++; /* count number of groups exported towards proc FOF_CPUHead */
+ nsend_local[SphP[i].FOF_CPUHead]++; /* count number of groups exported towards proc FOF_CPUHead */
- /* some init */
- fof_init_group_properties(ng);
+ /* some init */
+ fof_init_group_properties(ng);
- ng++;
+ ng++;
- }
+ }
+ }
+
Ngroups = ng;
Ntgroups = ntg;
Npgroups = npg;
MPI_Allreduce(&Ngroups, &Tot_Ngroups, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
MPI_Allreduce(&Ntgroups, &Tot_Ntgroups, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
MPI_Allreduce(&Npgroups, &Tot_Npgroups, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
if (ThisTask==0)
{
printf("FoF: %d groups selected for star formation.\n",Tot_Ngroups);
printf("FoF: %d true groups. \n",Tot_Ntgroups);
printf("FoF: %d pseudo groups. \n",Tot_Npgroups);
}
- /* here, we need to compute potential, in order to estimate the virial fraction for each group */
- if (Tot_Ngroups>0)
- {
- if (ThisTask==0)
- printf("FoF: ");
- compute_potential();
- }
/* sort groups */
qsort(Groups, Ngroups, sizeof(struct fof_groups_data), fof_compare_groups_key);
-
- for (i=0;i<ng;i++)
- {
- Groups[i].Index = i; /* compute index */
-
- if( Groups[i].Task == ThisTask ) /* a true head */
- SphP[Groups[i].Head].FOF_gid = i; /* link towards the group id */
-
- }
-
-
+
for(j = 1, noffset[0] = 0; j < NTask; j++)
noffset[j] = noffset[j - 1] + nsend_local[j - 1];
/* gather number of exported groups */
/* info : nsend[j * NTask + i] : number of elements of j send to i */
MPI_Allgather(nsend_local, NTask, MPI_INT, nsend, NTask, MPI_INT, MPI_COMM_WORLD);
+
/* find the max number of imported groups */
for (i=0,maxig=0;i<NTask;i++)
{
for (j=0;j<NTask;j++)
{
/* number of groups received by i */
if (i!=j)
maxig = dmax(maxig ,nsend[j * NTask + i] );
}
}
GroupsGet = malloc(sizeof(struct fof_groups_data) * maxig);
GroupsRecv = malloc(sizeof(struct fof_groups_data) * maxig);
+
+
+ /* link true head with their group */
+ for (i=0;i<ng;i++)
+ {
+ Groups[i].Index = i; /* compute index */
+
+ if( Groups[i].Task == ThisTask ) /* a true head */
+ SphP[Groups[i].Head].FOF_gidx = i; /* link towards the group id */ /*this is no longer needed, as done after */
+ }
+
+
/*
- /* first communication
+ /* first communication (send peudo groups)
/*
/* get Head ID and Head Position
/*
*/
for(level = 1; level < (1 << PTask); level++)
{
for(ngrp = level; ngrp < (1 << PTask); ngrp++)
{
sendTask = ThisTask;
recvTask = ThisTask ^ ngrp;
if((recvTask < NTask))
{
if(nsend[ThisTask * NTask + recvTask] > 0 || nsend[recvTask * NTask + ThisTask] > 0)
{
if (nsend[recvTask * NTask + ThisTask]>maxig)
endrun(1963);
/* get the groups */
MPI_Sendrecv(&Groups[noffset[recvTask]],
nsend_local[recvTask] * sizeof(struct fof_groups_data), MPI_BYTE,
recvTask, TAG_HYDRO_A,
&GroupsGet[0],
nsend[recvTask * NTask + ThisTask] * sizeof(struct fof_groups_data), MPI_BYTE,
recvTask, TAG_HYDRO_A, MPI_COMM_WORLD, &status);
/* do the computation */
for(j = 0; j < nsend[recvTask * NTask + ThisTask]; j++)
{
if (GroupsGet[j].Task!=ThisTask)
endrun(1965);
GroupsGet[j].HeadID = P[GroupsGet[j].Head].ID;
for (k=0;k<3;k++)
GroupsGet[j].HeadPos[k] = P[GroupsGet[j].Head].Pos[k];
-
- GroupsGet[j].HeadPotential = P[GroupsGet[j].Head].Potential*P[GroupsGet[j].Head].Mass;
-
+
}
/* get the result */
MPI_Sendrecv(&GroupsGet[0],
nsend[recvTask * NTask + ThisTask] * sizeof(struct fof_groups_data), MPI_BYTE,
recvTask, TAG_HYDRO_A,
&GroupsRecv[0],
nsend_local[recvTask] * sizeof(struct fof_groups_data),MPI_BYTE,
recvTask, TAG_HYDRO_A, MPI_COMM_WORLD, &status
);
/* add the result to the groups */
for(j = 0; j < nsend_local[recvTask]; j++)
{
place = GroupsRecv[j].Index;
- Groups[place].HeadID = GroupsRecv[j].HeadID;
+ Groups[place].HeadID = GroupsRecv[j].HeadID;
for (k=0;k<3;k++)
Groups[place].HeadPos[k] = GroupsRecv[j].HeadPos[k];
- Groups[place].HeadPotential = GroupsRecv[j].HeadPotential;
}
}
}
}
level = ngrp - 1;
}
+
+
+ /*
+ /* loop over all particles in a group and attribute the group ID (this is needed for the groups potential computation)
+ /* The group ID correspond to the ID of the head particle.
+ */
+ for (i=0;i<Ngroups;i++)
+ {
+
+ next=Groups[i].LocalHead; /* indice towards Head or Pseudo Head */
+
+ while(next!=-1) /* loop over all local members */
+ {
+ SphP[next].FOF_gidx=i; /* link all particles to its local group (true or pseudo) */
+ SphP[next].FOF_gid = Groups[i].HeadID; /* set the group ID */
+
+ next=SphP[next].FOF_Next;
+ }
+ }
+
+
+
+#ifndef FOF_COMPUTE_GROUPS_VIRIAL_LOCALLY
+ /* now here, we can compute potential, in order to estimate the virial fraction for each group */
+ if (Tot_Ngroups>0)
+ {
+ if (ThisTask==0)
+ printf("FoF: ");
+ compute_potential();
+
+ fof_compute_groups_potential();
+
+ }
+#endif
+
+
/*
/* compute properties of groups using local particles
*/
for (i=0;i<Ngroups;i++)
{
-
next=Groups[i].LocalHead; /* indice towards Head or Pseudo Head */
Groups[i].Nlocal=0;
while(next!=-1) /* loop over all local members */
{
fof_add_particle_properties(next,i,0);
-
+
/* count local particles linked to the head */
Groups[i].Nlocal++;
-
+
next=SphP[next].FOF_Next;
}
- }
+ }
/*
- /* second communication
+ /* second communication (send peudo groups)
*/
/* now, need to communicate */
for(level = 1; level < (1 << PTask); level++)
{
for(ngrp = level; ngrp < (1 << PTask); ngrp++)
{
sendTask = ThisTask;
recvTask = ThisTask ^ ngrp;
if((recvTask < NTask))
{
//printf("(%02d) -> %02d (level=%02d ngrp=%02d)\n",sendTask,recvTask,level,ngrp);
if(nsend[ThisTask * NTask + recvTask] > 0 || nsend[recvTask * NTask + ThisTask] > 0)
{
if (nsend[recvTask * NTask + ThisTask]>maxig)
endrun(1963);
/* get the particles */
MPI_Sendrecv(&Groups[noffset[recvTask]],
nsend_local[recvTask] * sizeof(struct fof_groups_data), MPI_BYTE,
recvTask, TAG_HYDRO_A,
&GroupsGet[0],
nsend[recvTask * NTask + ThisTask] * sizeof(struct fof_groups_data), MPI_BYTE,
recvTask, TAG_HYDRO_A, MPI_COMM_WORLD, &status);
for(j = 0; j < nsend[recvTask * NTask + ThisTask]; j++)
{
//if (ThisTask==0)
// printf("(%d) head=%08d \n",ThisTask,GroupsGet[j].Head);
if (GroupsGet[j].Task!=ThisTask)
endrun(1967);
- gid = SphP[ GroupsGet[j].Head ].FOF_gid ;
+ gidx = SphP[ GroupsGet[j].Head ].FOF_gidx ;
- if (Groups[gid].Head!=GroupsGet[j].Head)
+ if (Groups[gidx].Head!=GroupsGet[j].Head)
{
printf("(%d) %d -> %d\n ",ThisTask,sendTask,recvTask);
- printf("(%d) something is wrong here... GroupsGet[j].Head=%d GroupsGet[j].Task=%d gid=%d Groups[gid].Head=%d\n",ThisTask, GroupsGet[j].Head,GroupsGet[j].Task,gid,Groups[gid].Head);
+ printf("(%d) something is wrong here... GroupsGet[j].Head=%d GroupsGet[j].Task=%d gid=%d Groups[gid].Head=%d\n",ThisTask, GroupsGet[j].Head,GroupsGet[j].Task,gidx,Groups[gidx].Head);
endrun(1968);
}
- fof_add_particle_properties(j,gid,1);
+ fof_add_particle_properties(j,gidx,1);
}
}
}
}
level = ngrp - 1;
}
fof_final_operations_on_groups_properties();
fof_set_groups_for_sfr();
/* now, each pseudo groups needs to be exported */
/* WARNING : in term of communication, this part is not optimized at all
as we communicte the whole structure while only some items are needed
*/
for(level = 1; level < (1 << PTask); level++)
{
for(ngrp = level; ngrp < (1 << PTask); ngrp++)
{
sendTask = ThisTask;
recvTask = ThisTask ^ ngrp;
if((recvTask < NTask))
{
if(nsend[ThisTask * NTask + recvTask] > 0 || nsend[recvTask * NTask + ThisTask] > 0)
{
if (nsend[recvTask * NTask + ThisTask]>maxig)
endrun(1963);
/* get the groups */
MPI_Sendrecv(&Groups[noffset[recvTask]],
nsend_local[recvTask] * sizeof(struct fof_groups_data), MPI_BYTE,
recvTask, TAG_HYDRO_A,
&GroupsGet[0],
nsend[recvTask * NTask + ThisTask] * sizeof(struct fof_groups_data), MPI_BYTE,
recvTask, TAG_HYDRO_A, MPI_COMM_WORLD, &status);
/* do the computation */
for(j = 0; j < nsend[recvTask * NTask + ThisTask]; j++)
{
if (GroupsGet[j].Task!=ThisTask)
endrun(1965);
- GroupsGet[j].SfrFlag = Groups[ SphP[ GroupsGet[j].Head ].FOF_gid ].SfrFlag;
+ GroupsGet[j].SfrFlag = Groups[ SphP[ GroupsGet[j].Head ].FOF_gidx ].SfrFlag;
}
/* get the result */
MPI_Sendrecv(&GroupsGet[0],
nsend[recvTask * NTask + ThisTask] * sizeof(struct fof_groups_data), MPI_BYTE,
recvTask, TAG_HYDRO_A,
&GroupsRecv[0],
nsend_local[recvTask] * sizeof(struct fof_groups_data),MPI_BYTE,
recvTask, TAG_HYDRO_A, MPI_COMM_WORLD, &status
);
/* add the result to the groups */
for(j = 0; j < nsend_local[recvTask]; j++)
{
place = GroupsRecv[j].Index;
Groups[place].SfrFlag = GroupsRecv[j].SfrFlag;
}
}
}
}
level = ngrp - 1;
}
/* count star forming groups */
Nsfrgroups=0;
if (Ngroups>0)
{
- for (gid=0;gid<Ngroups;gid++)
+ for (gidx=0;gidx<Ngroups;gidx++)
{
- if( Groups[gid].SfrFlag == 1 ) /* the group must be flagged as forming stars */
+ if( Groups[gidx].SfrFlag == 1 ) /* the group must be flagged as forming stars */
Nsfrgroups++;
}
}
MPI_Allreduce(&Nsfrgroups, &Tot_Nsfrgroups, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
if (ThisTask==0)
printf("FoF: %d groups flagged for star formation.\n",Tot_Nsfrgroups);
free(nsend);
free(nsend_local);
free(noffset);
free(GroupsRecv);
free(GroupsGet);
}
void fof_init_group_properties(int gid)
{
int k;
Groups[gid].Mass = 0;
for (k=0;k<3;k++)
{
Groups[gid].MassCenter[k] = 0;
Groups[gid].MV2[k] = 0;
Groups[gid].MV[k] = 0;
}
Groups[gid].DensityMax = 0;
Groups[gid].DensityMin = pow(2,32);
Groups[gid].PotentialMax = 0;
Groups[gid].RadiusMax = 0;
Groups[gid].W = 0;
Groups[gid].K = 0;
Groups[gid].U = 0;
Groups[gid].N = 0;
}
/*! Include particle properties into a group
+* if mode=0, we add the properties of a local particle
+* if mode=1, we add the properties of a group (containing the contribution of the local particles)
*
*/
void fof_add_particle_properties(int i, int gid, int mode)
{
int k;
int N;
float Mass;
float DensityMax;
float DensityMin;
float PotentialMax;
float MassCenter[3];
float MV[3];
float MV2[3];
float W;
float U;
float RadiusMax;
float dx,dy,dz;
if (mode==0)
{
N = 1;
Mass = P[i].Mass;
DensityMax = SphP[i].Density;
DensityMin = SphP[i].Density;
PotentialMax = P[i].Mass*P[i].Potential;
W = P[i].Mass*P[i].Potential;
#ifdef ISOTHERM_EQS
U = P[i].Mass*SphP[i].Entropy;
#else
#ifdef MULTIPHASE
if (SphP[i].Phase== GAS_SPH)
#ifdef DENSITY_INDEPENDENT_SPH
U = P[i].Mass*SphP[i].Entropy / (GAMMA_MINUS1) * pow(SphP[i].EgyWtDensity / a3, GAMMA_MINUS1);
#else
U = P[i].Mass*SphP[i].Entropy / (GAMMA_MINUS1) * pow(SphP[i].Density / a3, GAMMA_MINUS1);
#endif
else
U = P[i].Mass*SphP[i].Entropy;
#else /* MULTIPHASE */
#ifdef DENSITY_INDEPENDENT_SPH
U = P[i].Mass*SphP[i].Entropy / (GAMMA_MINUS1) * pow(SphP[i].EgyWtDensity / a3, GAMMA_MINUS1);
#else
U = P[i].Mass*SphP[i].Entropy / (GAMMA_MINUS1) * pow(SphP[i].Density / a3, GAMMA_MINUS1);
#endif
#endif /*MULTIPHASE*/
#endif /*ISOTHERM_EQS*/
for (k=0;k<3;k++)
{
MassCenter[k] = P[i].Mass * P[i].Pos[k];
MV[k] = P[i].Mass * P[i].Vel[k];
MV2[k] = P[i].Mass * P[i].Vel[k] * P[i].Vel[k];
}
dx = Groups[gid].HeadPos[0] - P[i].Pos[0];
dy = Groups[gid].HeadPos[1] - P[i].Pos[1];
dz = Groups[gid].HeadPos[2] - P[i].Pos[2];
#ifdef PERIODIC /* 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
RadiusMax = sqrt(dx * dx + dy * dy + dz * dz);
}
else
{
N = GroupsGet[i].N;
Mass = GroupsGet[i].Mass;
DensityMax = GroupsGet[i].DensityMax;
DensityMin = GroupsGet[i].DensityMin;
PotentialMax = GroupsGet[i].PotentialMax;
W = GroupsGet[i].W;
U = GroupsGet[i].U;
for (k=0;k<3;k++)
{
MassCenter[k] = GroupsGet[i].MassCenter[k];
MV[k] = GroupsGet[i].MV[k];
MV2[k] = GroupsGet[i].MV2[k];
}
RadiusMax = GroupsGet[i].RadiusMax;
}
Groups[gid].N += N;
Groups[gid].Mass += Mass;
Groups[gid].DensityMax = dmax(Groups[gid].DensityMax,DensityMax);
Groups[gid].DensityMin = dmin(Groups[gid].DensityMin,DensityMin);
Groups[gid].PotentialMax = dmax(Groups[gid].PotentialMax,PotentialMax);
Groups[gid].W += W;
Groups[gid].U += U;
for (k=0;k<3;k++)
{
Groups[gid].MassCenter[k] += MassCenter[k];
Groups[gid].MV[k] += MV[k];
Groups[gid].MV2[k] += MV2[k];
}
Groups[gid].RadiusMax = dmax(Groups[gid].RadiusMax,RadiusMax);
}
/*! Do some final opperations on groups properties
*
*/
void fof_final_operations_on_groups_properties()
{
int gid,k;
for (gid=0;gid<Ngroups;gid++)
{
Groups[gid].K =0;
for (k=0;k<3;k++)
{
Groups[gid].MassCenter[k] = Groups[gid].MassCenter[k]/Groups[gid].Mass;
Groups[gid].K += Groups[gid].MV2[k] - (Groups[gid].MV[k]*Groups[gid].MV[k])/Groups[gid].Mass ;
}
/* kinetic energy */
Groups[gid].K *= 0.5;
/* potential energy*/
Groups[gid].W -= (Groups[gid].N*Groups[gid].PotentialMax); /* add offset */
Groups[gid].W *= 0.5;
Groups[gid].T = (Groups[gid].U/Groups[gid].Mass) * GAMMA_MINUS1*All.mumh/All.Boltzmann;
//Groups[gid].Density = Groups[gid].Mass/( 4/3. * PI * pow(Groups[gid].RadiusMax,3) );
Groups[gid].Density = Groups[gid].DensityMax;
/* virial fraction */
Groups[gid].VirialFraction = -2*(Groups[gid].K +Groups[gid].U )/Groups[gid].W;
}
}
/*! Write groups properties
*
*/
void fof_write_groups_properties()
{
FILE *fd;
char buf[500];
int gid;
float vir1,vir2,Wp;
if (Ngroups>0)
{
if (ThisTask==0)
printf("FoF: write groups properties\n");
sprintf(buf, "%s%s.%d", All.OutputDir, "groups", ThisTask);
fd = fopen(buf,"w");
fprintf(fd,"# HeadID N Headx Heady Headz Mass CMx CMy CMz DensityMax DensityMin RadiusMax K U W Wp Vir1 Vir2\n");
for (gid=0;gid<Ngroups;gid++)
if( Groups[gid].Task == ThisTask )
{
//printf("(%02d)--> a true group (head=%d) mass=%g N=%d\n",ThisTask,Groups[gid].HeadID,Groups[i].Mass,Groups[i].N);
Wp = -All.G * Groups[gid].Mass * Groups[gid].Mass / Groups[gid].RadiusMax;
vir1 = -2*(Groups[gid].K +Groups[gid].U )/Groups[gid].W;
vir2 = -2*(Groups[gid].K +Groups[gid].U )/Wp;
fprintf(fd,"%08d %08d %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g \n", Groups[gid].HeadID,Groups[gid].N,Groups[gid].HeadPos[0],Groups[gid].HeadPos[1],Groups[gid].HeadPos[2] , Groups[gid].Mass , Groups[gid].MassCenter[0],Groups[gid].MassCenter[1],Groups[gid].MassCenter[2],Groups[gid].DensityMax,Groups[gid].DensityMin,Groups[gid].RadiusMax,Groups[gid].K,Groups[gid].U,Groups[gid].W,Wp,vir1,vir2);
}
fclose(fd);
}
}
+/*! This function computes the gravitational potential for the particles belonging to a group
+ * due to particles belonging to the same group.
+ */
+void fof_compute_groups_potential()
+{
-/*! Here, each group is flaged to form stars or not.
-* The decision is based on physical properties of the group.
-*
-*/
-void fof_set_groups_for_sfr()
-{
- int gid;
+#ifdef PMGRID
+ This function do not work with PMGRID on.
+#endif
- if (ThisTask==0)
- printf("FoF: set groups for sfr\n");
+ int i;
+ int n;
- Ntsfrgroups=0;
+#ifndef NOGRAVITY
+ long long ntot, ntotleft;
+ int j, k, level, sendTask, recvTask;
+ int ndone;
+ int maxfill, ngrp, place, nexport;
+ int *nsend, *noffset, *nsend_local, *nbuffer, *ndonelist, *numlist;
+ double fac;
+ double t0, t1, tstart, tend;
+ MPI_Status status;
+ double r2;
- for (gid=0;gid<Ngroups;gid++)
- if( Groups[gid].Task == ThisTask ) /* a true group */
- {
-
- /* init to 0 */
- Groups[gid].SfrFlag = 0;
-
-
- /* here, we needs to flag for sfr, according to physical quantities */
- printf("FoF: (%d) Members=%d MinMembers=%d\n",ThisTask,Groups[gid].N,All.FoF_MinGroupMembers);
-
- if (Groups[gid].N<All.FoF_MinGroupMembers)
- continue;
-
- printf("FoF: (%d) Mass=%g MinMass%g\n",ThisTask,Groups[gid].Mass*All.CMUtoMsol,All.FoF_MinGroupMass*All.CMUtoMsol);
- if (Groups[gid].Mass<All.FoF_MinGroupMass)
- continue;
+ int NumPot;
- /* remove group that are unbound 2*(T+U)/W >~ 1 */
- printf("FoF: (%d) VirialFraction = %g FoF_VirialFractionThreshold = %g\n",ThisTask,Groups[gid].VirialFraction,All.FoF_VirialFractionThreshold);
- if (Groups[gid].VirialFraction > All.FoF_VirialFractionThreshold)
- continue;
+ t0 = second();
-#ifdef SFR
+ if(All.ComovingIntegrationOn)
+ set_softenings();
- printf("FoF: (%d) Temperature=%g MaxTemperature%g\n",ThisTask, Groups[gid].T, All.StarFormationTemperature);
- if (Groups[gid].T>All.StarFormationTemperature)
- continue;
-
- /* compute the sfr probability */
-
- double p,r;
- double dt=0;
- double tstar=1.;
- double MeanBaryonicDensity;
+ if(ThisTask == 0)
+ {
+ printf("Start computation of potential for particles belonging to a group...\n");
+ fflush(stdout);
+ }
-
- switch (All.StarFormationType)
- {
- case 0:
- All.ThresholdDensity = All.StarFormationDensity;
- break;
-
- case 1:
- MeanBaryonicDensity = All.OmegaBaryon * (3 * All.Hubble * All.Hubble / (8 * M_PI * All.G));
- All.ThresholdDensity = dmax(All.StarFormationDensity/a3inv,200*MeanBaryonicDensity);
- break;
-
- case 2:
- All.ThresholdDensity = All.StarFormationDensity;
- All.StarFormationTime = 1./All.StarFormationCstar / pow(4*PI*All.G*All.StarFormationDensity,0.5);
- break;
-
- case 3:
- All.StarFormationTime = 1./All.StarFormationCstar / pow(4*PI*All.G*All.StarFormationDensity,0.5);
- /* All.ThresholdDensity is fixed further */
- break;
-
- case 4:
- All.ThresholdDensity = All.StarFormationDensity;
- All.StarFormationTime = 1./All.StarFormationCstar / pow((32/(3*PI))*All.G*All.StarFormationDensity,0.5);
- break;
- }
-
-
-
-
-
- dt = DeltaTime; /* computed earlier */
-
-
- tstar = All.StarFormationTime / pow(Groups[gid].Density*a3inv/All.StarFormationDensity,0.5);
- p = (1. - exp(-dt/tstar) );
-
-
- if (All.FoF_StarFormationType==1)
- p = 1;
-
-
- r = get_StarFormation_random_number(Groups[gid].HeadID);
-
- printf("FoF: (%d) Probability=%g Random=%g tstar=%g dt=%g GroupDensity=%g StarFormationDensity=%g \n",ThisTask, p,r,tstar,dt,Groups[gid].Density,All.StarFormationDensity );
- if (r>p)
- continue;
-
-
-
-#endif
-
-
-
- /* the groups may form stars */
- Groups[gid].SfrFlag = 1;
-
- Ntsfrgroups+=1;
-
- //printf("%08d %08d %g %g %g %g %g %g %g %g %g %g %g %g %g \n", Groups[gid].HeadID,Groups[gid].N,Groups[gid].HeadPos[0],Groups[gid].HeadPos[1],Groups[gid].HeadPos[2] , Groups[gid].Mass , Groups[gid].MassCenter[0],Groups[gid].MassCenter[1],Groups[gid].MassCenter[2],Groups[gid].DensityMax,Groups[gid].DensityMin,Groups[gid].RadiusMax,Groups[gid].K,Groups[gid].U,Groups[gid].W);
-
-
- }
-
+ /* for the moment, we do not need the tree */
+ //tstart = second();
+ //if(TreeReconstructFlag)
+ // {
+ // if(ThisTask == 0)
+ // printf("Tree construction.\n");
+ //
+ // force_treebuild(NumPart);
+ //
+ // TreeReconstructFlag = 0;
+ //
+ // if(ThisTask == 0)
+ // printf("Tree construction done.\n");
+ // }
+ //tend = second();
+ //All.CPU_TreeConstruction += timediff(tstart, tend);
+
+
+ /* count the number of particles on which we need to compute potential */
+ for(n = 0, NumPot = 0; n < N_gas; n++)
+ {
- MPI_Allreduce(&Ntsfrgroups, &Tot_Ntsfrgroups, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
+ /* keep only if the particle belong to a group */
+ //SphP[n].FOF_gidx == ...;
+ if (SphP[n].FOF_gidx > -1)
+ {
+ printf("(%d) gidx = %d gid = %d P.ID = %d\n",ThisTask,SphP[n].FOF_gidx,SphP[n].FOF_gid,P[n].ID);
+ NumPot++;
+ }
+ }
- if (ThisTask==0)
- printf("FoF: %d true groups flagged for star formation.\n",Tot_Ntsfrgroups);
-
-
-
-}
-#ifdef SFR
-/*! Flag particles for star formation based on their groups
-*
-*/
-void fof_star_formation()
-{
+ numlist = malloc(NTask * sizeof(int) * NTask);
+ MPI_Allgather(&NumPot, 1, MPI_INT, numlist, 1, MPI_INT, MPI_COMM_WORLD);
+ for(i = 0, ntot = 0; i < NTask; i++)
+ ntot += numlist[i];
+ free(numlist);
- int gid;
- int next;
- int i;
+ 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);
- FILE *fd;
- char buf[500];
+ i = 0; /* beginn with this index */
+ ntotleft = ntot; /* particles left for all tasks together */
- double mnewstars=0,Tot_mnewstars=0;
- double mstars=0,Tot_mstars=0;
- int Nnewstars=0,Tot_Nnewstars=0;
- double star_formation_rate;
-
- if (ThisTask==0)
- printf("FoF: star formation\n");
- if (Ngroups>0)
+ if (ThisTask==0)
{
-
- sprintf(buf, "%s%s.%d", All.OutputDir, "sfp", ThisTask);
+ printf("FoF: compute potential for %d%09d particles.\n", (int) (ntot / 1000000000), (int) (ntot % 1000000000));
+ fflush(stdout);
+ }
-
+
+
+ while(ntotleft > 0)
+ {
+ for(j = 0; j < NTask; j++)
+ nsend_local[j] = 0;
+
+
+ /* do local particles and prepare export list */
+ for(nexport = 0, ndone = 0; i < N_gas && nexport < All.BunchSizeForceFOF - NTask; i++)
+ {
+
+ if (SphP[i].FOF_gidx > -1) /* the particle belongs to a group or pseudo-group */
+ {
+ ndone++;
+
+ for(j = 0; j < NTask; j++)
+ Exportflag[j] = 0;
+
+#ifndef PMGRID
+ fof_evaluate_groups_potential(i, 0);
+#else
+ !!! need to add a function here
+#endif
+
+ for(j = 0; j < NTask; j++)
+ {
+ if(Exportflag[j])
+ {
+ for(k = 0; k < 3; k++)
+ FOFGravDataGet[nexport].u.Pos[k] = P[i].Pos[k];
+#ifdef UNEQUALSOFTENINGS
+ FOFGravDataGet[nexport].Type = P[i].Type;
+#ifdef ADAPTIVE_GRAVSOFT_FORGAS
+ FOFGravDataGet[nexport].Soft = SphP[i].Hsml;
+#endif
+#endif
+ FOFGravDataGet[nexport].FOF_gidx = SphP[i].FOF_gidx;
+ FOFGravDataGet[nexport].FOF_gid = SphP[i].FOF_gid;
+
+
+ GravDataIndexTable[nexport].Task = j;
+ GravDataIndexTable[nexport].Index = i;
+ GravDataIndexTable[nexport].SortIndex = nexport;
+
+ nexport++;
+ nsend_local[j]++;
+ }
+ }
+ }
+ }
+
+ qsort(GravDataIndexTable, nexport, sizeof(struct FOFgravdata_index), grav_fof_compare_key);
+
+ for(j = 0; j < nexport; j++)
+ FOFGravDataIn[j] = FOFGravDataGet[FOFGravDataIndexTable[j].SortIndex];
+
+ for(j = 1, noffset[0] = 0; j < NTask; j++)
+ noffset[j] = noffset[j - 1] + nsend_local[j - 1];
+
+ MPI_Allgather(nsend_local, NTask, MPI_INT, nsend, NTask, MPI_INT, MPI_COMM_WORLD);
+
+ /* now do the particles that need to be exported */
+
+ for(level = 1; level < (1 << PTask); level++)
+ {
+ 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.BunchSizeForceFOF)
+ 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(&FOFGravDataIn[noffset[recvTask]],
+ nsend_local[recvTask] * sizeof(struct FOFgravdata_in), MPI_BYTE,
+ recvTask, TAG_POTENTIAL_A,
+ &FOFGravDataGet[nbuffer[ThisTask]],
+ nsend[recvTask * NTask + ThisTask] * sizeof(struct FOFgravdata_in), MPI_BYTE,
+ recvTask, TAG_POTENTIAL_A, MPI_COMM_WORLD, &status);
+ }
+ }
+
+ for(j = 0; j < NTask; j++)
+ if((j ^ ngrp) < NTask)
+ nbuffer[j] += nsend[(j ^ ngrp) * NTask + j];
+ }
+
+ for(j = 0; j < nbuffer[ThisTask]; j++)
+ {
+#ifndef PMGRID
+ fof_evaluate_groups_potential(j, 1);
+#else
+ !!! need to add a function here
+#endif
+ }
+
+
+ /* get the result */
+ 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.BunchSizeForceFOF)
+ break;
+
+ sendTask = ThisTask;
+ recvTask = ThisTask ^ ngrp;
+
+ if(recvTask < NTask)
+ {
+ if(nsend[ThisTask * NTask + recvTask] > 0 || nsend[recvTask * NTask + ThisTask] > 0)
+ {
+ /* send the results */
+ MPI_Sendrecv(&FOFGravDataResult[nbuffer[ThisTask]],
+ nsend[recvTask * NTask + ThisTask] * sizeof(struct FOFgravdata_in),
+ MPI_BYTE, recvTask, TAG_POTENTIAL_B,
+ &FOFGravDataOut[noffset[recvTask]],
+ nsend_local[recvTask] * sizeof(struct FOFgravdata_in),
+ MPI_BYTE, recvTask, TAG_POTENTIAL_B, MPI_COMM_WORLD, &status);
+
+ /* add the result to the particles */
+ for(j = 0; j < nsend_local[recvTask]; j++)
+ {
+ place = FOFGravDataIndexTable[noffset[recvTask] + j].Index;
+
+ SphP[place].FOFPotential += FOFGravDataOut[j + noffset[recvTask]].u.FOFPotential;
+ }
+ }
+ }
+
+ for(j = 0; j < NTask; j++)
+ if((j ^ ngrp) < NTask)
+ nbuffer[j] += nsend[(j ^ ngrp) * NTask + j];
+ }
+
+ level = ngrp - 1;
+ }
+
+ MPI_Allgather(&ndone, 1, MPI_INT, ndonelist, 1, MPI_INT, MPI_COMM_WORLD);
+ for(j = 0; j < NTask; j++)
+ ntotleft -= ndonelist[j];
+ }
+
+ free(ndonelist);
+ free(nsend);
+ free(nsend_local);
+ free(nbuffer);
+ free(noffset);
+
+
+ /* add correction to exclude self-potential */
+
+ for(i = 0; i < N_gas; i++)
+ if (SphP[i].FOF_gidx > -1) /* the particle belong to a group */
+ {
+ /* remove self-potential */
+ SphP[i].FOFPotential += P[i].Mass / All.SofteningTable[P[i].Type];
+
+ if(All.ComovingIntegrationOn)
+ if(All.PeriodicBoundariesOn)
+ SphP[i].FOFPotential -= 2.8372975 * pow(P[i].Mass, 2.0 / 3) *
+ pow(All.Omega0 * 3 * All.Hubble * All.Hubble / (8 * M_PI * All.G), 1.0 / 3);
+ }
+
+
+ /* multiply with the gravitational constant */
+
+ for(i = 0; i < N_gas; i++)
+ if (SphP[i].FOF_gidx > -1) /* the particle belong to a group */
+ SphP[i].FOFPotential *= All.G;
+
+
+//#ifdef PMGRID
+//
+//need to addapt this...
+//
+//#ifdef PERIODIC
+// pmpotential_periodic();
+//#ifdef PLACEHIGHRESREGION
+// pmpotential_nonperiodic(1);
+//#endif
+//#else
+// pmpotential_nonperiodic(0);
+//#ifdef PLACEHIGHRESREGION
+// pmpotential_nonperiodic(1);
+//#endif
+//#endif
+//
+//#endif //PMGRID
+
+
+
+ if(All.ComovingIntegrationOn)
+ {
+#ifndef PERIODIC
+ fac = -0.5 * All.Omega0 * All.Hubble * All.Hubble;
+
+ for(i = 0; i < N_gas; i++)
+ if (SphP[i].FOF_gidx > -1) /* the particle belong to a group */
+ {
+ for(k = 0, r2 = 0; k < 3; k++)
+ r2 += P[i].Pos[k] * P[i].Pos[k];
+
+ SphP[i].FOFPotential += fac * r2;
+ }
+#endif
+ }
+ else
+ {
+#ifndef FORCE_OMEGALAMBDA_TO_0
+ fac = -0.5 * All.OmegaLambda * All.Hubble * All.Hubble;
+ if(fac != 0)
+ {
+ for(i = 0; i < N_gas; i++)
+ if (SphP[i].FOF_gidx > -1) /* the particle belong to a group */
+ {
+ for(k = 0, r2 = 0; k < 3; k++)
+ r2 += P[i].Pos[k] * P[i].Pos[k];
+
+ SphP[i].FOFPotential += fac * r2;
+ }
+ }
+#endif
+ }
+
+
+ if(ThisTask == 0)
+ {
+ printf("potential due to particles in the group done.\n");
+ fflush(stdout);
+ }
+
+ t1 = second();
+
+ All.CPU_Potential += timediff(t0, t1);
+
+#else
+ for(i = 0; i < N_gas; i++)
+ if (SphP[i].FOF_gidx > -1) /* the particle belong to a group */
+ SphP[i].FOFPotential = 0;
+#endif //NOGRAVITY
+
+
+
+ for(i = 0; i < N_gas; i++)
+ if (SphP[i].FOF_gidx > -1) /* the particle belong to a group */
+ {
+ printf("(%d)--------> pot=%g fofpot=%g (ID=%d)\n",ThisTask,P[i].Potential,SphP[i].FOFPotential,P[i].ID);
+ }
+
+}
+
+
+
+/*! This routine computes the gravitational potential by walking the
+ * tree. The same opening criteria is used as for the gravitational force
+ * walk.
+ */
+void fof_evaluate_groups_potential(int target, int mode)
+{
+
+ int ptype,next,gidx,gid,i;
+ double r2, dx, dy, dz, mass, r, u, h, h_inv, wp;
+ double pot, pos_x, pos_y, pos_z;
+#if defined(UNEQUALSOFTENINGS) && !defined(ADAPTIVE_GRAVSOFT_FORGAS)
+ int maxsofttype;
+#endif
+#ifdef ADAPTIVE_GRAVSOFT_FORGAS
+ double soft = 0;
+#endif
+#ifdef PERIODIC
+ double boxsize, boxhalf;
+
+ boxsize = All.BoxSize;
+ boxhalf = 0.5 * All.BoxSize;
+#endif
+
+ pot = 0;
+
+ if(mode == 0)
+ {
+ pos_x = P[target].Pos[0];
+ pos_y = P[target].Pos[1];
+ pos_z = P[target].Pos[2];
+ ptype = P[target].Type;
+#ifdef ADAPTIVE_GRAVSOFT_FORGAS
+ if(ptype == 0)
+ soft = SphP[target].Hsml;
+#endif
+ gidx = SphP[target].FOF_gidx; /* index to the local group */
+ gid = SphP[target].FOF_gid; /* id of the local group */
+ }
+ else
+ {
+ pos_x = FOFGravDataGet[target].u.Pos[0];
+ pos_y = FOFGravDataGet[target].u.Pos[1];
+ pos_z = FOFGravDataGet[target].u.Pos[2];
+#ifdef UNEQUALSOFTENINGS
+ ptype = FOFGravDataGet[target].Type;
+#else
+ ptype = P[0].Type;
+#endif
+#ifdef ADAPTIVE_GRAVSOFT_FORGAS
+ if(ptype == 0)
+ soft = FOFGravDataGet[target].Soft;
+#endif
+ gid = FOFGravDataGet[target].FOF_gid;
+
+ /* here, gidx = FOFGravDataGet[target].FOF_gidx;
+ /* do not corresponds to the correct Group index,
+ /* we need to loop over groups to find the correct one */
+
+ for (i=0;i<Ngroups;i++)
+ {
+ if ( Groups[i].HeadID == gid) ;
+ {
+ gidx = i;
+ break;
+ }
+
+ if (i==Ngroups-1)
+ {
+ printf("(%d) it seems that we have been unable to find the correct group for this Task !",ThisTask);
+ printf("its better to stop\n");
+ endrun(1975);
+ }
+ }
+
+
+
+ }
+
+
+ next=Groups[gidx].LocalHead; /* indice towards Head or Pseudo Head */
+
+ while(next!=-1) /* loop over all local members */
+ {
+
+ dx = P[next].Pos[0] - pos_x;
+ dy = P[next].Pos[1] - pos_y;
+ dz = P[next].Pos[2] - pos_z;
+ mass = P[next].Mass;
+
+#ifdef PERIODIC
+ dx = NEAREST(dx);
+ dy = NEAREST(dy);
+ dz = NEAREST(dz);
+#endif
+ r2 = dx * dx + dy * dy + dz * dz;
+
+
+
+#ifdef UNEQUALSOFTENINGS
+#ifdef ADAPTIVE_GRAVSOFT_FORGAS
+ h = soft;
+
+ if(h < SphP[next].Hsml)
+ h = SphP[next].Hsml;
+
+#else
+ h = All.ForceSoftening[ptype]; /* all gas particles are gas particles */
+#endif
+#endif
+
+
+ r = sqrt(r2);
+
+ if(r >= h)
+ pot -= mass / r;
+ else
+ {
+#ifdef UNEQUALSOFTENINGS
+ h_inv = 1.0 / h;
+#endif
+ u = r * h_inv;
+
+ if(u < 0.5)
+ wp = -2.8 + u * u * (5.333333333333 + u * u * (6.4 * u - 9.6));
+ else
+ wp =
+ -3.2 + 0.066666666667 / u + u * u * (10.666666666667 +
+ u * (-16.0 + u * (9.6 - 2.133333333333 * u)));
+
+ pot += mass * h_inv * wp;
+ }
+
+#ifdef PERIODIC
+ pot += mass * ewald_pot_corr(dx, dy, dz);
+#endif
+
+
+ next=SphP[next].FOF_Next;
+ }
+
+
+ /*
+
+ now, we need to fill Exportflag[j], to export the particle if needed.
+
+ */
+
+
+
+
+ if(mode == 0)
+ SphP[target].FOFPotential = pot;
+ else
+ FOFGravDataResult[target].u.FOFPotential = pot;
+
+
+}
+
+
+
+
+
+
+
+
+
+/*! Here, each group is flaged to form stars or not.
+* The decision is based on physical properties of the group.
+*
+*/
+void fof_set_groups_for_sfr()
+{
+ int gid;
+
+ if (ThisTask==0)
+ printf("FoF: set groups for sfr\n");
+
+ Ntsfrgroups=0;
+
+ for (gid=0;gid<Ngroups;gid++)
+ if( Groups[gid].Task == ThisTask ) /* a true group */
+ {
+
+ /* init to 0 */
+ Groups[gid].SfrFlag = 0;
+
+
+ /* here, we needs to flag for sfr, according to physical quantities */
+ printf("FoF: (%d) Members=%d MinMembers=%d\n",ThisTask,Groups[gid].N,All.FoF_MinGroupMembers);
+
+ if (Groups[gid].N<All.FoF_MinGroupMembers)
+ continue;
+
+ printf("FoF: (%d) Mass=%g MinMass%g\n",ThisTask,Groups[gid].Mass*All.CMUtoMsol,All.FoF_MinGroupMass*All.CMUtoMsol);
+ if (Groups[gid].Mass<All.FoF_MinGroupMass)
+ continue;
+
+#ifndef FOF_COMPUTE_GROUPS_VIRIAL_LOCALLY
+ /* remove group that are unbound 2*(T+U)/W >~ 1 */
+ printf("FoF: (%d) VirialFraction = %g FoF_VirialFractionThreshold = %g\n",ThisTask,Groups[gid].VirialFraction,All.FoF_VirialFractionThreshold);
+ if (Groups[gid].VirialFraction > All.FoF_VirialFractionThreshold)
+ continue;
+#endif
+
+
+#ifdef SFR
+
+ printf("FoF: (%d) Temperature=%g MaxTemperature%g\n",ThisTask, Groups[gid].T, All.StarFormationTemperature);
+ if (Groups[gid].T>All.StarFormationTemperature)
+ continue;
+
+ /* compute the sfr probability */
+
+ double p,r;
+ double dt=0;
+ double tstar=1.;
+ double MeanBaryonicDensity;
+
+
+ switch (All.StarFormationType)
+ {
+ case 0:
+ All.ThresholdDensity = All.StarFormationDensity;
+ break;
+
+ case 1:
+ MeanBaryonicDensity = All.OmegaBaryon * (3 * All.Hubble * All.Hubble / (8 * M_PI * All.G));
+ All.ThresholdDensity = dmax(All.StarFormationDensity/a3inv,200*MeanBaryonicDensity);
+ break;
+
+ case 2:
+ All.ThresholdDensity = All.StarFormationDensity;
+ All.StarFormationTime = 1./All.StarFormationCstar / pow(4*PI*All.G*All.StarFormationDensity,0.5);
+ break;
+
+ case 3:
+ All.StarFormationTime = 1./All.StarFormationCstar / pow(4*PI*All.G*All.StarFormationDensity,0.5);
+ /* All.ThresholdDensity is fixed further */
+ break;
+
+ case 4:
+ All.ThresholdDensity = All.StarFormationDensity;
+ All.StarFormationTime = 1./All.StarFormationCstar / pow((32/(3*PI))*All.G*All.StarFormationDensity,0.5);
+ break;
+
+ case 6:
+ /* estimate the freefall time */
+ All.StarFormationTime = 1./ pow((32/(3*PI))*All.G*Groups[gid].Density*a3inv,0.5);
+ break;
+
+ }
+
+
+
+
+
+ dt = DeltaTime; /* computed earlier */
+
+
+ //tstar = All.StarFormationTime / pow(Groups[gid].Density*a3inv/All.StarFormationDensity,0.5);
+
+ tstar = All.StarFormationTime * All.StarFormationCstar;
+
+ p = (1. - exp(-dt/tstar) );
+
+
+ if (All.FoF_StarFormationType==1)
+ p = 1;
+
+
+ r = get_StarFormation_random_number(Groups[gid].HeadID);
+
+ printf("FoF: (%d) Probability=%g Random=%g tstar=%g dt=%g GroupDensity=%g StarFormationDensity=%g \n",ThisTask, p,r,tstar,dt,Groups[gid].Density,All.StarFormationDensity );
+ if (r>p)
+ continue;
+
+
+
+#endif
+
+
+
+ /* the groups may form stars */
+ Groups[gid].SfrFlag = 1;
+
+ Ntsfrgroups+=1;
+
+ //printf("%08d %08d %g %g %g %g %g %g %g %g %g %g %g %g %g \n", Groups[gid].HeadID,Groups[gid].N,Groups[gid].HeadPos[0],Groups[gid].HeadPos[1],Groups[gid].HeadPos[2] , Groups[gid].Mass , Groups[gid].MassCenter[0],Groups[gid].MassCenter[1],Groups[gid].MassCenter[2],Groups[gid].DensityMax,Groups[gid].DensityMin,Groups[gid].RadiusMax,Groups[gid].K,Groups[gid].U,Groups[gid].W);
+
+
+ }
+
+
+ MPI_Allreduce(&Ntsfrgroups, &Tot_Ntsfrgroups, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
+
+ if (ThisTask==0)
+ printf("FoF: %d true groups flagged for star formation.\n",Tot_Ntsfrgroups);
+
+
+
+}
+
+#ifdef SFR
+
+/*! Flag particles for star formation based on their groups
+*
+*/
+void fof_star_formation()
+{
+
+ int gid;
+ int next;
+ int i;
+
+ FILE *fd;
+ char buf[500];
+
+ double mnewstars=0,Tot_mnewstars=0;
+ double mstars=0,Tot_mstars=0;
+ int Nnewstars=0,Tot_Nnewstars=0;
+ double star_formation_rate;
+
+ if (ThisTask==0)
+ printf("FoF: star formation\n");
+
+ if (Ngroups>0)
+ {
+
+ sprintf(buf, "%s%s.%d", All.OutputDir, "sfp", ThisTask);
+
+
fd = fopen(buf,"w");
for (gid=0;gid<Ngroups;gid++)
{
if( Groups[gid].SfrFlag == 1 ) /* the group must be flagged as forming stars */
{
/* loop over particles of the group */
next= Groups[gid].LocalHead ;
while(next!=-1)
{
/* create a new star */
P[next].Type = ST;
RearrangeParticlesFlag=1;
/* count mass */
mnewstars+=P[i].Mass;
Nnewstars+=1;
fprintf(fd,"%d\n",P[next].ID);
next=SphP[next].FOF_Next;
}
}
}
fflush(fd);
- close(fd);
+ fclose(fd);
}
/* compute star mass */
mstars=0;
for (i=0;i< NumPart;i++)
{
if (P[i].Type==ST)
mstars+= P[i].Mass;
}
/* share results */
MPI_Allreduce(&mstars, &Tot_mstars, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
MPI_Allreduce(&mnewstars, &Tot_mnewstars, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
MPI_Allreduce(&Nnewstars, &Tot_Nnewstars, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
if (All.TimeStep>0)
star_formation_rate = Tot_mnewstars/All.TimeStep;
else
star_formation_rate = 0.;
#ifndef PY_INTERFACE
if (ThisTask==0)
{
//fprintf(FdSfr, "Step %d, Time: %g, NewStarsPart: %g \n", All.NumCurrentTiStep, All.Time, Tot_mstars);
fprintf(FdSfr, "%15g %15g %15g %15g %15g\n", All.Time,All.TimeStep,Tot_mstars,Tot_mnewstars,star_formation_rate);
fflush(FdSfr);
}
#endif
if(ThisTask == 0)
{
printf("FoF: Total number of new star particles : %d \n",(int) Tot_Nnewstars);
printf("FoF: Total number of star particles : %d%09d\n",(int) (All.TotN_stars / 1000000000), (int) (All.TotN_stars % 1000000000));
fflush(stdout);
}
#ifdef CHECK_BLOCK_ORDER
int typenow;
rearrange_particle_sequence();
typenow = 0;
for(i = 0; i < NumPart; i++)
{
if ((P[i].Type<typenow)&&(typenow<=ST))
{
printf("\nBlock order error\n");
printf("(%d) i=%d id=%d Type=%d typenow=%d\n\n",ThisTask,i,P[i].ID,P[i].Type,typenow);
endrun(999004);
}
typenow = P[i].Type;
}
#endif
#ifdef CHECK_ID_CORRESPONDENCE
rearrange_particle_sequence();
for(i = N_gas; i < N_gas+N_stars; i++)
{
if( StP[P[i].StPIdx].PIdx != i )
{
printf("\nP/StP correspondance error\n");
printf("(%d) (in starformation) N_stars=%d N_gas=%d i=%d id=%d P[i].StPIdx=%d StP[P[i].StPIdx].PIdx=%d\n\n",ThisTask,N_stars,N_gas,i,P[i].ID,P[i].StPIdx,StP[P[i].StPIdx].PIdx);
endrun(999005);
}
if(StP[P[i].StPIdx].ID != P[i].ID)
{
printf("\nP/StP correspondance error\n");
printf("(%d) (in starformation) N_gas=%d N_stars=%d i=%d Type=%d P.Id=%d P[i].StPIdx=%d StP[P[i].StPIdx].ID=%d \n\n",ThisTask,N_gas,N_stars,i,P[i].Type,P[i].ID, P[i].StPIdx, StP[P[i].StPIdx].ID);
endrun(999006);
}
}
#endif
/* force domaine decomposition */
if (Tot_Nnewstars>1)
All.NumForcesSinceLastDomainDecomp = All.TotNumPart * All.TreeDomainUpdateFrequency *10;
}
#endif /* SFR */
/*! This function is responsible of sampling
* the IMF.
*/
void fof_IMF_sampling(int Np)
{
int i,j,k;
double fp;
char buf[500];
FILE *fd = 0;
double Mcl=0;
for (i=0;i<Np;i++)
{
Mcl += FoF_P[i].Mass*All.CMUtoMsol;
}
if (ThisTask==0)
printf("\nFoF: fof_IMF_sampling : members = %6d cluster mass = %6g [Msol]\n",Np,Mcl);
#ifdef CHIMIE_OPTIMAL_SAMPLING
double current_mass;
double Mtot;
int stop_discrete_imf;
double Mrem_cl;
double Mrem_p;
double m1,m2,mp;
current_mass = optimal_init_norm(Mcl); /* in Msol, compute Cp->k and Cp->m_max */
/*
* do the descrete part of the IMF
*/
stop_discrete_imf=0;
for (k=0;k<Np;k++)
{
if (stop_discrete_imf)
break;
/* add at least one star */
Mtot+=current_mass;
FoF_P[k].MassNew = current_mass;
FoF_P[k].MassMax = current_mass;
FoF_P[k].MassMin = current_mass;
FoF_P[k].MassSSP = Mcl;
FoF_P[k].NStars = 1;
FoF_P[k].k = optimal_get_k_normalisation_factor(); /* imf normalisation, Cp->k is set by optimal_init_norm above */
if (optimal_stop_loop(current_mass))
break;
current_mass = optimal_get_next_mass(current_mass);
while( fabs( FoF_P[k].MassNew-FoF_P[k].Mass*All.CMUtoMsol + current_mass ) < fabs( FoF_P[k].MassNew-FoF_P[k].Mass*All.CMUtoMsol ) )
{
Mtot+=current_mass;
FoF_P[k].MassNew += current_mass;
FoF_P[k].MassMin = current_mass;
FoF_P[k].NStars++;
if ( FoF_P[k].NStars >= MAX_STARS_PER_PART)
{
stop_discrete_imf=1;
break;
}
if (optimal_stop_loop(current_mass))
break;
current_mass = optimal_get_next_mass(current_mass);
}
}
/*
* do the continuous part of the IMF
*/
// remaining mass in the cluster
Mrem_cl = Mcl - Mtot;
// mass of remaining particles
Mrem_p=0;
j = k;
for (k=j;k<Np;k++)
Mrem_p+=FoF_P[k].Mass*All.CMUtoMsol;
for (k=j;k<Np;k++)
{
mp = (FoF_P[k].Mass*All.CMUtoMsol)*Mrem_cl/Mrem_p;
m2 = FoF_P[k-1].MassMin;
m1 = optimal_get_m1_from_m2(m2,mp);
Mtot += mp;
FoF_P[k].MassNew = mp;
FoF_P[k].MassMax = m2;
FoF_P[k].MassMin = m1;
FoF_P[k].NStars = -1;
FoF_P[k].MassSSP = Mcl;
}
/* write some info */
if (ThisTask==0)
{
- sprintf(buf, "%s%s_%04d.txt", All.OutputDir, All.FoF_SnapshotFileBase, All.FoF_SnapshotFileCount++);
+ sprintf(buf, "%s%s_%04d.txt", All.OutputDir, All.FoF_IMFSnapshotFileBase, All.FoF_IMFSnapshotFileCount++);
if(!(fd = fopen(buf, "w")))
{
printf("can't open file `%s' for savinf fof.\n", buf);
}
else
{
fprintf(fd,"fof_IMF_sampling :Time=%g members = %6d cluster mass = %6g [Msol]\n",All.Time,Np,Mcl);
fprintf(fd,"\n i ID #stars MassMin MassMax CurrentMass MassNew MassRatio\n\n");
for (i=0;i<Np;i++)
{
fp = 100*fabs(FoF_P[i].Mass*All.CMUtoMsol - FoF_P[i].MassNew) / (FoF_P[i].Mass*All.CMUtoMsol);
//if (fp>50)
//printf("FoF: fof_IMF_sampling : %3d %6d %4d %8.4g %8.4g %6.2f %6.2f %g\n",i,FoF_P[i].ID,FoF_P[i].NStars,FoF_P[i].MassMin,FoF_P[i].MassMax,FoF_P[i].MassNew,FoF_P[i].Mass*All.CMUtoMsol, FoF_P[i].Mass*All.CMUtoMsol/FoF_P[i].MassNew );
fprintf(fd,"%3d %6d %4d %8.4g %8.4g %6.2f %6.2f %6.3f %g %g %g\n",i, FoF_P[i].ID, FoF_P[i].NStars, FoF_P[i].MassMin, FoF_P[i].MassMax, FoF_P[i].Mass*All.CMUtoMsol, FoF_P[i].MassNew, FoF_P[i].Mass*All.CMUtoMsol/FoF_P[i].MassNew, FoF_P[i].Pos[0], FoF_P[i].Pos[1], FoF_P[i].Pos[2] );
}
/* check */
fp = 100* (Mcl-Mtot)/(Mcl);
//if (fp>1e-3)
{
printf("FoF: fof_IMF_sampling : Mtot=%8.2f mass difference %7.3f %\n", Mtot,100* (Mcl-Mtot)/(Mcl) );
fprintf(fd,"\nMtot=%8.2f mass difference %7.3f %\n", Mtot,100* (Mcl-Mtot)/(Mcl) );
}
fflush(fd);
}
fclose(fd);
}
/* convert all masses in Code Mass Unit */
for (k=0;k<Np;k++)
{
FoF_P[k].MassMax *= All.MsoltoCMU;
FoF_P[k].MassMin *= All.MsoltoCMU;
FoF_P[k].MassSSP *= All.MsoltoCMU;
}
#endif
}
#ifdef SFR
/*! Flag particles for star formation based on their groups
* in addition, we address to each particles Min and Max stellar
* masses that it will represent, according to an IMF
*
*/
void fof_star_formation_and_IMF_sampling()
{
int gid;
int next;
int index;
int i,j,k;
double mnewstars=0,Tot_mnewstars=0;
double mstars=0,Tot_mstars=0;
int Nnewstars=0,Tot_Nnewstars=0;
double star_formation_rate;
int ntop;
int *ntoplist, *ntopoffset;
int *npartlist, *npartoffset;
int Np=0,Np_local;
int Ns=0;
int pass;
if (ThisTask==0)
printf("FoF: star formation and IMF sampling\n");
/* create the TopTGroups structure
TopTSfrGroups is a structure shared by all Tasks and contains
the Task and Head of all true groups.
*/
TopTSfrGroups = malloc(sizeof(struct fof_topgroups_exchange)*Tot_Ntsfrgroups);
TopTSfrGroups_local = malloc(sizeof(struct fof_topgroups_exchange)*Ntsfrgroups);
j=0;
if (Ngroups>0)
{
for (gid=0;gid<Ngroups;gid++)
{
if( Groups[gid].Task == ThisTask ) /* a true group */
{
if( Groups[gid].SfrFlag == 1 ) /* the group must be flagged as forming stars */
{
if (j==Ntsfrgroups)
{
printf("j=%d == Nsfrgroups=%d !!!\n",j,Ntsfrgroups);
endrun(1970);
}
TopTSfrGroups_local[j].Task = Groups[gid].Task;
TopTSfrGroups_local[j].Head = Groups[gid].Head;
j++;
}
}
}
}
ntoplist = malloc(sizeof(int) * NTask);
ntopoffset = malloc(sizeof(int) * NTask);
MPI_Allgather(&Ntsfrgroups, 1, MPI_INT, ntoplist, 1, MPI_INT, MPI_COMM_WORLD);
for(i = 0, ntopoffset[0] = 0; i < NTask; i++)
{
if(i > 0)
ntopoffset[i] = ntopoffset[i - 1] + ntoplist[i - 1];
}
for(i = 0; i < NTask; i++)
{
ntoplist[i] *= sizeof(struct fof_topgroups_exchange);
ntopoffset[i] *= sizeof(struct fof_topgroups_exchange);
}
MPI_Allgatherv(TopTSfrGroups_local, Ntsfrgroups * sizeof(struct fof_topgroups_exchange), MPI_BYTE, TopTSfrGroups, ntoplist, ntopoffset, MPI_BYTE, MPI_COMM_WORLD);
free(ntoplist);
free(ntopoffset);
/* check that TopTGroups is correct */
/*
for (i=0;i<Ntsfrgroups;i++)
printf(">>> local (%d) i=%d Task=%d Head=%d \n",ThisTask,i,TopTSfrGroups_local[i].Task,TopTSfrGroups_local[i].Head);
if (ThisTask==0)
for (i=0;i<Tot_Ntsfrgroups;i++)
printf(">>> global (%d) i=%d Task=%d Head=%d \n",ThisTask,i,TopTSfrGroups[i].Task,TopTSfrGroups[i].Head);
*/
/*
Here, we want to fill the FoF_P structure that contains particles information for a group that will form an IMF. This structure is shared by all Tasks.
Loop over all TopTSfrGroups and check if a local Group corresponds to it.
1) fill FoF_P_local with local information
2) send FoF_P_local to all and create FoF_P
*/
RearrangeParticlesFlag=0;
for (i=0;i<Tot_Ntsfrgroups;i++)
{
Np_local=-1;
pass=0;
if (Ngroups>0)
{
for (gid=0;gid<Ngroups;gid++)
{
if( Groups[gid].SfrFlag == 1 ) /* the group must be flagged as forming stars */
{
if ( (Groups[gid].Task==TopTSfrGroups[i].Task) && ((Groups[gid].Head==TopTSfrGroups[i].Head))) /* the pseudo group fit the top group */
{
/* count number of stars */
/* Note : Groups[gid].N != Np_local as it corresponds to the total group for the true Groups */
Np_local = 0;
next= Groups[gid].LocalHead ;
while(next!=-1)
{
Np_local+=1;
next=SphP[next].FOF_Next;
}
if (pass!=0)
{
printf("(%d) we already found a group linked to Task=%d Head=%d in this proc. \n",ThisTask,TopTSfrGroups[i].Task,TopTSfrGroups[i].Head);
printf("we should reduce such groups before... we prefere to stop.\n");
endrun(1974);
}
pass++;
/* prepare stars */
FoF_P_local = malloc(Np_local*sizeof(struct fof_particles_in));
next= Groups[gid].LocalHead ;
j=0;
while(next!=-1)
{
FoF_P_local[j].Mass = P[next].Mass;
FoF_P_local[j].Task = ThisTask;
FoF_P_local[j].Index = next;
FoF_P_local[j].ID = P[next].ID;
FoF_P_local[j].Pos[0] = P[next].Pos[0];
FoF_P_local[j].Pos[1] = P[next].Pos[1];
FoF_P_local[j].Pos[2] = P[next].Pos[2];
+
+#ifdef FOF_COMPUTE_GROUPS_VIRIAL_LOCALLY
+ FoF_P_local[j].Vel[0] = P[next].Vel[0];
+ FoF_P_local[j].Vel[1] = P[next].Vel[1];
+ FoF_P_local[j].Vel[2] = P[next].Vel[2];
+
+
+#ifdef ISOTHERM_EQS
+ FoF_P_local[j].EnergySpec = SphP[next].Entropy;
+#else
+#ifdef DENSITY_INDEPENDENT_SPH
+ FoF_P_local[j].EnergySpec = SphP[next].Entropy / (GAMMA_MINUS1) * pow(SphP[next].EgyWtDensity / a3, GAMMA_MINUS1);
+#else
+ FoF_P_local[j].EnergySpec = SphP[next].Entropy / (GAMMA_MINUS1) * pow(SphP[next].Density / a3, GAMMA_MINUS1);
+#endif
+#endif /*ISOTHERM_EQS*/
+
+
+#ifdef DENSITY_INDEPENDENT_SPH
+ FoF_P_local[j].Density = SphP[next].EgyWtDensity;
+#else
+ FoF_P_local[j].Density = SphP[next].Density;
+#endif
+
+
+
+#ifdef ADAPTIVE_GRAVSOFT_FORGAS
+ FoF_P_local[j].Hsml = P[next].Hsml;
+#endif
+
+
+
+#endif
+
j++;
next=SphP[next].FOF_Next;
}
/* sort particles according to some physical quantity */
qsort(FoF_P_local, Np_local, sizeof(struct fof_particles_in), fof_compare_particles);
}
}
}
}
/* all Tasks get all particles and sample the IMF, thus, we no longer needs to communicate back */
if (Np_local==-1) /* no particles for this Task */
{
Np_local = 0;
FoF_P_local = malloc(Np_local*sizeof(struct fof_particles_in));
}
npartlist = malloc(sizeof(int) * NTask);
npartoffset = malloc(sizeof(int) * NTask);
MPI_Allgather(&Np_local, 1, MPI_INT, npartlist, 1, MPI_INT, MPI_COMM_WORLD);
for(k = 0, Np=0, npartoffset[0] = 0; k < NTask; k++)
{
Np += npartlist[k];
if(k > 0)
npartoffset[k] = npartoffset[k - 1] + npartlist[k - 1];
}
FoF_P = malloc(Np * sizeof(struct fof_particles_in));
for(k = 0; k < NTask; k++)
{
npartlist[k] *= sizeof(struct fof_particles_in);
npartoffset[k] *= sizeof(struct fof_particles_in);
}
MPI_Allgatherv(FoF_P_local, Np_local * sizeof(struct fof_particles_in), MPI_BYTE, FoF_P, npartlist, npartoffset, MPI_BYTE, MPI_COMM_WORLD);
/* sort particles according to some physical quantity */
qsort(FoF_P, Np, sizeof(struct fof_particles_in), fof_compare_particles);
//Ns += Np;
//if (ThisTask==0)
// printf("check i=%d Np=%d Ns=%d Task=%d Head=%d\n",i,Np,Ns,TopTSfrGroups[i].Task,TopTSfrGroups[i].Head);
//if (ThisTask==0)
//{
// printf("check %d \n",i);
// for(k=0;k<Np;k++)
// printf("check %d %g\n",FoF_P[k].ID,FoF_P[k].Mass);
//}
+#ifdef FOF_COMPUTE_GROUPS_VIRIAL_LOCALLY
+ double VirialFraction;
+ double Epot,Ekin,Eint;
+ VirialFraction = fof_compute_groups_virial_locally(Np,&Epot,&Ekin,&Eint);
+
+
+ if (ThisTask==0)
+ fof_save_fof_particles(Np,VirialFraction,Epot,Ekin,Eint);
+
+
+ if (VirialFraction < All.FoF_VirialFractionThreshold)
+ {
+#endif
+
+
/*
now, sample the IMF
*/
fof_IMF_sampling(Np);
/* now, each proc copy its particles from FoF_P */
for(k = 0; k < Np; k++)
{
if (FoF_P[k].Task==ThisTask)
{
index = FoF_P[k].Index;
/* at this point, we turn gas particles into stellar particles */
#ifdef STELLAR_PROP
if (N_stars+Nnewstars+1 > All.MaxPartStars)
{
printf("No memory left for new star particle : N_stars+1=%d MaxPartStars=%d\n\n",N_stars+1,All.MaxPartStars);
endrun(999008);
}
#else
if (N_stars+Nnewstars+1 > All.MaxPart-N_gas)
{
printf("No memory left for new star particle : N_stars+1=%d All.MaxPart-N_gas=%d\n\n",N_stars+1,All.MaxPart-N_gas);
endrun(999009);
}
#endif
RearrangeParticlesFlag=1;
P[index].Mass = FoF_P[k].MassNew*All.MsoltoCMU;
P[index].Type = ST;
//P[index].FoFidx = k; /* reference to the FoF_P structure (no longer used) */
/* we store IMF information in the SPH structure in order to use the information in the rearrange_particle_sequence routine
and as StP still doesn't exists for these particles. */
SphP[index].FOF_MassMax = FoF_P[k].MassMax;
SphP[index].FOF_MassMin = FoF_P[k].MassMin;
SphP[index].FOF_MassSSP = FoF_P[k].MassSSP;
SphP[index].FOF_NStars = FoF_P[k].NStars;
#ifdef CHIMIE_OPTIMAL_SAMPLING
SphP[index].OptIMF_k = FoF_P[k].k;
SphP[index].OptIMF_CurrentMass = FoF_P[k].MassMax*All.CMUtoMsol;
#endif
mnewstars+=P[index].Mass;
Nnewstars+=1;
/* gather energy */
#ifdef FEEDBACK
LocalSysState.StarEnergyFeedback += SphP[i].EgySpecFeedback * P[i].Mass;
#endif
-
-
-
-
}
}
-
+
+
+
+#ifdef FOF_COMPUTE_GROUPS_VIRIAL_LOCALLY
+ }
+#endif
+
free(npartlist);
free(npartoffset);
free(FoF_P);
free(FoF_P_local);
}
free(TopTSfrGroups_local);
free(TopTSfrGroups);
/* rearrange_particle_sequence
* this may not be done after each group, as we
* need to conserve particle order
*/
rearrange_particle_sequence();
/* compute star mass */
mstars=0;
for (i=0;i< NumPart;i++)
{
if (P[i].Type==ST)
mstars+= P[i].Mass;
}
/* share results */
MPI_Allreduce(&mstars, &Tot_mstars, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
MPI_Allreduce(&mnewstars, &Tot_mnewstars, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
MPI_Allreduce(&Nnewstars, &Tot_Nnewstars, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
if (All.TimeStep>0)
star_formation_rate = Tot_mnewstars/All.TimeStep;
else
star_formation_rate = 0.;
#ifndef PY_INTERFACE
if (ThisTask==0)
{
//fprintf(FdSfr, "Step %d, Time: %g, NewStarsPart: %g \n", All.NumCurrentTiStep, All.Time, Tot_mstars);
fprintf(FdSfr, "%15g %15g %15g %15g %15g\n", All.Time,All.TimeStep,Tot_mstars,Tot_mnewstars,star_formation_rate);
fflush(FdSfr);
}
#endif
if(ThisTask == 0)
{
printf("FoF: Total number of new star particles : %d \n",(int) Tot_Nnewstars);
printf("FoF: Total number of star particles : %d%09d\n",(int) (All.TotN_stars / 1000000000), (int) (All.TotN_stars % 1000000000));
fflush(stdout);
}
#ifdef CHECK_BLOCK_ORDER
int typenow;
rearrange_particle_sequence();
typenow = 0;
for(i = 0; i < NumPart; i++)
{
if ((P[i].Type<typenow)&&(typenow<=ST))
{
printf("\nBlock order error\n");
printf("(%d) i=%d id=%d Type=%d typenow=%d\n\n",ThisTask,i,P[i].ID,P[i].Type,typenow);
endrun(999004);
}
typenow = P[i].Type;
}
#endif
#ifdef CHECK_ID_CORRESPONDENCE
rearrange_particle_sequence();
for(i = N_gas; i < N_gas+N_stars; i++)
{
if( StP[P[i].StPIdx].PIdx != i )
{
printf("\nP/StP correspondance error\n");
printf("(%d) (in starformation) N_stars=%d N_gas=%d i=%d id=%d P[i].StPIdx=%d StP[P[i].StPIdx].PIdx=%d\n\n",ThisTask,N_stars,N_gas,i,P[i].ID,P[i].StPIdx,StP[P[i].StPIdx].PIdx);
endrun(999005);
}
if(StP[P[i].StPIdx].ID != P[i].ID)
{
printf("\nP/StP correspondance error\n");
printf("(%d) (in starformation) N_gas=%d N_stars=%d i=%d Type=%d P.Id=%d P[i].StPIdx=%d StP[P[i].StPIdx].ID=%d \n\n",ThisTask,N_gas,N_stars,i,P[i].Type,P[i].ID, P[i].StPIdx, StP[P[i].StPIdx].ID);
endrun(999006);
}
}
#endif
/* force domaine decomposition */
if (Tot_Nnewstars>1)
All.NumForcesSinceLastDomainDecomp = All.TotNumPart * All.TreeDomainUpdateFrequency *10;
}
#endif /* SFR */
+#ifdef FOF_COMPUTE_GROUPS_VIRIAL_LOCALLY
+
+
+
+/*! This function is responsible of sampling
+ * the IMF.
+ */
+double fof_compute_groups_virial_locally(int Np,double *Epot,double *Ekin,double *Eint)
+{
+
+ int i,j,k;
+ double U,K,W;
+ double pot;
+ double r2, dx, dy, dz, massi,massj, r, u, h, h_inv, wp;
+ double pos_x,pos_y,pos_z;
+ double fac;
+ double VirialFraction;
+#ifdef ADAPTIVE_GRAVSOFT_FORGAS
+ double soft;
+#endif
+
+#ifdef PERIODIC
+ double boxsize, boxhalf;
+
+ boxsize = All.BoxSize;
+ boxhalf = 0.5 * All.BoxSize;
+#endif
+
+
+ if (ThisTask==0)
+ printf("\n(%d)FoF: fof_compute_groups_virial_locally : members = %6d \n",ThisTask,Np);
+
+
+
+ /* compute potential energy */
+ for (i=0;i<Np;i++)
+ FoF_P[i].Potential=0;
+
+
+ for (i=0;i<Np;i++)
+ {
+
+ pos_x = FoF_P[i].Pos[0];
+ pos_y = FoF_P[i].Pos[1];
+ pos_z = FoF_P[i].Pos[2];
+ massi = FoF_P[i].Mass;
+#ifdef ADAPTIVE_GRAVSOFT_FORGAS
+ soft = FoF_P[i].Hsml;
+#endif
+
+ for (j=i+1;j<Np;j++)
+ {
+
+
+ dx = FoF_P[j].Pos[0] - pos_x;
+ dy = FoF_P[j].Pos[1] - pos_y;
+ dz = FoF_P[j].Pos[2] - pos_z;
+ massj = FoF_P[j].Mass;
+
+#ifdef PERIODIC
+ dx = NEAREST(dx);
+ dy = NEAREST(dy);
+ dz = NEAREST(dz);
+#endif
+ r2 = dx * dx + dy * dy + dz * dz;
+
+
+
+#ifdef UNEQUALSOFTENINGS
+#ifdef ADAPTIVE_GRAVSOFT_FORGAS
+ h = soft;
+
+ if(h < FoF_P[j].Hsml)
+ h = FoF_P[j].Hsml;
+
+#else
+ h = All.ForceSoftening[0]; /* all gas particles are gas particles */
+#endif
+#endif
+
+ r = sqrt(r2);
+
+ if(r >= h)
+ pot -= 1 / r;
+ else
+ {
+#ifdef UNEQUALSOFTENINGS
+ h_inv = 1.0 / h;
+#endif
+ u = r * h_inv;
+
+ if(u < 0.5)
+ wp = -2.8 + u * u * (5.333333333333 + u * u * (6.4 * u - 9.6));
+ else
+ wp = -3.2 + 0.066666666667 / u + u * u * (10.666666666667 +
+ u * (-16.0 + u * (9.6 - 2.133333333333 * u)));
+
+ pot = h_inv * wp;
+
+ }
+
+#ifdef PERIODIC
+ pot += ewald_pot_corr(dx, dy, dz);
+#endif
+
+ FoF_P[i].Potential+=pot*massj;
+ FoF_P[j].Potential+=pot*massi;
+
+ }
+ }
+
+
+ /* add some corrections */
+
+
+ for (i=0;i<Np;i++)
+ {
+
+ if(All.ComovingIntegrationOn)
+ if(All.PeriodicBoundariesOn)
+ FoF_P[i].Potential -= 2.8372975 * pow(FoF_P[i].Mass, 2.0 / 3) *
+ pow(All.Omega0 * 3 * All.Hubble * All.Hubble / (8 * M_PI * All.G), 1.0 / 3);
+
+
+ FoF_P[i].Potential *= All.G;
+
+
+ if(All.ComovingIntegrationOn)
+ {
+#ifndef PERIODIC
+ fac = -0.5 * All.Omega0 * All.Hubble * All.Hubble;
+
+ for(i = 0; i < N_gas; i++)
+ {
+ for(k = 0, r2 = 0; k < 3; k++)
+ r2 += FoF_P[i].Pos[k] * FoF_P[i].Pos[k];
+
+ FoF_P[i].Potential += fac * r2;
+ }
+#endif
+ }
+ else
+ {
+#ifndef FORCE_OMEGALAMBDA_TO_0
+ fac = -0.5 * All.OmegaLambda * All.Hubble * All.Hubble;
+ if(fac != 0)
+ {
+ for(i = 0; i < N_gas; i++)
+ {
+ for(k = 0, r2 = 0; k < 3; k++)
+ r2 += FoF_P[i].Pos[k] * FoF_P[i].Pos[k];
+
+ FoF_P[i].Potential += fac * r2;
+ }
+ }
+#endif
+ }
+
+ }
+
+
+
+
+ W = 0;
+ for (i=0;i<Np;i++)
+ W+= FoF_P[i].Mass * FoF_P[i].Potential;
+ W = 0.5*W;
+
+ /* compute kinetic energy */
+ K = 0;
+ for (i=0;i<Np;i++)
+ K+= FoF_P[i].Mass * ( FoF_P[i].Vel[0]*FoF_P[i].Vel[0] + FoF_P[i].Vel[1]*FoF_P[i].Vel[1] + FoF_P[i].Vel[2]*FoF_P[i].Vel[2]);
+ K = 0.5*K;
+
+
+
+
+ /* compute internal energy */
+ U = 0;
+ for (i=0;i<Np;i++)
+ {
+ if (ThisTask==0)
+ printf("--> %d %g %g\n",FoF_P[i].ID,FoF_P[i].Mass,FoF_P[i].EnergySpec);
+ U+= FoF_P[i].Mass * FoF_P[i].EnergySpec;
+ }
+
+
+
+
+ VirialFraction=-2*(K + U )/ W;
+
+
+ if (ThisTask==0)
+ printf("\n(%d)FoF: Time=%15g VirialFraction = %15g \n",ThisTask,All.Time,VirialFraction);
+
+
+ *Epot = W;
+ *Ekin = K;
+ *Eint = U;
+
+
+ return VirialFraction;
+
+
+
+
+}
+
+
+
+
+void fof_save_fof_particles(int Np,double VirialFraction,double Epot,double Ekin,double Eint)
+{
+
+
+ FILE *fd;
+ char buf[500];
+ int i;
+
+
+
+ if (VirialFraction < All.FoF_VirialFractionThreshold)
+ sprintf(buf, "%s%s_accepted_%04d.txt", All.OutputDir, All.FoF_SnapshotFileBase, All.FoF_SnapshotFileCount_Accepted++);
+ else
+ //sprintf(buf, "%s%s_rejected_%04d.txt", All.OutputDir, All.FoF_SnapshotFileBase, All.FoF_SnapshotFileCount_Rejected++);
+ return;
+
+
+
+
+
+ printf("FoF: fof_save_fof_particles\n");
+
+ fd = fopen(buf, "w");
+ fprintf(fd,"Time = %g\nMembers = %6d\nVirialFraction = %g\nEpot = %g\nEkin = %g\nEint = %g\n\n",All.Time,Np,VirialFraction,Epot,Ekin,Eint);
+
+
+
+ for (i=0;i<Np;i++)
+ {
+ fprintf(fd,"%3d %20.10e %20.15e %20.10e %20.10e %20.10e %20.10e %20.10e %20.10e %20.10e\n",FoF_P[i].ID,FoF_P[i].Pos[0],FoF_P[i].Pos[1],FoF_P[i].Pos[2],FoF_P[i].Vel[0],FoF_P[i].Vel[1],FoF_P[i].Vel[2],FoF_P[i].Mass,FoF_P[i].EnergySpec,FoF_P[i].Density);
+ }
+
+
+
+
+
+
+ fclose(fd);
+}
+#endif // FOF_COMPUTE_GROUPS_VIRIAL_LOCALLY
void fof_group_info(void)
{
int i;
int next;
for(i = 0; i < N_gas; i++)
if ( (P[i].Type == 0) && (SphP[i].Density*a3inv>All.FoF_ThresholdDensity) )
if (P[i].ID==3480)
if (SphP[i].FOF_Head==i)
{
printf("(%d) this is indeed a head (CPUHead=%d CPUPrev=%d prev=%d)\n",ThisTask,SphP[i].FOF_CPUHead,SphP[i].FOF_CPUPrev,SphP[i].FOF_Prev);
next=i;
while(next!=-1)
{
printf("%08d\n",P[next].ID);
next=SphP[next].FOF_Next;
}
}
}
/*! Send pseudo heads and find correct head in distant CPU
*
* Here, we call the routinie : fof_link_pseudo_heads(j)
*
*/
void fof_send_and_link_pseudo_heads(void)
{
long long ntot, ntotleft;
int i, j, k, n, ngrp, maxfill, source, ndone;
int level, sendTask, recvTask, nexport, place;
int *nbuffer, *noffset, *nsend_local, *nsend, *numlist, *ndonelist;
int npleft;
int iter=0;
MPI_Status status;
numlist = malloc(NTask * sizeof(int) * NTask);
MPI_Allgather(&NpHead, 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);
do
{
i=0;
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 */
for(nexport = 0, ndone = 0; i < N_gas && nexport < All.BunchSizeFOF - NTask; i++)
if ( (SphP[i].FOF_Head==i) && (SphP[i].FOF_CPUHead!=ThisTask) && (SphP[i].FOF_Done==0) ) /* a pseudo head */
{
ndone++;
j = SphP[i].FOF_CPUHead;
for(k = 0; k < 3; k++)
{
FOFDataIn[nexport].Pos[k] = P[i].Pos[k];
}
FOFDataIn[nexport].Density = SphP[i].Density;
FOFDataIn[nexport].Hsml = SphP[i].Hsml;
FOFDataIn[nexport].ID = P[i].ID;
FOFDataIn[nexport].FOF_Prev = SphP[i].FOF_Prev;
FOFDataIn[nexport].FOF_Head = SphP[i].FOF_Head;
FOFDataIn[nexport].Index = i;
FOFDataIn[nexport].Task = j;
nexport++;
nsend_local[j]++;
}
qsort(FOFDataIn, nexport, sizeof(struct FOFdata_in), fof_compare_key);
for(j = 1, noffset[0] = 0; j < NTask; j++)
noffset[j] = noffset[j - 1] + nsend_local[j - 1];
MPI_Allgather(nsend_local, NTask, MPI_INT, nsend, NTask, MPI_INT, MPI_COMM_WORLD);
/* now do the particles that need to be exported */
for(level = 1; level < (1 << PTask); level++)
{
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.BunchSizeFOF)
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(&FOFDataIn[noffset[recvTask]],
nsend_local[recvTask] * sizeof(struct FOFdata_in), MPI_BYTE,
recvTask, TAG_HYDRO_A,
&FOFDataGet[nbuffer[ThisTask]],
nsend[recvTask * NTask + ThisTask] * sizeof(struct FOFdata_in), MPI_BYTE,
recvTask, TAG_HYDRO_A, MPI_COMM_WORLD, &status);
}
}
for(j = 0; j < NTask; j++)
if((j ^ ngrp) < NTask)
nbuffer[j] += nsend[(j ^ ngrp) * NTask + j];
}
/* now do the imported particles */
for(j = 0; j < nbuffer[ThisTask]; j++)
fof_link_pseudo_heads(j);
/* do a block to measure imbalance */
/* get the result */
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.BunchSizeFOF)
break;
sendTask = ThisTask;
recvTask = ThisTask ^ ngrp;
if(recvTask < NTask)
{
if(nsend[ThisTask * NTask + recvTask] > 0 || nsend[recvTask * NTask + ThisTask] > 0)
{
MPI_Sendrecv(&FOFDataResult[nbuffer[ThisTask]],
nsend[recvTask * NTask + ThisTask] * sizeof(struct FOFdata_out),
MPI_BYTE, recvTask, TAG_HYDRO_B,
&FOFDataPartialResult[noffset[recvTask]],
nsend_local[recvTask] * sizeof(struct FOFdata_out),
MPI_BYTE, recvTask, TAG_HYDRO_B, MPI_COMM_WORLD, &status);
for(j = 0; j < nsend_local[recvTask]; j++)
{
source = j + noffset[recvTask];
place = FOFDataIn[source].Index;
SphP[place].FOF_Head = FOFDataPartialResult[source].FOF_Head;
SphP[place].FOF_CPUHead = FOFDataPartialResult[source].FOF_CPUHead;
SphP[place].FOF_Prev = FOFDataPartialResult[source].FOF_Prev;
SphP[place].FOF_CPUPrev = FOFDataPartialResult[source].FOF_CPUPrev;
SphP[place].FOF_Done = FOFDataPartialResult[source].FOF_Done;
}
}
}
for(j = 0; j < NTask; j++)
if((j ^ ngrp) < NTask)
nbuffer[j] += nsend[(j ^ ngrp) * NTask + j];
}
level = ngrp - 1;
}
MPI_Allgather(&ndone, 1, MPI_INT, ndonelist, 1, MPI_INT, MPI_COMM_WORLD);
for(j = 0; j < NTask; j++)
ntotleft -= ndonelist[j];
}
/* do final operations on results */
/* count particles that needs another loop */
MPI_Barrier(MPI_COMM_WORLD);
for(i = 0, npleft = 0; i < N_gas; i++)
if ( (SphP[i].FOF_Head==i) && (SphP[i].FOF_CPUHead!=ThisTask) ) /* a pseudo head */
if (SphP[i].FOF_Done==0) /* not done yet */
npleft++;
numlist = malloc(NTask * sizeof(int) * NTask);
MPI_Allgather(&npleft, 1, MPI_INT, numlist, 1, MPI_INT, MPI_COMM_WORLD);
for(i = 0, ntot = 0; i < NTask; i++)
ntot += numlist[i];
free(numlist);
if(ntot > 0)
{
iter++;
if (ThisTask==0)
{
printf("FoF: iteration %03d : need to repeat for %d%09d particles.\n",iter,(int) (ntot / 1000000000), (int) (ntot % 1000000000));
fflush(stdout);
}
if (iter>10)
{
endrun(1260);
}
}
}
while(ntot>0);
free(ndonelist);
free(nsend);
free(nsend_local);
free(nbuffer);
free(noffset);
}
void fof_allocate_groups(void)
{
Groups = malloc(sizeof(struct fof_groups_data) * (NpHead+NHead));
}
void fof_free_groups(void)
{
free(Groups);
}
/*! Link an imported pseudo head to a local head
*
* If the imported particle points towards a particle
* that is actually exported, wait for another loop..
* and flag it as not done : .FOF_Done=0.
*
*/
void fof_link_pseudo_heads(int target)
{
int prev,tail,head;
if (FOFDataGet[target].Task!=ThisTask)
{
printf("(%d) received ID=%d task=%d\n",ThisTask,FOFDataGet[target].ID,FOFDataGet[target].Task);
endrun(1956);
}
prev = FOFDataGet[target].FOF_Prev;
if (SphP[prev].FOF_Prev==-1) /* a dead end */
{
FOFDataResult[target].FOF_Prev = -1;
FOFDataResult[target].FOF_Head = -1;
FOFDataResult[target].FOF_Done = 1;
return;
}
/* find a valid head */
head = SphP[prev].FOF_Head;
if (head==-1)
endrun(1957);
if (SphP[head].FOF_Head==-1) /* a dead end */
{
FOFDataResult[target].FOF_Prev = -1;
FOFDataResult[target].FOF_Head = -1;
FOFDataResult[target].FOF_Done = 1;
return;
}
if (head!=SphP[head].FOF_Head)
{
printf("(%d) the head particle i=%d (i.FOF_Head=%d) is not a head !!! (i.FOF_CPUPrev=%d)\n",ThisTask,head,SphP[head].FOF_Head,SphP[head].FOF_CPUPrev);
endrun(1958);
}
/* head is now either
- a true head
- a pseudo head, but not done
- a pseudo head, done (prev=-2)
- a pseudo head, done
*/
/* a true head */
if ((SphP[head].FOF_CPUHead==ThisTask)&&(SphP[head].FOF_CPUPrev!=-2))
{
FOFDataResult[target].FOF_Prev = head; /* for this pseudo head, the head remains the same, but the real head is stored in prev */
FOFDataResult[target].FOF_CPUPrev = ThisTask;
FOFDataResult[target].FOF_Head = FOFDataGet[target].Index;
FOFDataResult[target].FOF_CPUHead = ThisTask;
FOFDataResult[target].FOF_Done = 1;
return;
}
/* a pseudo head, but not done */
if ( (SphP[head].FOF_CPUHead!=ThisTask) && (SphP[head].FOF_Done==0))
{
FOFDataResult[target].FOF_Prev = FOFDataGet[target].FOF_Prev; /* do nothing */
FOFDataResult[target].FOF_CPUPrev = ThisTask;
FOFDataResult[target].FOF_Head = FOFDataGet[target].FOF_Head; /* do nothing */
FOFDataResult[target].FOF_CPUHead = ThisTask;
FOFDataResult[target].FOF_Done = 0;
return;
}
/* a pseudo head, but done (prev=-2) */
if ((SphP[head].FOF_CPUHead==ThisTask)&&(SphP[head].FOF_CPUPrev==-2))
{
FOFDataResult[target].FOF_Prev = SphP[head].FOF_Prev;
FOFDataResult[target].FOF_CPUPrev = -2; /* this is to keep the trace that the particle was as pseudo head, as its new FOF_CPUHead could be now its own CPU */
FOFDataResult[target].FOF_Head = FOFDataGet[target].Index; /* WARNING : THOSE PARTICLES ARE PSEUDO HEAD THAT LINK TO OTHER CPU THAN THE INITIAL ONE */
FOFDataResult[target].FOF_CPUHead = SphP[head].FOF_CPUHead; /* instead of this ThisTask */
FOFDataResult[target].FOF_Done = 1;
return;
}
/* a pseudo head, but done */
if ( (SphP[head].FOF_CPUHead!=ThisTask) && (SphP[head].FOF_Done==1))
{
FOFDataResult[target].FOF_Prev = SphP[head].FOF_Prev;
FOFDataResult[target].FOF_CPUPrev = -2; /* this is to keep the trace that the particle was as pseudo head, as its new FOF_CPUHead could be now its own CPU */
FOFDataResult[target].FOF_Head = FOFDataGet[target].Index; /* WARNING : THOSE PARTICLES ARE PSEUDO HEAD THAT LINK TO OTHER CPU THAN THE INITIAL ONE */
FOFDataResult[target].FOF_CPUHead = SphP[head].FOF_CPUHead; /* instead of this ThisTask */
FOFDataResult[target].FOF_Done = 1;
return;
}
printf("we have a problem here !!\n");
endrun(1974);
}
/*! 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 fof_compare_key(const void *a, const void *b)
{
if(((struct FOFdata_in *) a)->Task < (((struct FOFdata_in *) b)->Task))
return -1;
if(((struct FOFdata_in *) a)->Task > (((struct FOFdata_in *) b)->Task))
return +1;
return 0;
}
/*! 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 fof_compare_phdata(const void *a, const void *b)
{
if(((struct fof_phdata *) a)->prev < (((struct fof_phdata *) b)->prev))
return -1;
if(((struct fof_phdata *) a)->prev > (((struct fof_phdata *) b)->prev))
return +1;
return 0;
}
/*! 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 fof_compare_groups_key(const void *a, const void *b)
{
if(((struct fof_groups_data *) a)->Task < (((struct fof_groups_data *) b)->Task))
return -1;
if(((struct fof_groups_data *) a)->Task > (((struct fof_groups_data *) b)->Task))
return +1;
return 0;
}
/*! This is a comparison kernel for a sort routine, which is used to sort
* particles according to some physical quantity.
*/
int fof_compare_particles(const void *a, const void *b)
{
/* if the mass is equal, sort with respect to ID */
if(((struct fof_particles_in *) a)->Mass == (((struct fof_particles_in *) b)->Mass))
{
if(((struct fof_particles_in *) a)->ID < (((struct fof_particles_in *) b)->ID))
return +1;
if(((struct fof_particles_in *) a)->ID > (((struct fof_particles_in *) b)->ID))
return -1;
return 0;
}
else
{
if(((struct fof_particles_in *) a)->Mass < (((struct fof_particles_in *) b)->Mass))
return +1;
if(((struct fof_particles_in *) a)->Mass > (((struct fof_particles_in *) b)->Mass))
return -1;
return 0;
}
}
+/*! This function is used as a comparison kernel in a sort routine. It is
+ * used to group particles in the communication buffer that are going to
+ * be sent to the same CPU.
+ */
+int grav_fof_compare_key(const void *a, const void *b)
+{
+ if(((struct FOFgravdata_index *) a)->Task < (((struct FOFgravdata_index *) b)->Task))
+ return -1;
+
+ if(((struct FOFgravdata_index *) a)->Task > (((struct FOFgravdata_index *) b)->Task))
+ return +1;
+ return 0;
+}
#endif // FOF
diff --git a/src/init.c b/src/init.c
index 3244188..ffa15db 100644
--- a/src/init.c
+++ b/src/init.c
@@ -1,830 +1,832 @@
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <mpi.h>
#include "allvars.h"
#include "proto.h"
/*! \file init.c
* \brief Code for initialisation of a simulation from initial conditions
*/
/*! This function reads the initial conditions, and allocates storage for the
* tree. Various variables of the particle data are initialised and An intial
* domain decomposition is performed. If SPH particles are present, the inial
* SPH smoothing lengths are determined.
*/
void init(void)
{
int i, j;
double a3;
#ifdef SFR
double Mgas=0,sum_Mgas=0;
int nstars=0;
int *numlist;
#ifndef LONGIDS
unsigned int MaxID=0;
#else
unsigned long long MaxID=0;
#endif
#endif
All.Time = All.TimeBegin;
switch (All.ICFormat)
{
case 1:
#if (MAKEGLASS > 1)
seed_glass();
#else
read_ic(All.InitCondFile);
#endif
break;
case 2:
case 3:
read_ic(All.InitCondFile);
break;
default:
if(ThisTask == 0)
printf("ICFormat=%d not supported.\n", All.ICFormat);
endrun(0);
}
All.Time = All.TimeBegin;
All.Ti_Current = 0;
if(All.ComovingIntegrationOn)
{
All.Timebase_interval = (log(All.TimeMax) - log(All.TimeBegin)) / TIMEBASE;
a3 = All.Time * All.Time * All.Time;
}
else
{
All.Timebase_interval = (All.TimeMax - All.TimeBegin) / TIMEBASE;
a3 = 1;
}
if (ThisTask==0)
printf("\nMinimum Time Step (Timebase_interval) = %g \n\n", All.Timebase_interval);
set_softenings();
All.NumCurrentTiStep = 0; /* setup some counters */
#ifndef SET_SNAPSHOT_FILE_COUNT
All.SnapshotFileCount = 0;
#endif
if(RestartFlag == 2)
All.SnapshotFileCount = atoi(All.InitCondFile + strlen(All.InitCondFile) - 3) + 1;
#ifdef FOF
- All.FoF_SnapshotFileCount = 0;
+ All.FoF_SnapshotFileCount_Accepted = 0;
+ All.FoF_SnapshotFileCount_Rejected = 0;
+ All.FoF_IMFSnapshotFileCount = 0;
#endif
All.TotNumOfForces = 0;
All.NumForcesSinceLastDomainDecomp = 0;
if(All.ComovingIntegrationOn)
if(All.PeriodicBoundariesOn == 1)
check_omega();
All.TimeLastStatistics = All.TimeBegin - All.TimeBetStatistics;
#ifdef AGN_ACCRETION
All.TimeLastAccretion = All.TimeBegin - All.TimeBetAccretion;
All.LastMTotInRa = 0;
#endif
#ifdef BONDI_ACCRETION
All.BondiTimeLast = All.TimeBegin - All.BondiTimeBet;
#endif
#ifdef CHIMIE
#ifdef CHIMIE_TIMEBET
All.ChimieTimeLastChimie = All.TimeBegin - All.ChimieTimeBetChimie; /* shoud be change following FoF_TimeLastFoF */
All.ChimieTi_begstep = All.Ti_Current;
#endif
#endif
#ifdef FOF
All.FoF_TimeLastFoF = All.TimeBegin;
#endif
#ifdef BUBBLES
All.EnergyBubbles=0;
#endif
if(All.ComovingIntegrationOn) /* change to new velocity variable */
{
for(i = 0; i < NumPart; i++)
for(j = 0; j < 3; j++)
P[i].Vel[j] *= sqrt(All.Time) * All.Time;
}
for(i = 0; i < NumPart; i++) /* start-up initialization */
{
for(j = 0; j < 3; j++)
P[i].GravAccel[j] = 0;
#ifdef PMGRID
for(j = 0; j < 3; j++)
P[i].GravPM[j] = 0;
#endif
P[i].Ti_endstep = 0;
P[i].Ti_begstep = 0;
P[i].OldAcc = 0;
P[i].GravCost = 1;
P[i].Potential = 0;
#ifdef PARTICLE_FLAG
P[i].Flag = 0;
#endif
#ifdef TESSEL
P[i].iPref = -1; /* index of the reference particle : -1 for normal particles */
#endif
#ifdef VANISHING_PARTICLES
P[i].VanishingFlag=0;
#endif
#ifdef SFR
if (P[i].ID>MaxID)
MaxID=P[i].ID;
#endif
}
#ifdef PMGRID
All.PM_Ti_endstep = All.PM_Ti_begstep = 0;
#endif
#ifdef FLEXSTEPS
All.PresentMinStep = TIMEBASE;
for(i = 0; i < NumPart; i++) /* start-up initialization */
{
P[i].FlexStepGrp = (int) (TIMEBASE * get_random_number(P[i].ID));
}
#endif
for(i = 0; i < N_gas; i++) /* initialize sph_properties */
{
for(j = 0; j < 3; j++)
{
SphP[i].VelPred[j] = P[i].Vel[j];
SphP[i].HydroAccel[j] = 0;
#ifdef DISSIPATION_FORCES
SphP[i].DissipationForcesAccel[j] = 0;
#endif
}
SphP[i].DtEntropy = 0;
#ifdef COOLING
//SphP[i].EntropyRad = 0;
SphP[i].DtEntropyRad = 0;
SphP[i].DtEnergyRad = 0;
#endif
#ifdef DISSIPATION_FORCES
SphP[i].EnergyDissipationForces = 0;
SphP[i].DtEnergyDissipationForces = 0;
#endif
#ifdef STELLAR_FLUX
SphP[i].EnergyFlux = 0.;
#endif
#ifdef AGN_HEATING
SphP[i].EgySpecAGNHeat = 0.;
SphP[i].DtEgySpecAGNHeat = 0.;
#endif
#ifdef MULTIPHASE
#ifdef COUNT_COLLISIONS
SphP[i].StickyCollisionNumber = 0;
#endif
#endif
#ifdef FEEDBACK
SphP[i].EgySpecFeedback = 0.;
SphP[i].DtEgySpecFeedback = 0.;
SphP[i].EnergySN = 0.;
SphP[i].EnergySNrem = 0.;
SphP[i].TimeSN = 0.;
for(j = 0; j < 3; j++)
{
SphP[i].FeedbackVel[j] = 0;
}
#endif
#ifdef FEEDBACK_WIND
for(j = 0; j < 3; j++)
{
SphP[i].FeedbackWindVel[j] = 0;
}
#endif
#if defined(ART_VISCO_MM)|| defined(ART_VISCO_RO) || defined(ART_VISCO_CD)
SphP[i].ArtBulkViscConst = All.ArtBulkViscConstMin;
#ifdef ART_VISCO_CD
SphP[i].ArtBulkViscConst = 0.;
SphP[i].DiVelAccurate = 0.;
SphP[i].DiVelTemp = 0.;
#endif
#endif
#ifdef OUTPUTOPTVAR1
SphP[i].OptVar1 = 0.;
#endif
#ifdef OUTPUTOPTVAR2
SphP[i].OptVar2 = 0.;
#endif
#ifdef COMPUTE_VELOCITY_DISPERSION
for(j = 0; j < VELOCITY_DISPERSION_SIZE; j++)
SphP[i].VelocityDispersion[j] = 0.;
#endif
if(RestartFlag == 0)
{
SphP[i].Hsml = 0;
SphP[i].Density = -1;
}
#ifdef MULTIPHASE
/* here, we set the Phase, according to the SpecificEnergy and not Entropy */
if (SphP[i].Entropy > All.CriticalEgySpec)
SphP[i].Phase = GAS_SPH; /* warmer phase */
else
{
if (SphP[i].Entropy >= All.CriticalNonCollisionalEgySpec)
SphP[i].Phase = GAS_STICKY;
else
SphP[i].Phase = GAS_DARK;
}
SphP[i].StickyFlag = 0;
SphP[i].StickyTime = All.Time;
//SphP[i].StickyTime = All.Time + All.StickyIdleTime*get_random_number(P[i].ID);
#endif
#ifdef SFR
Mgas += P[i].Mass;
#endif
}
#ifdef SFR
#ifndef LONGIDS
MPI_Allreduce(&MaxID, &All.MaxID, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD);
#else
printf("MPI_Allreduce must be adapted...\n");
endrun(-77);
#endif
All.MaxID++;
RearrangeParticlesFlag=0;
if (All.StarFormationStarMass==0)
{
/* compute the mean gas mass */
MPI_Allreduce(&Mgas, &sum_Mgas, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
All.StarFormationStarMass = (sum_Mgas/All.TotN_gas) / All.StarFormationNStarsFromGas;
}
for(i = 0; i < NumPart; i++) /* initialize st_properties */
{
if (P[i].Type==ST)
nstars++;
#ifdef STELLAR_PROP
if (P[i].Type==ST)
{
if (RestartFlag==0) /* only if starting from scratch */
{
#ifndef CHIMIE_INPUT_ALL
P[i].StPIdx = i-N_gas;
StP[P[i].StPIdx].FormationTime = 0; /* bad */
StP[P[i].StPIdx].InitialMass = P[i].Mass; /* bad */
StP[P[i].StPIdx].IDProj = P[i].ID;
StP[P[i].StPIdx].Hsml = 0;
StP[P[i].StPIdx].Density = -1;
for(j = 0; j < NELEMENTS; j++)
StP[P[i].StPIdx].Metal[j] = 0.;
StP[P[i].StPIdx].Flag = 0; /*obsolete*/
#else /* here, we restart for a file already processed by gadget */
P[i].StPIdx = i-N_gas;
StP[P[i].StPIdx].Flag = 0; /*obsolete*/
#endif /* CHIMIE_INPUT_ALL */
}
if (RestartFlag==2) /* start from snapshot */
{
P[i].StPIdx = i-N_gas;
StP[P[i].StPIdx].Flag = 0; /*obsolete*/
}
StP[P[i].StPIdx].PIdx = i;
#ifdef CHECK_ID_CORRESPONDENCE
StP[P[i].StPIdx].ID = P[i].ID;
#endif
}
//else
// P[i].StPIdx = -1; /* shoud be set, however, may be a problem in domain.c --> must be corrected */
#endif // STELLAR_PROP
#ifdef CHIMIE
if (P[i].Type==0)
{
if (RestartFlag==0 && header.flag_metals==0) /* only if starting from scratch and metal block not present */
{
for(j = 0; j < NELEMENTS; j++)
{
#ifdef CHIMIE_SMOOTH_METALS
SphP[i].MassMetal[j] = (pow(10,All.InitGasMetallicity)-1e-10)*get_SolarMassAbundance(j);
#else
SphP[i].Metal[j] = (pow(10,All.InitGasMetallicity)-1e-10)*get_SolarMassAbundance(j);
#endif
//if (j==FE)
// SphP[i].Metal[j] = (pow(10,All.InitGasMetallicity)-1e-10)*All.CoolingParameters_FeHSolar;
//else
// SphP[i].Metal[j] = 0;
}
}
if (RestartFlag==2)
{
if(SphP[i].Metal[0] == 0)
{
for(j = 0; j < NELEMENTS; j++)
{
#ifdef CHIMIE_SMOOTH_METALS
SphP[i].MassMetal[j] = (pow(10,All.InitGasMetallicity)-1e-10)*get_SolarMassAbundance(j);
#else
SphP[i].Metal[j] = (pow(10,All.InitGasMetallicity)-1e-10)*get_SolarMassAbundance(j);
#endif
}
}
else
{
#ifdef CHIMIE_SMOOTH_METALS
for(j = 0; j < NELEMENTS; j++)
{
SphP[i].MassMetal[j] = SphP[i].Metal[j];
}
#endif
}
}
#ifdef CHIMIE_SMOOTH_METALS
if (RestartFlag==0 && header.flag_metals>0)
for(j = 0; j < NELEMENTS; j++)
SphP[i].MassMetal[j] = SphP[i].Metal[j];
#endif
#ifdef CHIMIE_THERMAL_FEEDBACK
SphP[i].DeltaEgySpec = 0;
SphP[i].NumberOfSNIa = 0;
SphP[i].NumberOfSNII = 0;
if (RestartFlag==0 || header.flag_supernova_thermaltime!=1) /* only if starting from scratch and sn block not present */
{
SphP[i].SNIIThermalTime = -1;
SphP[i].SNIaThermalTime = -2;
}
else
{
/* do nothing */
}
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
SphP[i].WindTime = All.TimeBegin-2*All.ChimieWindTime;
SphP[i].WindFlag = 0;
#endif
}
#endif /* CHIMIE */
#ifdef COOLING
#ifndef CHIMIE
All.GasMetal = (pow(10,All.InitGasMetallicity)-1e-10)*All.CoolingParameters_FeHSolar;
#endif /* CHIMIE*/
#endif /* COOLING */
#ifdef TIMESTEP_UPDATE_FOR_FEEDBACK
if (P[i].Type==0)
{
for (j=0;j<3;j++)
SphP[i].FeedbackUpdatedAccel[j] = 0;
}
#endif
}
#ifdef CHECK_ID_CORRESPONDENCE
#ifdef CHIMIE
for(i = N_gas; i < N_gas+N_stars; i++)
{
if( StP[P[i].StPIdx].PIdx != i )
{
printf("\nP/StP correspondance error\n");
printf("(%d) (in domain before) N_stars=%d N_gas=%d i=%d id=%d P[i].StPIdx=%d StP[P[i].StPIdx].PIdx=%d\n\n",ThisTask,N_stars,N_gas,i,P[i].ID,P[i].StPIdx,StP[P[i].StPIdx].PIdx);
endrun(333001);
}
if(StP[P[i].StPIdx].ID != P[i].ID)
{
printf("\nP/StP correspondance error\n");
printf("(%d) (in domain before) N_gas=%d N_stars=%d i=%d Type=%d P.Id=%d P[i].StPIdx=%d StP[P[i].StPIdx].ID=%d \n\n",ThisTask,N_gas,N_stars,i,P[i].Type,P[i].ID, P[i].StPIdx, StP[P[i].StPIdx].ID);
endrun(333002);
}
}
if (ThisTask==0)
printf("Check id correspondence before decomposition done...\n");
#endif // CHIMIE
#endif // CHECK_ID_CORRESPONDENCE
/* here, we would like to reduce N_stars to TotN_stars */
/* MPI_Allreduce(&N_stars, &All.TotN_stars, 1, MPI_LONG_LONG, MPI_SUM, MPI_COMM_WORLD); does not works */
numlist = malloc(NTask * sizeof(int) * NTask);
MPI_Allgather(&N_stars, 1, MPI_INT, numlist, 1, MPI_INT, MPI_COMM_WORLD);
for(i = 0, All.TotN_stars = 0; i < NTask; i++)
All.TotN_stars += numlist[i];
free(numlist);
if(ThisTask == 0)
{
printf("Total number of star particles : %d%09d\n\n",(int) (All.TotN_stars / 1000000000), (int) (All.TotN_stars % 1000000000));
fflush(stdout);
}
#endif /*SFR*/
ngb_treeallocate(MAX_NGB);
force_treeallocate(All.TreeAllocFactor * All.MaxPart, All.MaxPart);
All.NumForcesSinceLastDomainDecomp = 1 + All.TotNumPart * All.TreeDomainUpdateFrequency;
Flag_FullStep = 1; /* to ensure that Peano-Hilber order is done */
domain_Decomposition(); /* do initial domain decomposition (gives equal numbers of particles) */
ngb_treebuild(); /* will build tree */
setup_smoothinglengths();
#ifdef CHIMIE
#ifndef CHIMIE_INPUT_ALL
stars_setup_smoothinglengths();
#endif
#endif
#ifdef TESSEL
setup_searching_radius();
#endif
TreeReconstructFlag = 1;
/* at this point, the entropy variable normally contains the
* internal energy, read in from the initial conditions file, unless the file
* explicitly signals that the initial conditions contain the entropy directly.
* Once the density has been computed, we can convert thermal energy to entropy.
*/
#ifndef DENSITY_INDEPENDENT_SPH /* in this case, entropy is correctely defined in setup_smoothinglengths */
#ifndef ISOTHERM_EQS
if(header.flag_entropy_instead_u == 0)
{
for(i = 0; i < N_gas; i++)
{
#ifdef MULTIPHASE
{
switch(SphP[i].Phase)
{
case GAS_SPH:
SphP[i].Entropy = GAMMA_MINUS1 * SphP[i].Entropy / pow(SphP[i].Density / a3, GAMMA_MINUS1);
break;
case GAS_STICKY:
break;
case GAS_DARK:
SphP[i].Entropy = -SphP[i].Entropy;
break;
}
}
#else
SphP[i].Entropy = GAMMA_MINUS1 * SphP[i].Entropy / pow(SphP[i].Density / a3, GAMMA_MINUS1);
#endif
}
}
#endif
#endif /* DENSITY_INDEPENDENT_SPH */
#ifdef ENTROPYPRED
for(i = 0; i < N_gas; i++)
SphP[i].EntropyPred = SphP[i].Entropy;
#endif
#ifdef TRACE_ACC
trace_pos();
#endif
}
/*! This routine computes the mass content of the box and compares it to the
* specified value of Omega-matter. If discrepant, the run is terminated.
*/
void check_omega(void)
{
double mass = 0, masstot, omega;
int i;
for(i = 0; i < NumPart; i++)
mass += P[i].Mass;
MPI_Allreduce(&mass, &masstot, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
omega =
masstot / (All.BoxSize * All.BoxSize * All.BoxSize) / (3 * All.Hubble * All.Hubble / (8 * M_PI * All.G));
if(fabs(omega - All.Omega0) > 1.0e-3)
{
if(ThisTask == 0)
{
printf("\n\nI've found something odd!\n");
printf
("The mass content accounts only for Omega=%g,\nbut you specified Omega=%g in the parameterfile.\n",
omega, All.Omega0);
printf("\nI better stop.\n");
fflush(stdout);
}
endrun(1);
}
}
/*! This function is used to find an initial smoothing length for each SPH
* particle. It guarantees that the number of neighbours will be between
* desired_ngb-MAXDEV and desired_ngb+MAXDEV. For simplicity, a first guess
* of the smoothing length is provided to the function density(), which will
* then iterate if needed to find the right smoothing length.
*/
void setup_smoothinglengths(void)
{
int i, j, no, p;
double a3;
if(All.ComovingIntegrationOn)
{
a3 = All.Time * All.Time * All.Time;
}
else
{
a3 = 1;
}
if(RestartFlag == 0 || RestartFlag == 2)
{
for(i = 0; i < N_gas; i++)
{
no = Father[i];
while(10 * All.DesNumNgb * P[i].Mass > Nodes[no].u.d.mass)
{
p = Nodes[no].u.d.father;
if(p < 0)
break;
no = p;
}
#ifndef TWODIMS
SphP[i].Hsml =
pow(3.0 / (4 * M_PI) * All.DesNumNgb * P[i].Mass / Nodes[no].u.d.mass, 1.0 / 3) * Nodes[no].len;
#else
SphP[i].Hsml =
pow(1.0 / (M_PI) * All.DesNumNgb * P[i].Mass / Nodes[no].u.d.mass, 1.0 / 2) * Nodes[no].len;
#endif
}
}
#ifdef DENSITY_INDEPENDENT_SPH
/* initialization of the entropy variable is a little trickier in this version of SPH,
since we need to make sure it 'talks to' the density appropriately */
for(i = 0; i < N_gas; i++)
SphP[i].EntVarPred = pow(SphP[i].Entropy,1/GAMMA);
#endif
density(0);
#ifdef DENSITY_INDEPENDENT_SPH
if(header.flag_entropy_instead_u == 0)
{
for(j=0;j<5;j++)
{ /* since ICs give energies, not entropies, need to iterate get this initialized correctly */
for(i = 0; i < N_gas; i++)
SphP[i].EntVarPred = pow( GAMMA_MINUS1 * SphP[i].Entropy / pow(SphP[i].EgyWtDensity/a3 , GAMMA_MINUS1) ,1/GAMMA);
density(0);
}
/* convert energy into entropy */
for(i = 0; i < N_gas; i++)
SphP[i].Entropy = GAMMA_MINUS1 * SphP[i].Entropy / pow(SphP[i].EgyWtDensity/a3 , GAMMA_MINUS1);
}
#endif
}
#ifdef CHIMIE
/*! This function is used to find an initial smoothing length for each SPH
* particle. It guarantees that the number of neighbours will be between
* desired_ngb-MAXDEV and desired_ngb+MAXDEV. For simplicity, a first guess
* of the smoothing length is provided to the function density(), which will
* then iterate if needed to find the right smoothing length.
*/
void stars_setup_smoothinglengths(void)
{
int i, no, p;
if(RestartFlag == 0 || RestartFlag == 2)
{
for(i = 0; i < NumPart; i++)
{
if(P[i].Type == ST)
{
no = Father[i];
while(10 * All.DesNumNgb * P[i].Mass > Nodes[no].u.d.mass)
{
p = Nodes[no].u.d.father;
if(p < 0)
break;
no = p;
}
#ifndef TWODIMS
StP[P[i].StPIdx].Hsml =
pow(3.0 / (4 * M_PI) * All.DesNumNgb * P[i].Mass / Nodes[no].u.d.mass, 1.0 / 3) * Nodes[no].len;
#else
StP[P[i].StPIdx].Hsml =
pow(1.0 / (M_PI) * All.DesNumNgb * P[i].Mass / Nodes[no].u.d.mass, 1.0 / 2) * Nodes[no].len;
#endif
}
}
}
stars_density();
}
#endif
/*! If the code is run in glass-making mode, this function populates the
* simulation box with a Poisson sample of particles.
*/
#if (MAKEGLASS > 1)
void seed_glass(void)
{
int i, k, n_for_this_task;
double Range[3], LowerBound[3];
double drandom, partmass;
long long IDstart;
All.TotNumPart = MAKEGLASS;
partmass = All.Omega0 * (3 * All.Hubble * All.Hubble / (8 * M_PI * All.G))
* (All.BoxSize * All.BoxSize * All.BoxSize) / All.TotNumPart;
All.MaxPart = All.PartAllocFactor * (All.TotNumPart / NTask); /* sets the maximum number of particles that may */
allocate_memory();
header.npartTotal[1] = All.TotNumPart;
header.mass[1] = partmass;
if(ThisTask == 0)
{
printf("\nGlass initialising\nPartMass= %g\n", partmass);
printf("TotNumPart= %d%09d\n\n",
(int) (All.TotNumPart / 1000000000), (int) (All.TotNumPart % 1000000000));
}
/* set the number of particles assigned locally to this task */
n_for_this_task = All.TotNumPart / NTask;
if(ThisTask == NTask - 1)
n_for_this_task = All.TotNumPart - (NTask - 1) * n_for_this_task;
NumPart = 0;
IDstart = 1 + (All.TotNumPart / NTask) * ThisTask;
/* split the temporal domain into Ntask slabs in z-direction */
Range[0] = Range[1] = All.BoxSize;
Range[2] = All.BoxSize / NTask;
LowerBound[0] = LowerBound[1] = 0;
LowerBound[2] = ThisTask * Range[2];
srand48(ThisTask);
for(i = 0; i < n_for_this_task; i++)
{
for(k = 0; k < 3; k++)
{
drandom = drand48();
P[i].Pos[k] = LowerBound[k] + Range[k] * drandom;
P[i].Vel[k] = 0;
}
P[i].Mass = partmass;
P[i].Type = 1;
P[i].ID = IDstart + i;
NumPart++;
}
}
#endif
diff --git a/src/proto.h b/src/proto.h
index f802e3b..42eae97 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -1,776 +1,782 @@
/*! \file proto.h
* \brief this file contains all function prototypes of the code
*/
#ifndef ALLVARS_H
#include "allvars.h"
#endif
#ifdef HAVE_HDF5
#include <hdf5.h>
#endif
#ifdef COOLING_FCT_FROM_HDF5
#include <hdf5.h>
#endif
void advance_and_find_timesteps(void);
void allocate_commbuffers(void);
void allocate_memory(void);
void begrun(void);
int blockpresent(enum iofields blocknr);
#ifdef BLOCK_SKIPPING
int blockabsent(enum iofields blocknr);
#endif
void catch_abort(int sig);
void catch_fatal(int sig);
void check_omega(void);
void close_outputfiles(void);
int compare_key(const void *a, const void *b);
void compute_accelerations(int mode);
void compute_global_quantities_of_system(void);
void compute_potential(void);
int dens_compare_key(const void *a, const void *b);
void density(int mode);
void density_decouple(void);
void density_evaluate(int i, int mode);
#ifdef CHIMIE
int stars_dens_compare_key(const void *a, const void *b);
void stars_density(void);
void stars_density_evaluate(int i, int mode);
#endif
void distribute_file(int nfiles, int firstfile, int firsttask, int lasttask, int *filenr, int *master, int *last);
double dmax(double, double);
double dmin(double, double);
void do_box_wrapping(void);
void domain_Decomposition(void);
int domain_compare_key(const void *a, const void *b);
int domain_compare_key(const void *a, const void *b);
int domain_compare_toplist(const void *a, const void *b);
void domain_countToGo(void);
void domain_decompose(void);
void domain_determineTopTree(void);
void domain_exchangeParticles(int partner, int sphflag, int send_count, int recv_count);
void domain_findExchangeNumbers(int task, int partner, int sphflag, int *send, int *recv);
void domain_findExtent(void);
int domain_findSplit(int cpustart, int ncpu, int first, int last);
int domain_findSplityr(int cpustart, int ncpu, int first, int last);
void domain_shiftSplit(void);
void domain_shiftSplityr(void);
void domain_sumCost(void);
void domain_topsplit(int node, peanokey startkey);
void domain_topsplit_local(int node, peanokey startkey);
double drift_integ(double a, void *param);
void dump_particles(void);
void empty_read_buffer(enum iofields blocknr, int offset, int pc, int type);
void endrun(int);
void energy_statistics(void);
#ifdef ADVANCEDSTATISTICS
void advanced_energy_statistics(void);
#endif
void every_timestep_stuff(void);
void ewald_corr(double dx, double dy, double dz, double *fper);
void ewald_force(int ii, int jj, int kk, double x[3], double force[3]);
void ewald_init(void);
double ewald_pot_corr(double dx, double dy, double dz);
double ewald_psi(double x[3]);
void fill_Tab_IO_Labels(void);
void fill_write_buffer(enum iofields blocknr, int *pindex, int pc, int type);
void find_dt_displacement_constraint(double hfac);
int find_files(char *fname);
int find_next_outputtime(int time);
void find_next_sync_point_and_drift(void);
void force_create_empty_nodes(int no, int topnode, int bits, int x, int y, int z, int *nodecount, int *nextfree);
void force_exchange_pseudodata(void);
void force_flag_localnodes(void);
void force_insert_pseudo_particles(void);
void force_setupnonrecursive(int no);
void force_treeallocate(int maxnodes, int maxpart);
int force_treebuild(int npart);
int force_treebuild_single(int npart);
int force_treeevaluate(int target, int mode, double *ewaldcountsum);
int force_treeevaluate_direct(int target, int mode);
int force_treeevaluate_ewald_correction(int target, int mode, double pos_x, double pos_y, double pos_z, double aold);
void force_treeevaluate_potential(int target, int type);
void force_treeevaluate_potential_shortrange(int target, int mode);
int force_treeevaluate_shortrange(int target, int mode);
void force_treefree(void);
void force_treeupdate_pseudos(void);
void force_update_hmax(void);
void force_update_len(void);
void force_update_node(int no, int flag);
void force_update_node_hmax_local(void);
void force_update_node_hmax_toptree(void);
void force_update_node_len_local(void);
void force_update_node_len_toptree(void);
void force_update_node_recursive(int no, int sib, int father);
void force_update_pseudoparticles(void);
void force_update_size_of_parent_node(int no);
void free_memory(void);
int get_bytes_per_blockelement(enum iofields blocknr);
void get_dataset_name(enum iofields blocknr, char *buf);
int get_datatype_in_block(enum iofields blocknr);
double get_drift_factor(int time0, int time1);
double get_gravkick_factor(int time0, int time1);
double get_hydrokick_factor(int time0, int time1);
int get_particles_in_block(enum iofields blocknr, int *typelist);
double get_random_number(int id);
#ifdef SFR
double get_StarFormation_random_number(int id);
#endif
#ifdef FEEDBACK_WIND
double get_FeedbackWind_random_number(int id);
#endif
#ifdef CHIMIE
double get_Chimie_random_number(int id);
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
double get_ChimieKineticFeedback_random_number(int id);
#endif
#ifdef GAS_ACCRETION
double get_gasAccretion_random_number(int id);
void update_entropy_for_accreated_particles(void);
void allocate_gas_accretion(void);
#endif
#ifdef HOT_HALO
void Halo_order_particles_using_mass(void);
void Halo_reorder_particles_using_mass(void);
void allocate_accretion(void);
void init_accretion(void);
#endif
#ifdef TRACE_ACC
void trace_pos(void);
int pot_ind_compare_key(const void *a, const void *b);
int pot_tasks_compare_key(const void *a, const void *b);
#endif
#if defined(VANISHING_PARTICLES)|| defined(MERGE_SPLIT)
void vanishing_particles_remove(void);
int compact_StP(int oldN_stars);
#endif
#ifdef VANISHING_PARTICLES
void vanishing_particles(int time0, int time1);
void vanishing_particles_flag(int time0, int time1);
#endif
int get_timestep(int p, double *a, int flag);
int get_values_per_blockelement(enum iofields blocknr);
#ifdef SYNCHRONIZE_NGB_TIMESTEP
void synchronize_ngb_timestep();
int synchronize_ngb_timestep_evaluate(int target, int mode);
int synchronize_ngb_timestep_compare_key(const void *a, const void *b);
#endif
int grav_tree_compare_key(const void *a, const void *b);
void gravity_forcetest(void);
void gravity_tree(void);
void gravity_tree_shortrange(void);
double gravkick_integ(double a, void *param);
int hydro_compare_key(const void *a, const void *b);
void hydro_evaluate(int target, int mode);
void hydro_force(void);
double hydrokick_integ(double a, void *param);
int imax(int, int);
int imin(int, int);
void init(void);
void init_drift_table(void);
void init_peano_map(void);
#ifdef COSMICTIME
void init_cosmictime_table(void);
double get_cosmictime_difference(int time0, int time1);
void init_full_cosmictime_table(void);
double get_da_from_dt(double a, double dt);
double get_dt_from_da(double a, double da);
double get_CosmicTime_from_a(double a);
double get_a_from_CosmicTime(double t);
double get_Redshift_from_a(double a);
double get_a_from_Redshift(double z);
#endif
void long_range_force(void);
void long_range_init(void);
void long_range_init_regionsize(void);
void move_particles(int time0, int time1);
size_t my_fread(void *ptr, size_t size, size_t nmemb, FILE * stream);
size_t my_fwrite(void *ptr, size_t size, size_t nmemb, FILE * stream);
int ngb_clear_buf(FLOAT searchcenter[3], FLOAT hguess, int numngb);
void ngb_treeallocate(int npart);
void ngb_treebuild(void);
int ngb_treefind_pairs(FLOAT searchcenter[3], FLOAT hsml, int phase, int *startnode);
#ifdef MULTIPHASE
int ngb_treefind_phase_pairs(FLOAT searchcenter[3], FLOAT hsml, int phase, int *startnode);
int ngb_treefind_sticky_collisions(FLOAT searchcenter[3], FLOAT hguess, int phase, int *startnode);
#endif
int ngb_treefind_variable(FLOAT searchcenter[3], FLOAT hguess, int phase, int *startnode);
#ifdef CHIMIE
int ngb_treefind_variable_for_chimie(FLOAT searchcenter[3], FLOAT hguess, int *startnode);
#endif
void ngb_treefree(void);
void ngb_treesearch(int);
void ngb_treesearch_pairs(int);
void ngb_update_nodes(void);
void open_outputfiles(void);
peanokey peano_hilbert_key(int x, int y, int z, int bits);
void peano_hilbert_order(void);
void pm_init_nonperiodic(void);
void pm_init_nonperiodic_allocate(int dimprod);
void pm_init_nonperiodic_free(void);
void pm_init_periodic(void);
void pm_init_periodic_allocate(int dimprod);
void pm_init_periodic_free(void);
void pm_init_regionsize(void);
void pm_setup_nonperiodic_kernel(void);
int pmforce_nonperiodic(int grnr);
void pmforce_periodic(void);
int pmpotential_nonperiodic(int grnr);
void pmpotential_periodic(void);
double pow(double, double); /* on some old DEC Alphas, the correct prototype for pow() is missing, even when math.h is included */
void read_file(char *fname, int readTask, int lastTask);
void read_header_attributes_in_hdf5(char *fname);
void read_ic(char *fname);
int read_outputlist(char *fname);
void read_parameter_file(char *fname);
void readjust_timebase(double TimeMax_old, double TimeMax_new);
void reorder_gas(void);
void reorder_particles(void);
#ifdef STELLAR_PROP
void reorder_stars(void);
void reorder_st(void);
#endif
void restart(int mod);
void run(void);
void savepositions(int num);
double second(void);
void seed_glass(void);
void set_random_numbers(void);
void set_softenings(void);
void set_units(void);
void init_local_sys_state(void);
void setup_smoothinglengths(void);
#ifdef CHIMIE
void stars_setup_smoothinglengths(void);
#endif
void statistics(void);
void terminate_processes(void);
double timediff(double t0, double t1);
#ifdef HAVE_HDF5
void write_header_attributes_in_hdf5(hid_t handle);
#endif
void write_file(char *fname, int readTask, int lastTask);
void write_pid_file(void);
#ifdef COOLING
int init_cooling(FLOAT metallicity);
int init_cooling_with_metals();
double cooling_function(double temperature);
double cooling_function_with_metals(double temperature,double metal);
void init_from_new_redshift(double Redshift);
double J_0();
double J_nu(double e);
double sigma_rad_HI(double e);
double sigma_rad_HeI(double e);
double sigma_rad_HeII(double e);
double cooling_bremstrahlung_HI(double T);
double cooling_bremstrahlung_HeI(double T);
double cooling_bremstrahlung_HeII(double T);
double cooling_ionization_HI(double T);
double cooling_ionization_HeI(double T);
double cooling_ionization_HeII(double T);
double cooling_recombination_HI(double T);
double cooling_recombination_HeI(double T);
double cooling_recombination_HeII(double T);
double cooling_dielectric_recombination(double T);
double cooling_excitation_HI(double T);
double cooling_excitation_HII(double T);
double cooling_compton(double T);
double A_HII(double T);
double A_HeIId(double T);
double A_HeII(double T);
double A_HeIII(double T);
double G_HI(double T);
double G_HeI(double T);
double G_HeII(double T);
double G_gHI();
double G_gHeI();
double G_gHeII();
double G_gHI_t(double J0);
double G_gHeI_t(double J0);
double G_gHeII_t(double J0);
double G_gHI_w();
double G_gHeI_w();
double G_gHeII_w();
double heating_radiative_HI();
double heating_radiative_HeI();
double heating_radiative_HeII();
double heating_radiative_HI_t(double J0);
double heating_radiative_HeI_t(double J0);
double heating_radiative_HeII_t(double J0);
double heating_radiative_HI_w();
double heating_radiative_HeI_w();
double heating_radiative_HeII_w();
double heating_compton();
void print_cooling(double T,double c1,double c2,double c3,double c4,double c5,double c6,double c7,double c8,double c9,double c10,double c11,double c12,double c13,double h1, double h2, double h3, double h4);
void compute_densities(double T,double X,double* n_H, double* n_HI,double* n_HII,double* n_HEI,double* n_HEII,double* n_HEIII,double* n_E,double* mu);
void compute_cooling_from_T_and_Nh(double T,double X,double n_H,double *c1,double *c2,double *c3,double *c4,double *c5,double *c6,double *c7,double *c8,double *c9,double *c10,double *c11,double *c12,double *c13,double *h1, double *h2, double *h3, double *h4);
double compute_cooling_from_Egyspec_and_Density(double Egyspec,double Density, double *MeanWeight);
double DoCooling(FLOAT Density,FLOAT Entropy,int Phase,int i,FLOAT DtEntropyVisc, double dt, double hubble_a);
void CoolingForOne(int i,int t0,int t1,int ti_step,double dt_entr3,double a3inv,double hubble_a);
void cooling();
double lambda(FLOAT density,FLOAT egyspec,FLOAT Metal, int phase, int i);
#endif
#ifdef HEATING
void heating();
double gamma_fct(FLOAT Density,FLOAT Entropy,int i);
#endif
#ifdef AGN_HEATING
void agn_heating();
double gamma_fct(FLOAT density,double r, double SpecPower);
double HeatingRadialDependency(double r);
#endif
#ifdef MULTIPHASE
void update_phase(void);
void init_sticky(void);
void sticky(void);
void sticky_compute_energy_kin(int mode);
void sticky_collisions(void);
void sticky_collisions2(int loop);
void sticky_evaluate(int target, int mode, int loop);
int sticky_compare_key(const void *a, const void *b);
#endif
#ifdef FEEDBACK_WIND
void feedbackwind_compute_energy_kin(int mode);
#endif
#ifdef CHIMIE
void init_chimie(void);
void check_chimie(void);
void chimie(void);
void do_chimie(void);
void set_table(int i);
void chimie_evaluate(int target, int mode);
int chimie_compare_key(const void *a, const void *b);
int get_nelts();
char* get_Element(int i);
float get_SolarMassAbundance(int i);
#if defined(CHIMIE_THERMAL_FEEDBACK) && defined(CHIMIE_COMPUTE_THERMAL_FEEDBACK_ENERGY)
void chimie_compute_energy_int(int mode);
#endif
#if defined(CHIMIE_KINETIC_FEEDBACK) && defined(CHIMIE_COMPUTE_KINETIC_FEEDBACK_ENERGY)
void chimie_compute_energy_kin(int mode);
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
void chimie_apply_wind(void);
#endif
#ifdef CHIMIE_OPTIMAL_SAMPLING
double init_optimal_imf_sampling(int i);
double optimal_get_next_mass(double m);
double optimal_get_next_mass_for_one_particle(int j);
double optimal_get_m1_from_m2(double m2, double mp);
double optimal_init_norm(double Mecl);
int optimal_stop_loop(double m);
float optimal_get_k_normalisation_factor();
#endif
#endif
#ifdef DISSIPATION_FORCES
void dissipation_forces(void);
int dissipation_forces_compare_key(const void *a, const void *b);
void dissipation_forces_evaluate(int target, int mode);
#endif
#ifdef INTEGRAL_CONSERVING_DISSIPATION
void icd_set_LocalDissipationOn(void);
void icd_set_LocalDissipationOff(void);
void icd_set_des_nngb(int n);
void icd_set_xc(double x[3]);
void integral_conserving_dissipation(void);
void global_ic_dissipation_m1(void);
void local_ic_dissipation_m1(void);
int set_dissipation_list(void);
void set_dissipation_center(void);
void compute_integrals_m1(void);
void compute_alpha_m1(void);
void apply_transformation_m1(void);
void compute_energy_kin(void);
double get_Total_Gas_energy_kin(void);
double get_Gas_energy_kin(void);
void icd_find_ngbs(void);
double icd_get_alpha(void);
double icd_get_M(void);
double icd_get_X(double x[3]);
double icd_get_V(double v[3]);
double icd_get_T(void);
double icd_get_I(void);
double icd_get_J(void);
double icd_get_DeltaTmin(void);
int setup_integral_conserving_dissipation_local(int flag,int n,double x[3]);
int compare_icd_key(const void *a, const void *b);
void icd_allocate_numlist(void);
void icd_free_numlist(void);
#endif
#ifdef OUTERPOTENTIAL
void init_outer_potential(void);
void outer_forces(void);
void outer_potential(void);
void forces_potentials(FLOAT pos[3], FLOAT vel[3], FLOAT acc[3]);
void potential_components(FLOAT pos[3], FLOAT Phi[1]);
#ifdef NFW
void init_outer_potential_nfw(void);
void outer_forces_nfw(FLOAT pos[3], FLOAT acc[3]);
void outer_potential_nfw(FLOAT pos[3], FLOAT Phi[1]);
#endif
#ifdef MIYAMOTONAGAI
void init_outer_potential_miyamotonagai(void);
void outer_forces_miyamotonagai(FLOAT pos[3], FLOAT acc[3]);
void outer_potential_miyamotonagai(FLOAT pos[3], FLOAT Phi[1]);
#endif
#ifdef PLUMMER
void init_outer_potential_plummer(void);
void outer_forces_plummer(FLOAT pos[3], FLOAT acc[3]);
void outer_potential_plummer(FLOAT pos[3], FLOAT Phi[1]);
#endif
#ifdef PISOTHERM
void init_outer_potential_pisotherm(void);
void outer_forces_pisotherm(FLOAT pos[3], FLOAT acc[3]);
void outer_potential_pisotherm(FLOAT pos[3], FLOAT Phi[1]);
double potential_f(double r, void * params);
double get_potential(double r);
#endif
#ifdef EVOLVE_POT
void init_outer_potential_evolve(void);
int NumVars(int pottype);
void adapt_evolve_variables(int pottype, double *vars, int nlines);
void interp_evolve_vals(void);
void outer_potential_evolve(FLOAT pos[3], FLOAT Phi[1]);
void outer_forces_evolve(FLOAT pos[3], FLOAT acc[3]);
#endif
#ifdef PERIODICOUTER
void forces_rotating(FLOAT pos[3], FLOAT vel[3], FLOAT acc[3], FLOAT RotAng[4], FLOAT RotAcc[3]);
void move_tracer(double dt);//int time0, int time1);
void kick_tracer(double dt);
void update_tracequat(double dt);
void fictitious_forces(void);
void update_traceacc(void);
void update_tracepotential(void);
void update_rotang(void);
void inertialv(void);
void init_quat(void);
#endif
#if defined(PERIODICOUTER) || defined(MERGE_SPLIT)
double *quatproduct(double z[4], double x[4], double y[4]);
double *quatconj(double y[4], double x[4]);
double *quatrot(double z[4], double x[4], double y[4]);
#endif
#ifdef HOT_HALO
void halo_creation(void);
void halo_creation_time(double dt);
FLOAT num_gas_created(FLOAT dt);
FLOAT halo_dens(void);
void update_entropy_for_accreted_particles(void);
double get_Halo_random_number(int id);
double *angcorrection(FLOAT pos[3], double vel[3]);
#endif
#endif
#ifdef SFR
void star_formation(void);
void rearrange_particle_sequence(void);
void sfr_compute_energy_int(int mode);
void sfr_check_number_of_stars(int mode);
#endif
#ifdef AGN_ACCRETION
void compute_agn_accretion(void);
#endif
#ifdef BUBBLES
void init_bubble(void);
void make_bubble(void);
void create_bubble(int sign);
#endif
#ifdef BONDI_ACCRETION
void bondi_accretion(void);
#endif
#ifdef PNBODY
void init_pnbody();
void finalize_pnbody();
void compute_pnbody();
#endif
#ifdef AB_TURB
void init_turb();
#endif
double artificial_viscosity(double r,double vdotr2,double soundspeed_i,double soundspeed_j,double dwk_i,double dwk_j,int timestep,int j,FLOAT mass,FLOAT rho,FLOAT f1,double *maxSignalVel);
#if defined(ART_VISCO_MM)|| defined(ART_VISCO_RO)
double artificial_viscosity_improved(double r,double vdotr2,double soundspeed_i,double soundspeed_j,double dwk_i,double dwk_j,double h_i,double alpha_i,int timestep,int j,FLOAT mass,FLOAT rho,FLOAT f1,double *maxSignalVel);
#endif
#if defined(ART_VISCO_CD)
double artificial_viscosity_CD(double r,double vdotr2,double soundspeed_i,double soundspeed_j,double dwk_i,double dwk_j,int timestep,int j,FLOAT mass,FLOAT rho,FLOAT f1,double *maxSignalVel);
double artificial_viscosity_CD_prediction(double r,double vdotr2,double soundspeed_i,double soundspeed_j,double dwk_i,double dwk_j,int timestep,int j,FLOAT mass,FLOAT rho,FLOAT f1,double *maxSignalVel);
#endif
#if defined(ART_VISCO_MM)|| defined(ART_VISCO_RO) || defined(ART_VISCO_CD)
void move_art_visc(int i,double dt_drift);
#ifdef ART_VISCO_CD
void art_visc_allocate();
void art_visc_free();
void compute_art_visc(int i);
#endif
#endif
#ifdef TIMESTEP_UPDATE_FOR_FEEDBACK
FLOAT updated_pressure(FLOAT EntropyPred,FLOAT Density,FLOAT DeltaEgySpec);
FLOAT updated_pressure_hydra(FLOAT EntropyPred,FLOAT Density,FLOAT DeltaEgySpec);
void make_particle_active(int target);
void kickback(int i,int tstart,int tend);
#endif
#ifdef GAS_ACCRETION
void init_gas_accretion(void);
void gas_accretion(void);
#endif
#ifdef COOLING_FCT_FROM_HDF5
float computeLambda(float rho_H_in, float T_in, float nHe_in, float metalicity);
int endsWith(const char *str, const char *suffix);
void closestMatch1D(float* TABLE, int SIZE, float input, float match[2], int index[2]);
void checkRedshiftForUpdate();
int updateCoolingTable();
void loadDataInTable1D(hid_t table, char* table_key, float** TABLE, int* SIZE);
void loadDataInTable2D(hid_t table, char* table_key, float*** TABLE);
void loadDataInTable3D(hid_t table, char* table_key, float**** TABLE);
void BroadcastTablesToAllFromMaster();
int freeMemory();
#endif
#ifdef COOLING_WIERSMA
int InitWiersmaCooling(char * TablesDirectory);
int setTablesFromRedshift(double RedShift);
double compute_LambdaTotal(double T,double nH,double HeMfrac,double Z, double Zsol);
#endif
#ifdef COOLING_GRACKLE
void init_cooling_GRACKLE();
void CoolingForOne_GRACKLE(int i, double tstart, double tend, double dt_entr, double dt_entr2, double dt_entr3, double a_now, double a3inv);
#endif
#ifdef JEANS_PRESSURE_FLOOR
double JeansPressureFloor(int i);
#endif
#ifdef FOF
void fof(void);
void fof_init(void);
void fof_find_densest_neighbour(void);
int fof_compare_key(const void *a, const void *b);
int fof_compare_groups_key(const void *a, const void *b);
int fof_compare_phdata(const void *a, const void *b);
int fof_compare_particles(const void *a, const void *b);
void fof_evaluate(int target, int mode);
void fof_link_particles_to_local_head(void);
void fof_link_to_local_head(int i);
void fof_link_pseudo_heads(int i);
void fof_find_local_heads(void);
void fof_regroup_pseudo_heads(void);
void fof_regroup_exported_pseudo_heads(void);
void fof_clean_local_groups(void);
void fof_compute_local_tails(void);
void fof_send_and_link_pseudo_heads(void);
void fof_write_local_groups(void);
void fof_write_all_groups(void);
void fof_group_info(void);
void fof_compute_groups_properties(void);
void fof_init_group_properties(int gid);
void fof_add_particle_properties(int i, int gid, int mode);
void fof_final_operations_on_groups_properties();
void fof_write_groups_properties();
void fof_write_particles_id_and_indicies(void);
void fof_set_groups_for_sfr(void);
+void fof_compute_groups_potential(void);
+void fof_evaluate_groups_potential(int target, int mode);
+#ifdef FOF_COMPUTE_GROUPS_VIRIAL_LOCALLY
+double fof_compute_groups_virial_locally(int Np,double *Epot,double *Ekin,double *Eint);
+void fof_save_fof_particles(int Np,double VirialFraction,double Epot,double Ekin,double Eint);
+#endif
#ifdef SFR
void fof_star_formation(void);
void fof_star_formation_and_IMF_sampling(void);
#endif
void fof_allocate_groups(void);
void fof_free_groups(void);
-
+int grav_fof_compare_key(const void *a, const void *b);
#endif //FOF
#ifdef TESSEL
void ConstructDelaunay();
void ComputeVoronoi();
void setup_searching_radius();
int ngb_treefind_variable_for_tessel(FLOAT searchcenter[3], FLOAT hsml, int phase, int *startnode);
void ghost();
void tessel_compute_accelerations();
void tessel_convert_energy_to_entropy();
void tessel_kick(float dt_kick);
void tessel_drift(float dt_drift);
double tessel_get_timestep();
int CheckCompletenessForThisPoint(int i);
int ghost_compare_key(const void *a, const void *b);
void CheckTriangles();
void AddGhostPoints(int istart,int nadd);
void dump_triangles(char *filename);
void dump_voronoi(char *filename);
#ifdef PY_INTERFACE
#include <Python.h>
PyObject *gadget_GetAllDelaunayTriangles(self, args);
PyObject *gadget_GetAllvPoints(self, args);
PyObject *gadget_GetAllvDensities(PyObject* self);
PyObject *gadget_GetAllvVolumes(PyObject* self);
PyObject *gadget_GetAllvPressures(PyObject* self);
PyObject *gadget_GetAllvEnergySpec(PyObject* self);
PyObject *gadget_GetAllvAccelerations(PyObject* self);
PyObject *gadget_GetvPointsForOnePoint(self, args);
PyObject *gadget_GetNgbPointsForOnePoint(self, args);
PyObject *gadget_GetNgbPointsAndFacesForOnePoint(self, args);
PyObject *gadget_GetAllGhostPositions(PyObject* self);
PyObject *gadget_GetAllGhostvDensities(PyObject* self);
PyObject *gadget_GetAllGhostvVolumes(PyObject* self);
#endif
#endif
#ifdef PY_INTERFACE
#include <Python.h>
void allocate_commbuffersQ(void);
void density_sub(void);
void density_evaluate_sub(int i, int mode);
void do_box_wrappingQ(void);
void domain_DecompositionQ(void);
void domain_decomposeQ(void);
int domain_findSplitQ(int cpustart, int ncpu, int first, int last);
void domain_shiftSplitQ(void);
void domain_findExchangeNumbersQ(int task, int partner, int sphflag, int *send, int *recv);
void domain_exchangeParticlesQ(int partner, int sphflag, int send_count, int recv_count);
void domain_countToGoQ(void);
void domain_walktoptreeQ(int no);
void domain_sumCostQ(void);
void domain_findExtentQ(void);
void domain_determineTopTreeQ(void);
void domain_topsplit_localQ(int node, peanokey startkey);
void domain_topsplitQ(int node, peanokey startkey);
int force_treeevaluate_sub(int target, int mode, double *ewaldcountsum);
void force_treeevaluate_potential_sub(int target, int type);
void force_treeevaluate_potential_shortrange_sub(int target, int mode);
int force_treeevaluate_shortrange_sub(int target, int mode);
void gravity_tree_sub(void);
void sph(void);
void sph_evaluate(int target, int mode);
void sph_sub(void);
void sph_evaluate_sub(int target, int mode);
void sph_thermal_conductivity(void);
void sph_evaluate_thermal_conductivity(int target, int mode);
int sph_compare_key(const void *a, const void *b);
void peano_hilbert_orderQ(void);
void reorder_gasQ(void);
void reorder_particlesQ(void);
void setup_smoothinglengths_sub(void);
#ifdef SFR
PyObject * sfr_SetParameters(PyObject *self, PyObject *args);
PyObject * sfr_GetParameters();
#endif
#endif

Event Timeline