Page MenuHomec4science

No OneTemporary

File Metadata

Created
Thu, Nov 28, 20:36
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/src/Makefiles/Makefile.SNs b/src/Makefiles/Makefile.SNs
index c9fd087..83fe597 100644
--- a/src/Makefiles/Makefile.SNs
+++ b/src/Makefiles/Makefile.SNs
@@ -1,877 +1,878 @@
#----------------------------------------------------------------------
# From the list below, please activate/deactivate the options that
# apply to your run. If you modify any of these options, make sure
# that you recompile the whole code by typing "make clean; make".
#
# Look at end of file for a brief guide to the compile-time options.
#----------------------------------------------------------------------
#--------------------------------------- Basic operation mode of code
OPT += -DPERIODIC
OPT += -DUNEQUALSOFTENINGS
#--------------------------------------- Things that are always recommended
OPT += -DPEANOHILBERT
OPT += -DWALLCLOCK
#--------------------------------------- TreePM Options
#OPT += -DPMGRID=128
#OPT += -DPLACEHIGHRESREGION=3
#OPT += -DENLARGEREGION=1.2
#OPT += -DASMTH=1.25
#OPT += -DRCUT=4.5
#--------------------------------------- Single/Double Precision
#OPT += -DDOUBLEPRECISION
#OPT += -DDOUBLEPRECISION_FFTW
#--------------------------------------- Time integration options
OPT += -DSYNCHRONIZATION
#OPT += -DFLEXSTEPS
#OPT += -DPSEUDOSYMMETRIC
OPT += -DNOSTOP_WHEN_BELOW_MINTIMESTEP
#OPT += -DNOPMSTEPADJUSTMENT
OPT += -DSYNCHRONIZE_NGB_TIMESTEP # ngb particles have synchronized time steps
OPT += -DTIMESTEP_UPDATE_FOR_FEEDBACK # timestep is updated when feedback occurs
OPT += -DIMPROVED_TIMESTEP_CRITERION_FORGAS # improvement of timestep criterion for the gas
#--------------------------------------- Output
OPT += -DADVANCEDSTATISTICS
OPT += -DADVANCEDCPUSTATISTICS
OPT += -DSYSTEMSTATISTICS
OPT += -DBLOCK_SKIPPING
#OPT += -DHAVE_HDF5
#OPT += -DOUTPUTPOTENTIAL
#OPT += -DOUTPUTACCELERATION
#OPT += -DOUTPUTCHANGEOFENTROPY
#OPT += -DOUTPUTTIMESTEP
#OPT += -DOUTPUTERADSTICKY
#OPT += -DOUTPUTERADFEEDBACK
#OPT += -DOUTPUTENERGYFLUX
OPT += -DOUTPUTOPTVAR1
OPT += -DOUTPUTSTELLAR_PROP
#--------------------------------------- Things for special behaviour
#OPT += -DNOGRAVITY
#OPT += -DNOTREERND
#OPT += -DNOTYPEPREFIX_FFTW
#OPT += -DLONG_X=60
#OPT += -DLONG_Y=5
#OPT += -DLONG_Z=0.2
#OPT += -DTWODIMS
#OPT += -DSPH_BND_PARTICLES
#OPT += -DNOVISCOSITYLIMITER
OPT += -DCOMPUTE_POTENTIAL_ENERGY
#OPT += -DLONGIDS
#OPT += -DISOTHERM_EQS
#OPT += -DADAPTIVE_GRAVSOFT_FORGAS
#OPT += -DSELECTIVE_NO_GRAVITY=2+4+8+16
#OPT += -DAVOIDNUMNGBPROBLEM
#OPT += -DLIMIT_DVEL=1.0
#OPT += -DOTHERINFO
#OPT += -DDOMAIN_AT_ORIGIN
OPT += -DNO_NEGATIVE_PRESSURE
#OPT += -DCOMPUTE_VELOCITY_DISPERSION
#OPT += -DCYLINDRICAL_SYMMETRY
OPT += -DWRITE_ALL_MASSES
OPT += -DCOUNT_ACTIVE_PARTICLES
OPT += -DRANDOMSEED_AS_PARAMETER
OPT += -DDETAILED_CPU
OPT += -DDETAILED_CPU_GRAVITY
OPT += -DDETAILED_CPU_DOMAIN
OPT += -DDETAILED_OUTPUT_IN_GRAVTREE
#OPT += -DSPLIT_DOMAIN_USING_TIME
OPT += -DCOSMICTIME
OPT += -DONLY_MASTER_READ_EWALD
#OPT += -DPNBODY
#OPT += -DPNBODY_OUTPUT_POS
#OPT += -DPNBODY_OUTPUT_VEL
#OPT += -DPNBODY_OUTPUT_NUM
#OPT += -DPNBODY_OUTPUT_MASS
#OPT += -DPNBODY_OUTPUT_TYPE
#OPT += -DPNBODY_OUTPUT_ENERGY
#OPT += -DPNBODY_OUTPUT_DENSITY
#OPT += -DPNBODY_OUTPUT_HSML
#OPT += -DPNBODY_OUTPUT_METALS
#--------------------------------------- Physical processes
OPT += -DCOOLING
#OPT += -DIMPLICIT_COOLING_INTEGRATION
#OPT += -DDO_NO_USE_HYDROGEN_MASSFRAC_IN_COOLING
#OPT += -DHEATING
#OPT += -DHEATING_PE # photo-electric heating
OPT += -DSFR
OPT += -DCOMPUTE_SFR_ENERGY
OPT += -DSFR_NEG_DIV_ONLY
OPT += -DSTELLAR_PROP
OPT += -DCHIMIE # need stellar prop
OPT += -DCHIMIE_THERMAL_FEEDBACK
OPT += -DCHIMIE_COMPUTE_THERMAL_FEEDBACK_ENERGY
#OPT += -DCHIMIE_KINETIC_FEEDBACK
#OPT += -DCHIMIE_COMPUTE_KINETIC_FEEDBACK_ENERGY
OPT += -DCHIMIE_EXTRAHEADER
#OPT += -DCHIMIE_INPUT_ALL
OPT += -DCHIMIE_MC_SUPERNOVAE
OPT += -DCHIMIE_ONE_SN_ONLY
#OPT += -DFEEDBACK
#OPT += -DFEEDBACK_WIND
#--------------------------------------- multiphase
#OPT += -DMULTIPHASE
#OPT += -DNO_HYDRO_FOR_GAS # do not use hydro routine (at all)
#OPT += -DNO_DENSITY_FOR_STICKY # do not compute density in sticky (need to be done in sfr)
#OPT += -DPHASE_MIXING # need MULTIPHASE : enable phase mixing
#OPT += -DCOLDGAS_CYCLE # need MULTIPHASE and PHASE_MIXING
#OPT += -DEXTERNAL_FLUX
#OPT += -DSTELLAR_FLUX
#OPT += -DCOUNT_COLLISIONS # count sticky collisions
+OPT += -DGAS_ACCRETION
#--------------------------------------- Outer potential
#OPT += -DOUTERPOTENTIAL
#OPT += -DNFW
#OPT += -DPISOTHERM
#OPT += -DPLUMMER
#OPT += -DMIYAMOTONAGAI
#OPT += -DCORIOLIS
#--------------------------------------- Testing and Debugging options
#OPT += -DFORCETEST=0.1
#OPT += -DWITH_ID_IN_HYDRA
#OPT += -DPARTICLE_FLAG
#OPT += -DOUTPUT_EVERY_TIMESTEP
#OPT += -DOUTPUT_COOLING_FUNCTION
OPT += -DCHECK_BLOCK_ORDER
OPT += -DCHECK_ENTROPY_SIGN
OPT += -DCHECK_TYPE_DURING_IO
OPT += -DCHECK_ID_CORRESPONDENCE
#--------------------------------------- Sph flavor
OPT += -DENTROPYPRED
OPT += -DDENSITY_INDEPENDENT_SPH
#--------------------------------------- Glass making
#OPT += -DMAKEGLASS=262144
#--------------------------------------- Agn
#OPT += -DBUBBLES
#OPT += -DAGN_ACCRETION
#OPT += -DAGN_FEEDBACK
#OPT += -DAGN_USE_ANGULAR_MOMENTUM
#OPT += -DAGN_HEATING
#OPT += -DBONDI_ACCRETION
#OPT += -DUSE_BONDI_POWER
#----------------------------------------------------------------------
# Here, select compile environment for the target machine. This may need
# adjustment, depending on your local system. Follow the examples to add
# additional target platforms, and to get things properly compiled.
#----------------------------------------------------------------------
#--------------------------------------- Select some defaults
CC = mpicc # sets the C-compiler
OPTIMIZE = -O2 -Wall -g # sets optimization and warning flags
MPICHLIB = -lmpich
#--------------------------------------- Select target computer
SYSTYPE="obscalc"
#SYSTYPE="callisto-intel"
#SYSTYPE="bg1"
#SYSTYPE="obsds"
#SYSTYPE="leo_openmpi"
#SYSTYPE="leo_mpich2shm"
#SYSTYPE="graphor0"
#SYSTYPE="obsrevaz"
#SYSTYPE="regor_openmpigcc"
#SYSTYPE="regor_mvapich2gcc"
#SYSTYPE="meso_mpich2"
#SYSTYPE="meso"
#SYSTYPE="revaz/local"
#SYSTYPE="revaz/local_mpich2"
#SYSTYPE="horizon3_mpich1"
#SYSTYPE="horizon3_mpich2"
#SYSTYPE="horizon3"
#SYSTYPE="LUXOR"
#SYSTYPE="MPA"
#SYSTYPE="Mako"
#SYSTYPE="Regatta"
#SYSTYPE="RZG_LinuxCluster"
#SYSTYPE="RZG_LinuxCluster-gcc"
#SYSTYPE="OpteronMPA"
#SYSTYPE="OPA-Cluster32"
#SYSTYPE="OPA-Cluster64"
#--------------------------------------- Adjust settings for target computer
# module add openmpi-x86_64
ifeq ($(SYSTYPE),"obscalc")
CC = mpicc
OPTIMIZE =
GSL_INCL =
GSL_LIBS =
FFTW_INCL=
FFTW_LIBS=
MPICHLIB =
HDF5INCL =
HDF5LIB =
NO_FFTW_LIB = "yes"
PY_INCL = -I/usr/include/python2.6/
PY_LIB = -lpython2.6
endif
ifeq ($(SYSTYPE),"callisto-intel")
CC = mpicc
OPTIMIZE =
GSL_INCL = -I/u1/yrevaz/local/gsl-intel/include
GSL_LIBS = -L/u1/yrevaz/local/gsl-intel/lib
FFTW_INCL= -I/u1/yrevaz/local/fftw-2.1.5-intel/include
FFTW_LIBS= -L/u1/yrevaz/local/fftw-2.1.5-intel/lib
MPICHLIB =
HDF5INCL =
HDF5LIB =
endif
ifeq ($(SYSTYPE),"bg1")
CC = mpicc
OPTIMIZE = -O3 -Wall -g
GSL_INCL = -I/home/yrevaz/local/include
GSL_LIBS = -L/home/yrevaz/local/lib
FFTW_INCL=
FFTW_LIBS=
MPICHLIB =
HDF5INCL =
HDF5LIB =
NO_FFTW_LIB = "yes"
endif
ifeq ($(SYSTYPE),"obsds")
CC = mpicc
OPTIMIZE = -O3 -Wall -g
GSL_INCL =
GSL_LIBS =
FFTW_INCL=
FFTW_LIBS=
MPICHLIB =
HDF5INCL =
HDF5LIB =
NO_FFTW_LIB = "yes"
endif
ifeq ($(SYSTYPE),"graphor0")
CC = mpicc
OPTIMIZE = -O3 -Wall -g
GSL_INCL = -I/home/epfl/revaz/local/include
GSL_LIBS = -L/home/epfl/revaz/local/lib
FFTW_INCL= -I/home/epfl/revaz/local/include
FFTW_LIBS= -L/home/epfl/revaz/local/lib
MPICHLIB = -L/home/epfl/revaz/local/openmpi/lib -lmpi
HDF5INCL =
HDF5LIB =
endif
ifeq ($(SYSTYPE),"obsrevaz")
CC = mpicc
OPTIMIZE = -O3 -Wall -fpack-struct
GSL_INCL =
GSL_LIBS =
FFTW_INCL= -I/home/revaz/local/include/
FFTW_LIBS= -L/home/revaz/local/lib/
MPICHLIB = -lmpi
HDF5INCL =
HDF5LIB =
endif
ifeq ($(SYSTYPE),"regor_openmpigcc")
CC = mpicc
OPTIMIZE = -O3 -Wall -fpack-struct
GSL_INCL = -I/usr/include
GSL_LIBS = -L/usr/lib64/
FFTW_INCL= -I/home/revaz/local_mvapich2gcc/include/
FFTW_LIBS= -L/home/revaz/local_mvapich2gcc/lib/
MPICHLIB = -lmpi
HDF5INCL =
HDF5LIB =
OPT += -DMESOMACHINE
endif
ifeq ($(SYSTYPE),"regor_mpich2")
CC = mpicc
OPTIMIZE = -O3 -Wall -fpack-struct
GSL_INCL = -I/usr/include
GSL_LIBS = -L/usr/lib64/
FFTW_INCL= -I/home/revaz/local_mvapich2gcc/include/
FFTW_LIBS= -L/home/revaz/local_mvapich2gcc/lib/
MPICHLIB = -L/home/revaz/local/mpich2-1.0.6nemesis/lib/ -lmpich
HDF5INCL =
HDF5LIB =
OPT += -DMESOMACHINE
endif
ifeq ($(SYSTYPE),"regor_mvapich2gcc")
CC = mpicc
OPTIMIZE = -O3 -Wall -fpack-struct
GSL_INCL = -I/usr/include
GSL_LIBS = -L/usr/lib64/
FFTW_INCL= -I/home/revaz/local_mvapich2gcc/include/
FFTW_LIBS= -L/home/revaz/local_mvapich2gcc/lib/
MPICHLIB = -L/cvos/shared/apps/ofed/1.2.5.3/mpi/gcc/mvapich2-0.9.8-15/lib/ -lmpich
HDF5INCL =
HDF5LIB =
OPT += -DMESOMACHINE
endif
ifeq ($(SYSTYPE),"leo_openmpi")
CC = mpicc
OPTIMIZE = -O3 -Wall -fpack-struct
GSL_INCL = -I/export/revaz/local/include
GSL_LIBS = -L/export/revaz/local/lib
FFTW_INCL= -I/export/revaz/local/include
FFTW_LIBS= -L/export/revaz/local/lib
MPICHLIB = -L/usr/local/mpich2-pgi/lib -lmpi
HDF5INCL =
HDF5LIB =
endif
ifeq ($(SYSTYPE),"leo_mpich2shm")
CC = mpicc
OPTIMIZE = -O3 -Wall -g -fpack-struct
GSL_INCL = -I/export/revaz/local/include
GSL_LIBS = -L/export/revaz/local/lib
FFTW_INCL= -I/export/revaz/local/include
FFTW_LIBS= -L/export/revaz/local/lib
MPICHLIB = -L/usr/local/mpich2-pgi/lib -lmpich
HDF5INCL =
HDF5LIB =
endif
ifeq ($(SYSTYPE),"meso_mpich2")
CC = mpicc
OPTIMIZE = -O3 -Wall -g -fpack-struct
GSL_INCL = -I/home/revaz/local/include
GSL_LIBS = -L/home/revaz/local/lib
FFTW_INCL= -I/horizon1/x86_64_sl4/fftw/2.1.5/include/
FFTW_LIBS= -L/horizon1/x86_64_sl4/fftw/2.1.5/lib/
MPICHLIB = -L/home/revaz/local/mpich2-1.0.3/lib -lmpich
HDF5INCL =
HDF5LIB =
endif
ifeq ($(SYSTYPE),"meso")
CC = mpicc
OPTIMIZE = -O3 -g
GSL_INCL =
GSL_LIBS =
FFTW_INCL= -I/horizon1/x86_64_sl4/fftw/2.1.5/include/
FFTW_LIBS= -L/horizon1/x86_64_sl4/fftw/2.1.5/lib/
MPICHLIB =
HDF5INCL =
HDF5LIB =
OPT += -DMESOMACHINE
endif
ifeq ($(SYSTYPE),"revaz/local")
CC = mpicc
OPTIMIZE = -O3 -Wall -g
GSL_INCL = -I/home/revaz/local/include
GSL_LIBS = -L/home/revaz/local/lib
FFTW_INCL= -I/home/revaz/local/include
FFTW_LIBS= -L/home/revaz/local/lib
MPICHLIB = -L/home/revaz/local/mpich-1.2.5/ch_p4/lib -lmpich
HDF5INCL =
HDF5LIB =
endif
ifeq ($(SYSTYPE),"revaz/local_mpich2")
CC = mpicc
OPTIMIZE = -O3 -Wall -g
GSL_INCL = -I/home/revaz/local/include
GSL_LIBS = -L/home/revaz/local/lib
FFTW_INCL= -I/home/revaz/local/include
FFTW_LIBS= -L/home/revaz/local/lib
MPICHLIB = -L/home/revaz/local/mpich2-1.0.3/lib/ -lmpich
HDF5INCL =
HDF5LIB =
endif
ifeq ($(SYSTYPE),"LUXOR")
CC = mpicc
OPTIMIZE = -O3 -Wall -g
#GSL_INCL = -I/home/revaz/local/include
#GSL_LIBS = -L/home/revaz/local/lib
#FFTW_INCL= -I/home/revaz/local/include
#FFTW_LIBS= -L/home/revaz/local/lib
MPICHLIB = -L/home/revaz/local/mpich-1.2.7/ch_p4/lib -lmpich
HDF5INCL =
HDF5LIB =
endif
ifeq ($(SYSTYPE),"horizon3")
CC = mpicc
OPTIMIZE = -O3 -Wall -g -fpack-struct
GSL_INCL = -I/home/revaz/local/include
GSL_LIBS = -L/home/revaz/local/lib
FFTW_INCL= -I/home/revaz/local/include
FFTW_LIBS= -L/home/revaz/local/lib
MPICHLIB = -llam
HDF5INCL =
HDF5LIB =
endif
ifeq ($(SYSTYPE),"horizon3_mpich1")
CC = mpicc
OPTIMIZE = -O3 -Wall -g -fpack-struct
GSL_INCL = -I/home/revaz/local/include
GSL_LIBS = -L/home/revaz/local/lib
FFTW_INCL= -I/home/revaz/local/include
FFTW_LIBS= -L/home/revaz/local/lib
MPICHLIB = -L/home/revaz/local/mpich-1.2.7/lib -lmpich
HDF5INCL =
HDF5LIB =
endif
ifeq ($(SYSTYPE),"horizon3_mpich2")
CC = mpicc
OPTIMIZE = -O3 -Wall -g -fpack-struct
GSL_INCL = -I/home/revaz/local/include
GSL_LIBS = -L/home/revaz/local/lib
FFTW_INCL= -I/home/revaz/local/include
FFTW_LIBS= -L/home/revaz/local/lib
MPICHLIB = -L/usr/local/mpich2-pgi/lib -lmpich
HDF5INCL =
HDF5LIB =
endif
ifeq ($(SYSTYPE),"MPA")
CC = mpicc
OPTIMIZE = -O3 -Wall
GSL_INCL = -I/usr/common/pdsoft/include
GSL_LIBS = -L/usr/common/pdsoft/lib -Wl,"-R /usr/common/pdsoft/lib"
FFTW_INCL=
FFTW_LIBS=
MPICHLIB =
HDF5INCL =
HDF5LIB = -lhdf5 -lz
endif
ifeq ($(SYSTYPE),"OpteronMPA")
CC = mpicc
OPTIMIZE = -O3 -Wall -m64
GSL_INCL = -L/usr/local/include
GSL_LIBS = -L/usr/local/lib
FFTW_INCL=
FFTW_LIBS=
MPICHLIB =
HDF5INCL = -I/opt/hdf5/include
HDF5LIB = -L/opt/hdf5/lib -lhdf5 -lz -Wl,"-R /opt/hdf5/lib"
endif
ifeq ($(SYSTYPE),"OPA-Cluster32")
CC = mpicc
OPTIMIZE = -O3 -Wall
GSL_INCL = -I/afs/rzg/bc-b/vrs/opteron32/include
GSL_LIBS = -L/afs/rzg/bc-b/vrs/opteron32/lib -Wl,"-R /afs/rzg/bc-b/vrs/opteron32/lib"
FFTW_INCL= -I/afs/rzg/bc-b/vrs/opteron32/include
FFTW_LIBS= -L/afs/rzg/bc-b/vrs/opteron32/lib
MPICHLIB =
HDF5INCL =
HDF5LIB = -lhdf5 -lz
endif
ifeq ($(SYSTYPE),"OPA-Cluster64")
CC = mpicc
OPTIMIZE = -O3 -Wall -m64
GSL_INCL = -I/afs/rzg/bc-b/vrs/opteron64/include
GSL_LIBS = -L/afs/rzg/bc-b/vrs/opteron64/lib -Wl,"-R /afs/rzg/bc-b/vrs/opteron64/lib"
FFTW_INCL= -I/afs/rzg/bc-b/vrs/opteron64/include
FFTW_LIBS= -L/afs/rzg/bc-b/vrs/opteron64/lib
MPICHLIB =
HDF5INCL =
HDF5LIB = -lhdf5 -lz
endif
ifeq ($(SYSTYPE),"Mako")
CC = mpicc # sets the C-compiler
OPTIMIZE = -O3 -march=athlon-mp -mfpmath=sse
GSL_INCL =
GSL_LIBS =
FFTW_INCL=
FFTW_LIBS=
MPICHLIB =
HDF5INCL =
HDF5LIB = -lhdf5 -lz
endif
ifeq ($(SYSTYPE),"Regatta")
CC = mpcc_r
OPTIMIZE = -O5 -qstrict -qipa -q64
GSL_INCL = -I/afs/rzg/u/vrs/gsl_psi64/include
GSL_LIBS = -L/afs/rzg/u/vrs/gsl_psi64/lib
FFTW_INCL= -I/afs/rzg/u/vrs/fftw_psi64/include
FFTW_LIBS= -L/afs/rzg/u/vrs/fftw_psi64/lib -q64 -qipa
MPICHLIB =
HDF5INCL = -I/afs/rzg/u/vrs/hdf5_psi64/include
HDF5LIB = -L/afs/rzg/u/vrs/hdf5_psi64/lib -lhdf5 -lz
endif
ifeq ($(SYSTYPE),"RZG_LinuxCluster")
CC = mpicci
OPTIMIZE = -O3 -ip # Note: Don't use the "-rcd" optimization of Intel's compiler! (causes code crashes)
GSL_INCL = -I/afs/rzg/u/vrs/gsl_linux/include
GSL_LIBS = -L/afs/rzg/u/vrs/gsl_linux/lib -Wl,"-R /afs/rzg/u/vrs/gsl_linux/lib"
FFTW_INCL= -I/afs/rzg/u/vrs/fftw_linux/include
FFTW_LIBS= -L/afs/rzg/u/vrs/fftw_linux/lib
HDF5INCL = -I/afs/rzg/u/vrs/hdf5_linux/include
HDF5LIB = -L/afs/rzg/u/vrs/hdf5_linux/lib -lhdf5 -lz -Wl,"-R /afs/rzg/u/vrs/hdf5_linux/lib"
endif
ifeq ($(SYSTYPE),"RZG_LinuxCluster-gcc")
CC = mpiccg
OPTIMIZE = -Wall -g -O3 -march=pentium4
GSL_INCL = -I/afs/rzg/u/vrs/gsl_linux_gcc3.2/include
GSL_LIBS = -L/afs/rzg/u/vrs/gsl_linux_gcc3.2/lib -Wl,"-R /afs/rzg/u/vrs/gsl_linux_gcc3.2/lib"
FFTW_INCL= -I/afs/rzg/u/vrs/fftw_linux_gcc3.2/include
FFTW_LIBS= -L/afs/rzg/u/vrs/fftw_linux_gcc3.2/lib
HDF5INCL = -I/afs/rzg/u/vrs/hdf5_linux/include
HDF5LIB = -L/afs/rzg/u/vrs/hdf5_linux/lib -lhdf5 -lz -Wl,"-R /afs/rzg/u/vrs/hdf5_linux/lib"
endif
ifneq (HAVE_HDF5,$(findstring HAVE_HDF5,$(OPT)))
HDF5INCL =
HDF5LIB =
endif
OPTIONS = $(OPTIMIZE) $(OPT)
EXEC = Gadget2
OBJS = main.o run.o predict.o begrun.o endrun.o global.o \
timestep.o init.o restart.o io.o \
accel.o read_ic.o ngb.o \
system.o allocate.o density.o \
gravtree.o hydra.o driftfac.o \
domain.o allvars.o potential.o \
forcetree.o peano.o gravtree_forcetest.o \
pm_periodic.o pm_nonperiodic.o longrange.o \
cooling.o agn_heating.o phase.o sticky.o outerpotential.o starformation.o \
agn_feedback.o bubbles.o bondi_accretion.o chimie.o stars_density.o cosmictime.o \
- pnbody.o ab_turb.o art_visc.o sigvel.o
+ pnbody.o ab_turb.o art_visc.o sigvel.o gas_accretion.o
INCL = allvars.h proto.h tags.h Makefile
CFLAGS = $(OPTIONS) $(GSL_INCL) $(FFTW_INCL) $(HDF5INCL) $(PY_INCL)
ifeq (NOTYPEPREFIX_FFTW,$(findstring NOTYPEPREFIX_FFTW,$(OPT))) # fftw installed with type prefix?
FFTW_LIB = $(FFTW_LIBS) -lrfftw_mpi -lfftw_mpi -lrfftw -lfftw
else
ifeq (DOUBLEPRECISION_FFTW,$(findstring DOUBLEPRECISION_FFTW,$(OPT)))
FFTW_LIB = $(FFTW_LIBS) -ldrfftw_mpi -ldfftw_mpi -ldrfftw -ldfftw
else
FFTW_LIB = $(FFTW_LIBS) -lsrfftw_mpi -lsfftw_mpi -lsrfftw -lsfftw
endif
endif
ifeq ($(NO_FFTW_LIB),"yes")
FFTW_LIB =
endif
LIBS = $(HDF5LIB) -g $(MPICHLIB) $(GSL_LIBS) -lgsl -lgslcblas -lm $(FFTW_LIB) $(PY_LIB)
$(EXEC): $(OBJS)
$(CC) $(OBJS) $(LIBS) -o $(EXEC)
$(OBJS): $(INCL)
clean:
rm -f $(OBJS) $(EXEC)
#-----------------------------------------------------------------------
#
# Brief guide to compile-time options of the code. More information
# can be found in the code documentation.
#
# - PERIODIC:
# Set this if you want to have periodic boundary conditions.
#
# - UNEQUALSOFTENINGS:
# Set this if you use particles with different gravitational
# softening lengths.
#
# - PEANOHILBERT:
# This is a tuning option. When set, the code will bring the
# particles after each domain decomposition into Peano-Hilbert
# order. This improves cache utilization and performance.
#
# - WALLCLOCK:
# If set, a wallclock timer is used by the code to measure internal
# time consumption (see cpu-log file). Otherwise, a timer that
# measures consumed processor ticks is used.
#
# - PMGRID:
# This enables the TreePM method, i.e. the long-range force is
# computed with a PM-algorithm, and the short range force with the
# tree. The parameter has to be set to the size of the mesh that
# should be used, (e.g. 64, 96, 128, etc). The mesh dimensions need
# not necessarily be a power of two. Note: If the simulation is
# not in a periodic box, then a FFT method for vacuum boundaries is
# employed, using an actual mesh with dimension twice(!) that
# specified by PMGRID.
#
# - PLACEHIGHRESREGION:
# If this option is set (will only work together with PMGRID), then
# the long range force is computed in two stages: One Fourier-grid
# is used to cover the whole simulation volume, allowing the
# computation of the longe-range force. A second Fourier mesh is
# placed on the region occupied by "high-resolution" particles,
# allowing the computation of an intermediate scale force. Finally,
# the force on short scales is computed with the tree. This
# procedure can be useful for "zoom-simulations", provided the
# majority of particles (the high-res particles) are occupying only
# a small fraction of the volume. To activate this option, the
# parameter needs to be set to an integer bit mask that encodes the
# particle types that make up the high-res particles.
# For example, if types 0, 1, and 4 form the high-res
# particles, set the parameter to PLACEHIGHRESREGION=19, because
# 2^0 + 2^1 + 2^4 = 19. The spatial region covered by the high-res
# grid is determined automatically from the initial conditions.
# Note: If a periodic box is used, the high-res zone may not intersect
# the box boundaries.
#
# - ENLARGEREGION:
# The spatial region covered by the high-res zone has a fixed size
# during the simulation, which initially is set to the smallest
# region that encompasses all high-res particles. Normally, the
# simulation will be interrupted if high-res particles leave this
# region in the course of the run. However, by setting this
# parameter to a value larger than one, the size of the high-res
# region can be expanded, providing a buffer region. For example,
# setting it to 1.4 will enlarge its side-length by 40% (it remains
# centered on the high-res particles). Hence, with this setting, the
# high-res region may expand or move by a limited amount.
# Note: If SYNCHRONIZATION is activated, the code will be able to
# continue even if high-res particles leave the initial high-res
# grid. In this case, the code will update the size and position of
# the grid that is placed onto the high-resolution region
# automatically. To prevent that this potentially happens every
# single PM step, one should nevertheless assign a value slightly
# larger than 1 to ENLARGEREGION.
#
# - ASMTH:
# This can be used to override the value assumed for the scale that
# defines the long-range/short-range force-split in the TreePM
# algorithm. The default value is 1.25, in mesh-cells.
#
# - RCUT:
# This can be used to override the maximum radius in which the
# short-range tree-force is evaluated (in case the TreePM algorithm
# is used). The default value is 4.5, given in mesh-cells.
#
# - DOUBLEPRECISION:
# This makes the code store and compute internal particle data in
# double precision. Note that output files are nevertheless written
# by converting the particle data to single precision.
#
# - DDOUBLEPRECISION_FFTW:
# If this is set, the code will use the double-precision version of
# FTTW, provided the latter has been explicitly installed with a
# "d" prefix, and NOTYPEPREFIX_FFTW is not set. Otherwise the
# single precision version ("s" prefix) is used.
#
# - SYNCHRONIZATION:
# When this is set, particles are kept in a binary hierarchy of
# timesteps and may only increase their timestep if the new
# timestep will put them into synchronization with the higher time
# level.
#
# - FLEXSTEPS:
# This is an alternative to SYNCHRONIZATION. Particle timesteps are
# here allowed to be integer multiples of the minimum timestep that
# occurs among the particles, which in turn is rounded down to the
# nearest power-of-two devision of the total simulated
# timespan. This option distributes particles more evenly over
# individual system timesteps, particularly once a simulation has
# run for a while, and may then result in a reduction of work-load
# imbalance losses.
#
# - PSEUDOSYMMETRIC:
# When this option is set, the code will try to "anticipate"
# timestep changes by extrapolating the change of the acceleration
# into the future. This can in certain idealized cases improve the
# long-term integration behaviour of periodic orbits, but should
# make little or no difference in most real-world applications. May
# only be used together with SYNCHRONIZATION.
#
# - NOSTOP_WHEN_BELOW_MINTIMESTEP:
# If this is activated, the code will not terminate when the
# timestep falls below the value of MinSizeTimestep specified in
# the parameterfile. This is useful for runs where one wants to
# enforce a constant timestep for all particles. This can be done
# by activating this option, and by setting MinSizeTimestep and
# MaxSizeTimestep to an equal value.
#
# - NOPMSTEPADJUSTMENT:
# When this is set, the long-range timestep for the PM-force
# computation (when the TreePM algorithm is used) is always
# determined by MaxSizeTimeStep. Otherwise, it is determined by
# the MaxRMSDisplacement parameter, or MaxSizeTimeStep, whichever
# gives the smaller step.
#
# - HAVE_HDF5:
# If this is set, the code will be compiled with support for input
# and output in the HDF5 format. You need to have the HDF5
# libraries and headers installed on your computer for this option
# to work. The HDF5 format can then be selected as format "3" in
# Gadget's parameterfile.
#
# - OUTPUTPOTENTIAL:
# This will make the code compute gravitational potentials for
# all particles each time a snapshot file is generated. The values
# are then included in the snapshot file. Note that the computation
# of the values of the gravitational potential costs additional CPU.
#
# - OUTPUTACCELERATION:
# This will include the physical acceleration of each particle in
# snapshot files.
#
# - OUTPUTCHANGEOFENTROPY:
# This will include the rate of change of entropy of gas particles
# in snapshot files.
#
# - OUTPUTTIMESTEP:
# This will include the current timesteps of all particles in the
# snapshot files.
#
# - NOGRAVITY
# This switches off gravity. Useful only for pure SPH simulations
# in non-expanding space.
#
# - NOTREERND:
# If this is not set, the tree construction will succeed even when
# there are a few particles at identical locations. This is done by
# `rerouting' particles once the node-size has fallen below 1.0e-3
# of the softening length. When this option is activated, this will
# be surpressed and the tree construction will always fail if there
# are particles at extremely close coordinates.
#
# - NOTYPEPREFIX_FFTW:
# This is an option that signals that FFTW has been compiled
# without the type-prefix option, i.e. no leading "d" or "s"
# characters are used to access the library.
#
# - LONG_X/Y/Z:
# These options can be used together with PERIODIC and NOGRAVITY only.
# When set, the options define numerical factors that can be used to
# distorts the periodic simulation cube into a parallelepiped of
# arbitrary aspect ratio. This can be useful for idealized SPH tests.
#
# - TWODIMS:
# This effectively switches of one dimension in SPH, i.e. the code
# follows only 2d hydrodynamics in the xy-, yz-, or xz-plane. This
# only works with NOGRAVITY, and if all coordinates of the third
# axis are exactly equal. Can be useful for idealized SPH tests.
#
# - SPH_BND_PARTICLES:
# If this is set, particles with a particle-ID equal to zero do not
# receive any SPH acceleration. This can be useful for idealized
# SPH tests, where these particles represent fixed "walls".
#
# - NOVISCOSITYLIMITER:
# If this is set, the code will not try to put an upper limit on
# the viscous force in case an implausibly high pair-wise viscous
# force (which may lead to a particle 'reflection' in case of poor
# timestepping) should arise. Note: For proper settings of the
# timestep parameters, this situation should not arise.
#
# - COMPUTE_POTENTIAL_ENERGY:
# When this option is set, the code will compute the gravitational
# potential energy each time a global statistics is computed. This
# can be useful for testing global energy conservation.
#
# - LONGIDS:
# If this is set, the code assumes that particle-IDs are stored as
# 64-bit long integers. This is only really needed if you want to
# go beyond ~2 billion particles.
#
# - ISOTHERM_EQS:
# This special option makes the gas behave like an isothermal gas
# with equation of state P = cs^2 * rho. The sound-speed cs is set by
# the thermal energy per unit mass in the intial conditions,
# i.e. cs^2=u. If the value for u is zero, then the initial gas
# temperature in the parameter file is used to define the sound speed
# according to cs^2 = 3/2 kT/mp, where mp is the proton mass.
#
# - ADAPTIVE_GRAVSOFT_FORGAS:
# When this option is set, the gravitational softening lengths used for
# gas particles is tied to their SPH smoothing length. This can be useful
# for dissipative collapse simulations. The option requires the setting
# of UNEQUALSOFTENINGS.
#
# - SELECTIVE_NO_GRAVITY:
# This can be used for special computations where one wants to
# exclude certain particle types from receiving gravitational
# forces. The particle types that are excluded in this fashion are
# specified by a bit mask, in the same as for the PLACEHIGHRESREGION
# option.
#
# - FORCETEST:
# This can be set to check the force accuracy of the code. The
# option needs to be set to a number between 0 and 1 (e.g. 0.01),
# which is taken to specify a random fraction of particles for
# which at each timestep forces by direct summation are
# computed. The normal tree-forces and the correct direct
# summation forces are collected in a file. Note that the
# simulation itself is unaffected by this option, but it will of
# course run much(!) slower, especially if
# FORCETEST*NumPart*NumPart >> NumPart. Note: Particle IDs must
# be set to numbers >=1 for this to work.
#
# - MAKEGLASS
# This option can be used to generate a glass-like particle
# configuration. The value assigned gives the particle load,
# which is initially generated as a Poisson sample and then
# evolved towards a glass with the sign of gravity reversed.
#
#-----------------------------------------------------------------------
diff --git a/src/allvars.c b/src/allvars.c
index 833e2ad..9403c6b 100644
--- a/src/allvars.c
+++ b/src/allvars.c
@@ -1,460 +1,471 @@
/*! \file allvars.c
* \brief provides instances of all global variables.
*/
#include <stdio.h>
#include <gsl/gsl_rng.h>
#include "tags.h"
#include "allvars.h"
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 N_acc;
+long long Ntotacc;
+#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 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. */
#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
+
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 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 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 f464ea5..3b2bd92 100644
--- a/src/allvars.h
+++ b/src/allvars.h
@@ -1,2034 +1,2060 @@
/*! \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 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 500 /*!< 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 5
#define MAXNELEMENTS 64
#define FIRST_ELEMENT "Fe"
#define FE 0
#endif
#ifdef COOLING
#define COOLING_NMETALICITIES 9
#define COOLING_NTEMPERATURES 171
#endif
#ifdef COMPUTE_VELOCITY_DISPERSION
#define VELOCITY_DISPERSION_SIZE 3
#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 N_acc;
+extern long long Ntotacc;
+#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 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. */
#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
+
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 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 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_cooling_data_max;
double CoolingParameters_cooling_data[COOLING_NMETALICITIES][COOLING_NTEMPERATURES];
int CoolingParameters_p;
int CoolingParameters_q;
#ifdef LAMBDA_DEPRAZ
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_ONE_SN_ONLY /*!< explode only one sn>*/
int ChimieOneSN;
#endif
#endif
#if defined (CHIMIE) || defined (COOLING)
double InitGasMetallicity;
#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 OUTERPOTENTIAL
#ifdef NFW
double HaloConcentration;
double HaloMass;
double GasMassFraction;
double NFWPotentialCte;
double Rs;
#endif
#ifdef PLUMMER
double PlummerMass;
double PlummerSoftenning;
double PlummerPotentialCte;
#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;
#endif
#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 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 GasAccretionParticleMass;
+#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 */
/* 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
}
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
}
*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];
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
+
+
#if PY_INTERFACE
FLOAT Observable;
FLOAT ObsMoment0;
FLOAT ObsMoment1;
FLOAT GradObservable[3];
#endif
# ifdef SYNCHRONIZE_NGB_TIMESTEP
int Ti_minNgbStep;
#endif
#ifdef TIMESTEP_UPDATE_FOR_FEEDBACK
FLOAT FeedbackUpdatedAccel[3]; /*!< acceleration after feedback injection */
#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
}
*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 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 Volume; /*!< current volume 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 */
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
}
*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 */
#ifdef MULTIPHASE
double critical_energy_spec;
#ifdef MESOMACHINE
char fill[38];
#else
char fill[48]; /* use 42 with regor... */
#endif
#else
char fill[56]; /*!< 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 SolarAbundances[NELEMENTS];
char labels[256-4-4*(NELEMENTS)];
}
chimie_extraheader;
#endif
#define IO_NBLOCKS 24 /*!< 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_STAR_FORMATIONTIME,
IO_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 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
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];
}
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
}
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
}
*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
}
*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
}
*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
}
*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 Volume;
FLOAT Pressure;
FLOAT F1;
FLOAT DhsmlDensityFactor;
int Timestep;
int Task;
int Index;
#ifdef WITH_ID_IN_HYDRA
int ID;
#endif
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 Volume;
FLOAT DhsmlDensity;
FLOAT Ngb;
#ifdef CHIMIE_KINETIC_FEEDBACK
FLOAT NgbMass;
#endif
}
*StarsDensDataResult, /*!< stores the locally computed SPH density results for imported particles */
*StarsDensDataPartialResult; /*!< imported partial SPH density results from other processors */
#endif /*CHIMIE*/
#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 efcbf81..9bcb83b 100644
--- a/src/begrun.c
+++ b/src/begrun.c
@@ -1,2185 +1,2207 @@
#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
/* 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");
init_cooling_with_metals();
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 abundance %s\t= %g\n",get_Element(i),get_SolarAbundance(i));
}
if(ThisTask == 0) printf("Initialize chimie done...\n");
#endif
-
+
+
#ifdef COOLING
#ifdef CHIMIE
All.CoolingParameters_FeHSolar = get_SolarAbundance(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
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
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 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 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;
All.ThresholdDensity = all.ThresholdDensity;
#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;
#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 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
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);
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 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;
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
#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;
#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);
#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
}
/*! 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(ThisTask != 0) /* only the root processor writes to the log files */
return;
if(RestartFlag == 0)
strcpy(mode, "w");
else
strcpy(mode, "a");
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) /* 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) /* write the header */
{
fprintf(FdEnergy,"# Time EnergyInt EnergyPot EnergyKin ");
#ifdef COOLING
fprintf(FdEnergy,"EnergyRadSph ");
#endif
#ifdef AGN_HEATING
fprintf(FdEnergy,"EnergyAGNHeat ");
#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)
{
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
}
/*! This function closes the global log-files.
*/
void close_outputfiles(void)
{
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 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;
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;
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
#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;
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;
#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 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 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;
#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
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/density.c b/src/density.c
index c259cbe..13648fd 100644
--- a/src/density.c
+++ b/src/density.c
@@ -1,873 +1,880 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <mpi.h>
#include "allvars.h"
#include "proto.h"
/*! \file density.c
* \brief SPH density computation and smoothing length determination
*
* This file contains the "first SPH loop", where the SPH densities and
* some auxiliary quantities are computed. If the number of neighbours
* obtained falls outside the target range, the correct smoothing
* length is determined iteratively, if needed.
*/
#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
/*! This function computes the local density for each active SPH particle,
* the number of neighbours in the current smoothing radius, and the
* divergence and curl of the velocity field. The pressure is updated as
* well. If a particle with its smoothing region is fully inside the
* local domain, it is not exported to the other processors. The function
* also detects particles that have a number of neighbours outside the
* allowed tolerance range. For these particles, the smoothing length is
* adjusted accordingly, and the density computation is executed again.
* Note that the smoothing length is not allowed to fall below the lower
* bound set by MinGasHsml.
*/
void density(int mode)
{
long long ntot, ntotleft;
int *noffset, *nbuffer, *nsend, *nsend_local, *numlist, *ndonelist;
int i, j, n, ndone, npleft, maxfill, source, iter = 0;
int level, ngrp, sendTask, recvTask, place, nexport;
double dt_entr, tstart, tend, tstart_ngb = 0, tend_ngb = 0;
double sumt, sumcomm, timengb, sumtimengb;
double timecomp = 0, timeimbalance = 0, timecommsumm = 0, sumimbalance;
MPI_Status status;
#ifdef DETAILED_CPU_OUTPUT_IN_DENSITY
double *timengblist;
double *timecomplist;
double *timecommsummlist;
double *timeimbalancelist;
#endif
#ifdef DETAILED_CPU
double t0=0,t1=0;
#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 DETAILED_CPU
if (mode==1)
t0 = second();
#endif
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);
for(n = 0, NumSphUpdate = 0; n < N_gas; n++)
{
SphP[n].Left = SphP[n].Right = 0;
#ifdef AVOIDNUMNGBPROBLEM
SphP[n].OldNumNgb = -1;
#endif
#ifdef ART_CONDUCTIVITY
SphP[n].EnergyIntPred = GAMMA_MINUS1*SphP[n].Pressure/SphP[n].Density ;
#endif
#ifdef SFR
if((P[n].Ti_endstep == All.Ti_Current) && (P[n].Type == 0))
#else
if(P[n].Ti_endstep == All.Ti_Current)
#endif
- NumSphUpdate++;
-
+ NumSphUpdate++;
}
numlist = malloc(NTask * sizeof(int) * NTask);
MPI_Allgather(&NumSphUpdate, 1, MPI_INT, numlist, 1, MPI_INT, MPI_COMM_WORLD);
for(i = 0, ntot = 0; i < NTask; i++)
ntot += numlist[i];
free(numlist);
/* we will repeat the whole thing for those particles where we didn't
* find enough neighbours
*/
do
{
i = 0; /* beginn with this index */
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 */
tstart = second();
for(nexport = 0, ndone = 0; i < N_gas && nexport < All.BunchSizeDensity - NTask; i++)
#ifdef SFR
if((P[i].Ti_endstep == All.Ti_Current) && (P[i].Type == 0))
#else
if(P[i].Ti_endstep == All.Ti_Current)
#endif
{
- ndone++;
+ ndone++;
for(j = 0; j < NTask; j++)
Exportflag[j] = 0;
density_evaluate(i, 0);
for(j = 0; j < NTask; j++)
{
if(Exportflag[j])
{
DensDataIn[nexport].Pos[0] = P[i].Pos[0];
DensDataIn[nexport].Pos[1] = P[i].Pos[1];
DensDataIn[nexport].Pos[2] = P[i].Pos[2];
DensDataIn[nexport].Vel[0] = SphP[i].VelPred[0];
DensDataIn[nexport].Vel[1] = SphP[i].VelPred[1];
DensDataIn[nexport].Vel[2] = SphP[i].VelPred[2];
DensDataIn[nexport].Hsml = SphP[i].Hsml;
#ifdef MULTIPHASE
DensDataIn[nexport].Phase = SphP[i].Phase;
#endif
DensDataIn[nexport].Index = i;
DensDataIn[nexport].Task = j;
#ifdef ART_CONDUCTIVITY
DensDataIn[nexport].EnergyIntPred = SphP[i].EnergyIntPred ;
#endif
nexport++;
nsend_local[j]++;
}
}
}
tend = second();
timecomp += timediff(tstart, tend);
qsort(DensDataIn, nexport, sizeof(struct densdata_in), dens_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.BunchSizeDensity)
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(&DensDataIn[noffset[recvTask]],
nsend_local[recvTask] * sizeof(struct densdata_in), MPI_BYTE,
recvTask, TAG_DENS_A,
&DensDataGet[nbuffer[ThisTask]],
nsend[recvTask * NTask + ThisTask] * sizeof(struct densdata_in),
MPI_BYTE, recvTask, TAG_DENS_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);
tstart = second();
for(j = 0; j < nbuffer[ThisTask]; j++)
density_evaluate(j, 1);
tend = second();
timecomp += timediff(tstart, tend);
/* do a block to explicitly 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.BunchSizeDensity)
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(&DensDataResult[nbuffer[ThisTask]],
nsend[recvTask * NTask + ThisTask] * sizeof(struct densdata_out),
MPI_BYTE, recvTask, TAG_DENS_B,
&DensDataPartialResult[noffset[recvTask]],
nsend_local[recvTask] * sizeof(struct densdata_out),
MPI_BYTE, recvTask, TAG_DENS_B, MPI_COMM_WORLD, &status);
/* add the result to the particles */
for(j = 0; j < nsend_local[recvTask]; j++)
{
source = j + noffset[recvTask];
place = DensDataIn[source].Index;
SphP[place].NumNgb += DensDataPartialResult[source].Ngb;
SphP[place].Density += DensDataPartialResult[source].Rho;
SphP[place].DivVel += DensDataPartialResult[source].Div;
SphP[place].DhsmlDensityFactor += DensDataPartialResult[source].DhsmlDensity;
#ifdef DENSITY_INDEPENDENT_SPH
SphP[place].EgyWtDensity += DensDataPartialResult[source].EgyRho;
SphP[place].DhsmlEgyDensityFactor += DensDataPartialResult[source].DhsmlEgyDensity;
#endif
SphP[place].Rot[0] += DensDataPartialResult[source].Rot[0];
SphP[place].Rot[1] += DensDataPartialResult[source].Rot[1];
SphP[place].Rot[2] += DensDataPartialResult[source].Rot[2];
#ifdef ART_CONDUCTIVITY
SphP[place].GradEnergyInt[0] += DensDataPartialResult[source].GradEnergyInt[0];
SphP[place].GradEnergyInt[1] += DensDataPartialResult[source].GradEnergyInt[1];
SphP[place].GradEnergyInt[2] += DensDataPartialResult[source].GradEnergyInt[2];
#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];
}
-
-
/* do final operations on results */
tstart = second();
for(i = 0, npleft = 0; i < N_gas; i++)
{
#ifdef SFR
if((P[i].Ti_endstep == All.Ti_Current) && (P[i].Type == 0))
#else
if(P[i].Ti_endstep == All.Ti_Current)
#endif
{
{
/* this two following lines where the old Gadget-2 version */
//SphP[i].DhsmlDensityFactor =
// 1 / (1 + SphP[i].Hsml * SphP[i].DhsmlDensityFactor / (NUMDIMS * SphP[i].Density));
/* they are replaced by the next ones, from Hopkins */
SphP[i].DhsmlDensityFactor *= SphP[i].Hsml / (NUMDIMS * SphP[i].Density);
if (SphP[i].DhsmlDensityFactor > -0.9)
{
SphP[i].DhsmlDensityFactor = 1 / (1 + SphP[i].DhsmlDensityFactor);
} else {
SphP[i].DhsmlDensityFactor = 1;
}
#ifdef DENSITY_INDEPENDENT_SPH
if((SphP[i].EntVarPred>0)&&(SphP[i].EgyWtDensity>0))
{
SphP[i].DhsmlEgyDensityFactor *= SphP[i].Hsml/ (NUMDIMS * SphP[i].EgyWtDensity);
SphP[i].DhsmlEgyDensityFactor *= -SphP[i].DhsmlDensityFactor;
SphP[i].EgyWtDensity /= SphP[i].EntVarPred;
} else {
SphP[i].DhsmlEgyDensityFactor=0; SphP[i].EntVarPred=0; SphP[i].EgyWtDensity=0;
}
#endif
SphP[i].CurlVel = sqrt(SphP[i].Rot[0] * SphP[i].Rot[0] +
SphP[i].Rot[1] * SphP[i].Rot[1] +
SphP[i].Rot[2] * SphP[i].Rot[2]) / SphP[i].Density;
SphP[i].DivVel /= SphP[i].Density;
dt_entr = (All.Ti_Current - (P[i].Ti_begstep + P[i].Ti_endstep) / 2) * All.Timebase_interval;
#ifdef DENSITY_INDEPENDENT_SPH
SphP[i].Pressure = pow(SphP[i].EntVarPred*SphP[i].EgyWtDensity,GAMMA);
#else
SphP[i].Pressure =
(SphP[i].Entropy + SphP[i].DtEntropy * dt_entr) * pow(SphP[i].Density, GAMMA);
#endif
#ifdef ART_CONDUCTIVITY
SphP[i].GradEnergyInt[0] /= SphP[i].Density;
SphP[i].GradEnergyInt[1] /= SphP[i].Density;
SphP[i].GradEnergyInt[2] /= SphP[i].Density;
#endif
}
/* now check whether we had enough neighbours */
if(SphP[i].NumNgb < (All.DesNumNgb - All.MaxNumNgbDeviation) ||
(SphP[i].NumNgb > (All.DesNumNgb + All.MaxNumNgbDeviation)
&& SphP[i].Hsml > (1.01 * All.MinGasHsml)))
{
#ifdef AVOIDNUMNGBPROBLEM
// if((SphP[i].NumNgb>SphP[i].OldNumNgb-All.MaxNumNgbDeviation/10000.)
// &&(SphP[i].NumNgb<SphP[i].OldNumNgb+All.MaxNumNgbDeviation/10000.))
if(SphP[i].NumNgb==SphP[i].OldNumNgb)
{
P[i].Ti_endstep = -P[i].Ti_endstep - 1;
printf("ID=%d NumNgb=%g OldNumNgb=%g\n",P[i].ID,SphP[i].NumNgb,SphP[i].OldNumNgb);
continue;
}
SphP[i].OldNumNgb = SphP[i].NumNgb;
#endif
/* need to redo this particle */
npleft++;
if(SphP[i].Left > 0 && SphP[i].Right > 0)
if((SphP[i].Right - SphP[i].Left) < 1.0e-3 * SphP[i].Left)
{
/* this one should be ok */
npleft--;
P[i].Ti_endstep = -P[i].Ti_endstep - 1; /* Mark as inactive */
continue;
}
if(SphP[i].NumNgb < (All.DesNumNgb - All.MaxNumNgbDeviation))
SphP[i].Left = dmax(SphP[i].Hsml, SphP[i].Left);
else
{
if(SphP[i].Right != 0)
{
if(SphP[i].Hsml < SphP[i].Right)
SphP[i].Right = SphP[i].Hsml;
}
else
SphP[i].Right = SphP[i].Hsml;
}
if(iter >= MAXITER - 10)
{
printf
("i=%d task=%d ID=%d Hsml=%g Left=%g Right=%g Ngbs=%g Right-Left=%g\n pos=(%g|%g|%g)\n",
i, ThisTask, (int) P[i].ID, SphP[i].Hsml, SphP[i].Left, SphP[i].Right,
(float) SphP[i].NumNgb, SphP[i].Right - SphP[i].Left, P[i].Pos[0], P[i].Pos[1],
P[i].Pos[2]);
fflush(stdout);
}
if(SphP[i].Right > 0 && SphP[i].Left > 0)
SphP[i].Hsml = pow(0.5 * (pow(SphP[i].Left, 3) + pow(SphP[i].Right, 3)), 1.0 / 3);
else
{
if(SphP[i].Right == 0 && SphP[i].Left == 0)
{
printf
("i=%d task=%d ID=%d Hsml=%g Left=%g Right=%g Ngbs=%g Right-Left=%g\n pos=(%g|%g|%g)\n",
i, ThisTask, (int) P[i].ID, SphP[i].Hsml, SphP[i].Left, SphP[i].Right,
(float) SphP[i].NumNgb, SphP[i].Right - SphP[i].Left, P[i].Pos[0], P[i].Pos[1],
P[i].Pos[2]);
fflush(stdout);
endrun(8188); /* can't occur */
}
if(SphP[i].Right == 0 && SphP[i].Left > 0)
{
if(P[i].Type == 0 && fabs(SphP[i].NumNgb - All.DesNumNgb) < 0.5 * All.DesNumNgb)
{
SphP[i].Hsml *=
1 - (SphP[i].NumNgb -
All.DesNumNgb) / (NUMDIMS * SphP[i].NumNgb) * SphP[i].DhsmlDensityFactor;
}
else
SphP[i].Hsml *= 1.26;
}
if(SphP[i].Right > 0 && SphP[i].Left == 0)
{
if(P[i].Type == 0 && fabs(SphP[i].NumNgb - All.DesNumNgb) < 0.5 * All.DesNumNgb)
{
SphP[i].Hsml *=
1 - (SphP[i].NumNgb -
All.DesNumNgb) / (NUMDIMS * SphP[i].NumNgb) * SphP[i].DhsmlDensityFactor;
}
else
SphP[i].Hsml /= 1.26;
}
}
if(SphP[i].Hsml < All.MinGasHsml)
SphP[i].Hsml = All.MinGasHsml;
}
else
P[i].Ti_endstep = -P[i].Ti_endstep - 1; /* Mark as inactive */
}
}
tend = second();
timecomp += timediff(tstart, tend);
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)
{
if(iter == 0)
tstart_ngb = second();
iter++;
if(iter > 0 && ThisTask == 0)
{
printf("ngb iteration %d: need to repeat for %d%09d particles.\n", iter,
(int) (ntot / 1000000000), (int) (ntot % 1000000000));
fflush(stdout);
}
if(iter > MAXITER)
{
printf("failed to converge in neighbour iteration in density()\n");
fflush(stdout);
endrun(1155);
}
}
else
tend_ngb = second();
}
- while(ntot > 0);
-
+ while(ntot > 0);
-
/* mark as active again */
for(i = 0; i < NumPart; i++)
if(P[i].Ti_endstep < 0)
- P[i].Ti_endstep = -P[i].Ti_endstep - 1;
+#ifdef GAS_ACCRETION
+ if (P[i].Mass!=0)
+#endif
+ P[i].Ti_endstep = -P[i].Ti_endstep - 1;
+
+
free(ndonelist);
free(nsend);
free(nsend_local);
free(nbuffer);
free(noffset);
/* collect some timing information */
if(iter > 0)
timengb = timediff(tstart_ngb, tend_ngb);
else
timengb = 0;
MPI_Reduce(&timengb, &sumtimengb, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
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);
#ifdef DETAILED_CPU_OUTPUT_IN_DENSITY
numlist = malloc(sizeof(int) * NTask);
timengblist = malloc(sizeof(double) * NTask);
timecomplist = malloc(sizeof(double) * NTask);
timecommsummlist = malloc(sizeof(double) * NTask);
timeimbalancelist = malloc(sizeof(double) * NTask);
MPI_Gather(&NumSphUpdate, 1, MPI_INT, numlist, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Gather(&timengb, 1, MPI_DOUBLE, timengblist, 1, MPI_DOUBLE, 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 density (mode=%d)\n\n",mode);
fprintf(FdTimings, "Nupdate ");
for (i=0;i<NTask;i++)
fprintf(FdTimings, "%12d ",numlist[i]);
fprintf(FdTimings, "\n");
fprintf(FdTimings, "timengb ");
for (i=0;i<NTask;i++)
fprintf(FdTimings, "%12g ",timengblist[i]);
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
#ifdef DETAILED_CPU
if (mode==1)
{
t1 = second();
All.CPU_StarFormation += timediff(t0, t1);
}
else
if(ThisTask == 0)
{
All.CPU_HydCompWalk += sumt / NTask;
All.CPU_HydCommSumm += sumcomm / NTask;
All.CPU_HydImbalance += sumimbalance / NTask;
All.CPU_EnsureNgb += sumtimengb / NTask;
}
#else
if(ThisTask == 0)
{
All.CPU_HydCompWalk += sumt / NTask;
All.CPU_HydCommSumm += sumcomm / NTask;
All.CPU_HydImbalance += sumimbalance / NTask;
All.CPU_EnsureNgb += sumtimengb / NTask;
}
#endif
+
+
+#ifdef GAS_ACCRETION
+update_entropy_for_accreated_particles();
+#endif
+
+
}
/*! This function represents the core of the SPH density computation. The
* target particle may either be local, or reside in the communication
* buffer.
*/
void density_evaluate(int target, int mode)
{
int j, n, startnode, numngb, numngb_inbox;
double h, h2, fac, hinv, hinv3, hinv4;
double rho, divv, wk, dwk;
double dx, dy, dz, r, r2, u, mass_j;
double dvx, dvy, dvz, rotv[3];
double weighted_numngb, dhsmlrho;
FLOAT *pos, *vel;
int phase=0;
#ifdef DENSITY_INDEPENDENT_SPH
double egyrho, dhsmlegyrho;
#endif
#ifdef ART_CONDUCTIVITY
double gradux, graduy, graduz;
double energyintpred;
#endif
if(mode == 0)
{
pos = P[target].Pos;
vel = SphP[target].VelPred;
h = SphP[target].Hsml;
#ifdef MULTIPHASE
phase = SphP[target].Phase;
#endif
#ifdef ART_CONDUCTIVITY
energyintpred = SphP[target].EnergyIntPred;
#endif
}
else
{
pos = DensDataGet[target].Pos;
vel = DensDataGet[target].Vel;
h = DensDataGet[target].Hsml;
#ifdef MULTIPHASE
phase = DensDataGet[target].Phase;
#endif
#ifdef ART_CONDUCTIVITY
energyintpred = DensDataGet[target].EnergyIntPred;
#endif
}
h2 = h * h;
hinv = 1.0 / h;
#ifndef TWODIMS
hinv3 = hinv * hinv * hinv;
#else
hinv3 = hinv * hinv / boxSize_Z;
#endif
hinv4 = hinv3 * hinv;
rho = divv = rotv[0] = rotv[1] = rotv[2] = 0;
weighted_numngb = 0;
dhsmlrho = 0;
#ifdef ART_CONDUCTIVITY
gradux=graduy=graduz=0;
#endif
#ifdef DENSITY_INDEPENDENT_SPH
egyrho=0; dhsmlegyrho=0;
#endif
startnode = All.MaxPart;
numngb = 0;
do
{
numngb_inbox = ngb_treefind_variable(&pos[0], h, phase, &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);
dwk = hinv4 * u * (KERNEL_COEFF_3 * u - KERNEL_COEFF_4);
}
else
{
wk = hinv3 * KERNEL_COEFF_5 * (1.0 - u) * (1.0 - u) * (1.0 - u);
dwk = hinv4 * KERNEL_COEFF_6 * (1.0 - u) * (1.0 - u);
}
mass_j = P[j].Mass;
rho += mass_j * wk;
weighted_numngb += NORM_COEFF * wk / hinv3;
dhsmlrho += -mass_j * (NUMDIMS * hinv * wk + u * dwk);
#ifdef DENSITY_INDEPENDENT_SPH
egyrho += mass_j * SphP[j].EntVarPred * wk;
dhsmlegyrho += -mass_j * SphP[j].EntVarPred * (NUMDIMS * hinv * wk + u * dwk);
#endif
if(r > 0)
{
fac = mass_j * dwk / r;
dvx = vel[0] - SphP[j].VelPred[0];
dvy = vel[1] - SphP[j].VelPred[1];
dvz = vel[2] - SphP[j].VelPred[2];
divv -= fac * (dx * dvx + dy * dvy + dz * dvz);
rotv[0] += fac * (dz * dvy - dy * dvz);
rotv[1] += fac * (dx * dvz - dz * dvx);
rotv[2] += fac * (dy * dvx - dx * dvy);
#ifdef ART_CONDUCTIVITY
if (All.NumCurrentTiStep==0)
fac = 0;
gradux += fac * (energyintpred-SphP[j].EnergyIntPred)*dx;
graduy += fac * (energyintpred-SphP[j].EnergyIntPred)*dy;
graduz += fac * (energyintpred-SphP[j].EnergyIntPred)*dz;
#endif
}
}
}
}
while(startnode >= 0);
if(mode == 0)
{
SphP[target].NumNgb = weighted_numngb;
SphP[target].Density = rho;
SphP[target].DivVel = divv;
SphP[target].DhsmlDensityFactor = dhsmlrho;
SphP[target].Rot[0] = rotv[0];
SphP[target].Rot[1] = rotv[1];
SphP[target].Rot[2] = rotv[2];
#ifdef ART_CONDUCTIVITY
SphP[target].GradEnergyInt[0] = gradux;
SphP[target].GradEnergyInt[1] = graduy;
SphP[target].GradEnergyInt[2] = graduz;
#endif
#ifdef DENSITY_INDEPENDENT_SPH
SphP[target].EgyWtDensity = egyrho;
SphP[target].DhsmlEgyDensityFactor = dhsmlegyrho;
#endif
}
else
{
DensDataResult[target].Rho = rho;
DensDataResult[target].Div = divv;
DensDataResult[target].Ngb = weighted_numngb;
DensDataResult[target].DhsmlDensity = dhsmlrho;
DensDataResult[target].Rot[0] = rotv[0];
DensDataResult[target].Rot[1] = rotv[1];
DensDataResult[target].Rot[2] = rotv[2];
#ifdef ART_CONDUCTIVITY
DensDataResult[target].GradEnergyInt[0] = gradux;
DensDataResult[target].GradEnergyInt[1] = graduy;
DensDataResult[target].GradEnergyInt[2] = graduz;
#endif
#ifdef DENSITY_INDEPENDENT_SPH
DensDataResult[target].EgyRho = egyrho;
DensDataResult[target].DhsmlEgyDensity = dhsmlegyrho;
#endif
}
}
/*! This routine is a comparison kernel used in a sort routine to group
* particles that are exported to the same processor.
*/
int dens_compare_key(const void *a, const void *b)
{
if(((struct densdata_in *) a)->Task < (((struct densdata_in *) b)->Task))
return -1;
if(((struct densdata_in *) a)->Task > (((struct densdata_in *) b)->Task))
return +1;
return 0;
}
diff --git a/src/forcetree.c b/src/forcetree.c
index d2f1c09..f09f8bf 100644
--- a/src/forcetree.c
+++ b/src/forcetree.c
@@ -1,3396 +1,3407 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <mpi.h>
#include "allvars.h"
#include "proto.h"
/*! \file forcetree.c
* \brief gravitational tree and code for Ewald correction
*
* This file contains the computation of the gravitational force by means
* of a tree. The type of tree implemented is a geometrical oct-tree,
* starting from a cube encompassing all particles. This cube is
* automatically found in the domain decomposition, which also splits up
* the global "top-level" tree along node boundaries, moving the particles
* of different parts of the tree to separate processors. Tree nodes can
* be dynamically updated in drift/kick operations to avoid having to
* reconstruct the tree every timestep.
*/
/*! auxialiary variable used to set-up non-recursive walk */
static int last;
/*! length of lock-up table for short-range force kernel in TreePM algorithm */
#define NTAB 1000
/*! variables for short-range lookup table */
static float tabfac, shortrange_table[NTAB], shortrange_table_potential[NTAB];
/*! toggles after first tree-memory allocation, has only influence on log-files */
static int first_flag = 0;
#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
/*! This function is a driver routine for constructing the gravitational
* oct-tree, which is done by calling a small number of other functions.
*/
int force_treebuild(int npart)
{
Numnodestree = force_treebuild_single(npart);
force_update_pseudoparticles();
force_flag_localnodes();
TimeOfLastTreeConstruction = All.Time;
return Numnodestree;
}
/*! Constructs the gravitational oct-tree.
*
* The index convention for accessing tree nodes is the following: the
* indices 0...NumPart-1 reference single particles, the indices
* All.MaxPart.... All.MaxPart+nodes-1 reference tree nodes. `Nodes_base'
* points to the first tree node, while `nodes' is shifted such that
* nodes[All.MaxPart] gives the first tree node. Finally, node indices
* with values 'All.MaxPart + MaxNodes' and larger indicate "pseudo
* particles", i.e. multipole moments of top-level nodes that lie on
* different CPUs. If such a node needs to be opened, the corresponding
* particle must be exported to that CPU. The 'Extnodes' structure
* parallels that of 'Nodes'. Its information is only needed for the SPH
* part of the computation. (The data is split onto these two structures
* as a tuning measure. If it is merged into 'Nodes' a somewhat bigger
* size of the nodes also for gravity would result, which would reduce
* cache utilization slightly.
*/
int force_treebuild_single(int npart)
{
int i, j, subnode = 0, parent, numnodes;
int nfree, th, nn, no;
struct NODE *nfreep;
double lenhalf, epsilon;
peanokey key;
/* create an empty root node */
nfree = All.MaxPart; /* index of first free node */
nfreep = &Nodes[nfree]; /* select first node */
nfreep->len = DomainLen;
for(j = 0; j < 3; j++)
nfreep->center[j] = DomainCenter[j];
for(j = 0; j < 8; j++)
nfreep->u.suns[j] = -1;
numnodes = 1;
nfreep++;
nfree++;
/* create a set of empty nodes corresponding to the top-level domain
* grid. We need to generate these nodes first to make sure that we have a
* complete top-level tree which allows the easy insertion of the
* pseudo-particles at the right place
*/
force_create_empty_nodes(All.MaxPart, 0, 1, 0, 0, 0, &numnodes, &nfree);
/* if a high-resolution region in a global tree is used, we need to generate
* an additional set empty nodes to make sure that we have a complete
* top-level tree for the high-resolution inset
*/
nfreep = &Nodes[nfree];
parent = -1; /* note: will not be used below before it is changed */
/* now we insert all particles */
for(i = 0; i < npart; i++)
{
+#ifdef GAS_ACCRETION
+ if (P[i].Mass==0)
+ continue;
+#endif
+
+
/* the softening is only used to check whether particles are so close
* that the tree needs not to be refined further
*/
epsilon = All.ForceSoftening[P[i].Type];
key = peano_hilbert_key((P[i].Pos[0] - DomainCorner[0]) * DomainFac,
(P[i].Pos[1] - DomainCorner[1]) * DomainFac,
(P[i].Pos[2] - DomainCorner[2]) * DomainFac, BITS_PER_DIMENSION);
no = 0;
while(TopNodes[no].Daughter >= 0)
no = TopNodes[no].Daughter + (key - TopNodes[no].StartKey) / (TopNodes[no].Size / 8);
no = TopNodes[no].Leaf;
th = DomainNodeIndex[no];
while(1)
{
if(th >= All.MaxPart) /* we are dealing with an internal node */
{
subnode = 0;
if(P[i].Pos[0] > Nodes[th].center[0])
subnode += 1;
if(P[i].Pos[1] > Nodes[th].center[1])
subnode += 2;
if(P[i].Pos[2] > Nodes[th].center[2])
subnode += 4;
nn = Nodes[th].u.suns[subnode];
if(nn >= 0) /* ok, something is in the daughter slot already, need to continue */
{
parent = th;
th = nn;
}
else
{
/* here we have found an empty slot where we can attach
* the new particle as a leaf.
*/
Nodes[th].u.suns[subnode] = i;
break; /* done for this particle */
}
}
else
{
/* We try to insert into a leaf with a single particle. Need
* to generate a new internal node at this point.
*/
Nodes[parent].u.suns[subnode] = nfree;
nfreep->len = 0.5 * Nodes[parent].len;
lenhalf = 0.25 * Nodes[parent].len;
if(subnode & 1)
nfreep->center[0] = Nodes[parent].center[0] + lenhalf;
else
nfreep->center[0] = Nodes[parent].center[0] - lenhalf;
if(subnode & 2)
nfreep->center[1] = Nodes[parent].center[1] + lenhalf;
else
nfreep->center[1] = Nodes[parent].center[1] - lenhalf;
if(subnode & 4)
nfreep->center[2] = Nodes[parent].center[2] + lenhalf;
else
nfreep->center[2] = Nodes[parent].center[2] - lenhalf;
nfreep->u.suns[0] = -1;
nfreep->u.suns[1] = -1;
nfreep->u.suns[2] = -1;
nfreep->u.suns[3] = -1;
nfreep->u.suns[4] = -1;
nfreep->u.suns[5] = -1;
nfreep->u.suns[6] = -1;
nfreep->u.suns[7] = -1;
subnode = 0;
if(P[th].Pos[0] > nfreep->center[0])
subnode += 1;
if(P[th].Pos[1] > nfreep->center[1])
subnode += 2;
if(P[th].Pos[2] > nfreep->center[2])
subnode += 4;
#ifndef NOTREERND
if(nfreep->len < 1.0e-3 * epsilon)
{
/* seems like we're dealing with particles at identical (or extremely close)
* locations. Randomize subnode index to allow tree construction. Note: Multipole moments
* of tree are still correct, but this will only happen well below gravitational softening
* length-scale anyway.
*/
subnode = (int) (8.0 * get_random_number((0xffff & P[i].ID) + P[i].GravCost));
P[i].GravCost += 1;
if(subnode >= 8)
subnode = 7;
}
#endif
nfreep->u.suns[subnode] = th;
th = nfree; /* resume trying to insert the new particle at
* the newly created internal node
*/
numnodes++;
nfree++;
nfreep++;
if((numnodes) >= MaxNodes)
{
printf("task %d: maximum number %d of tree-nodes reached.\n", ThisTask, MaxNodes);
printf("for particle %d\n", i);
dump_particles();
endrun(1);
}
}
}
}
/* insert the pseudo particles that represent the mass distribution of other domains */
force_insert_pseudo_particles();
/* now compute the multipole moments recursively */
last = -1;
force_update_node_recursive(All.MaxPart, -1, -1);
if(last >= All.MaxPart)
{
if(last >= All.MaxPart + MaxNodes) /* a pseudo-particle */
Nextnode[last - MaxNodes] = -1;
else
Nodes[last].u.d.nextnode = -1;
}
else
Nextnode[last] = -1;
return numnodes;
}
/*! This function recursively creates a set of empty tree nodes which
* corresponds to the top-level tree for the domain grid. This is done to
* ensure that this top-level tree is always "complete" so that we can
* easily associate the pseudo-particles of other CPUs with tree-nodes at
* a given level in the tree, even when the particle population is so
* sparse that some of these nodes are actually empty.
*/
void force_create_empty_nodes(int no, int topnode, int bits, int x, int y, int z, int *nodecount,
int *nextfree)
{
int i, j, k, n, sub, count;
if(TopNodes[topnode].Daughter >= 0)
{
for(i = 0; i < 2; i++)
for(j = 0; j < 2; j++)
for(k = 0; k < 2; k++)
{
sub = 7 & peano_hilbert_key((x << 1) + i, (y << 1) + j, (z << 1) + k, bits);
count = i + 2 * j + 4 * k;
Nodes[no].u.suns[count] = *nextfree;
Nodes[*nextfree].len = 0.5 * Nodes[no].len;
Nodes[*nextfree].center[0] = Nodes[no].center[0] + (2 * i - 1) * 0.25 * Nodes[no].len;
Nodes[*nextfree].center[1] = Nodes[no].center[1] + (2 * j - 1) * 0.25 * Nodes[no].len;
Nodes[*nextfree].center[2] = Nodes[no].center[2] + (2 * k - 1) * 0.25 * Nodes[no].len;
for(n = 0; n < 8; n++)
Nodes[*nextfree].u.suns[n] = -1;
if(TopNodes[TopNodes[topnode].Daughter + sub].Daughter == -1)
DomainNodeIndex[TopNodes[TopNodes[topnode].Daughter + sub].Leaf] = *nextfree;
*nextfree = *nextfree + 1;
*nodecount = *nodecount + 1;
if((*nodecount) >= MaxNodes)
{
printf("task %d: maximum number %d of tree-nodes reached.\n", ThisTask, MaxNodes);
printf("in create empty nodes\n");
dump_particles();
endrun(11);
}
force_create_empty_nodes(*nextfree - 1, TopNodes[topnode].Daughter + sub,
bits + 1, 2 * x + i, 2 * y + j, 2 * z + k, nodecount, nextfree);
}
}
}
/*! this function inserts pseudo-particles which will represent the mass
* distribution of the other CPUs. Initially, the mass of the
* pseudo-particles is set to zero, and their coordinate is set to the
* center of the domain-cell they correspond to. These quantities will be
* updated later on.
*/
void force_insert_pseudo_particles(void)
{
int i, index, subnode, nn, th;
for(i = 0; i < NTopleaves; i++)
{
index = DomainNodeIndex[i];
DomainMoment[i].mass = 0;
#ifdef STELLAR_FLUX
DomainMoment[i].starlum = 0;
#endif
DomainMoment[i].s[0] = Nodes[index].center[0];
DomainMoment[i].s[1] = Nodes[index].center[1];
DomainMoment[i].s[2] = Nodes[index].center[2];
}
for(i = 0; i < NTopleaves; i++)
{
if(i < DomainMyStart || i > DomainMyLast)
{
th = All.MaxPart; /* select index of first node in tree */
while(1)
{
if(th >= All.MaxPart) /* we are dealing with an internal node */
{
if(th >= All.MaxPart + MaxNodes)
endrun(888); /* this can't be */
subnode = 0;
if(DomainMoment[i].s[0] > Nodes[th].center[0])
subnode += 1;
if(DomainMoment[i].s[1] > Nodes[th].center[1])
subnode += 2;
if(DomainMoment[i].s[2] > Nodes[th].center[2])
subnode += 4;
nn = Nodes[th].u.suns[subnode];
if(nn >= 0) /* ok, something is in the daughter slot already, need to continue */
{
th = nn;
}
else
{
/* here we have found an empty slot where we can
* attach the pseudo particle as a leaf
*/
Nodes[th].u.suns[subnode] = All.MaxPart + MaxNodes + i;
break; /* done for this pseudo particle */
}
}
else
{
endrun(889); /* this can't be */
}
}
}
}
}
/*! this routine determines the multipole moments for a given internal node
* and all its subnodes using a recursive computation. The result is
* stored in the Nodes[] structure in the sequence of this tree-walk.
*
* Note that the bitflags-variable for each node is used to store in the
* lowest bits some special information: Bit 0 flags whether the node
* belongs to the top-level tree corresponding to the domain
* decomposition, while Bit 1 signals whether the top-level node is
* dependent on local mass.
*
* If UNEQUALSOFTENINGS is set, bits 2-4 give the particle type with
* the maximum softening among the particles in the node, and bit 5
* flags whether the node contains any particles with lower softening
* than that.
*/
void force_update_node_recursive(int no, int sib, int father)
{
int j, jj, p, pp, nextsib, suns[8];
FLOAT hmax;
#ifdef UNEQUALSOFTENINGS
#ifndef ADAPTIVE_GRAVSOFT_FORGAS
int maxsofttype, diffsoftflag;
#else
FLOAT maxsoft;
#endif
#endif
struct particle_data *pa;
double s[3], vs[3], mass;
#ifdef STELLAR_FLUX
double starlum;
#endif
if(no >= All.MaxPart && no < All.MaxPart + MaxNodes) /* internal node */
{
for(j = 0; j < 8; j++)
suns[j] = Nodes[no].u.suns[j]; /* this "backup" is necessary because the nextnode entry will
overwrite one element (union!) */
if(last >= 0)
{
if(last >= All.MaxPart)
{
if(last >= All.MaxPart + MaxNodes) /* a pseudo-particle */
Nextnode[last - MaxNodes] = no;
else
Nodes[last].u.d.nextnode = no;
}
else
Nextnode[last] = no;
}
last = no;
mass = 0;
#ifdef STELLAR_FLUX
starlum = 0;
#endif
s[0] = 0;
s[1] = 0;
s[2] = 0;
vs[0] = 0;
vs[1] = 0;
vs[2] = 0;
hmax = 0;
#ifdef UNEQUALSOFTENINGS
#ifndef ADAPTIVE_GRAVSOFT_FORGAS
maxsofttype = 7;
diffsoftflag = 0;
#else
maxsoft = 0;
#endif
#endif
for(j = 0; j < 8; j++)
{
if((p = suns[j]) >= 0)
{
/* check if we have a sibling on the same level */
for(jj = j + 1; jj < 8; jj++)
if((pp = suns[jj]) >= 0)
break;
if(jj < 8) /* yes, we do */
nextsib = pp;
else
nextsib = sib;
force_update_node_recursive(p, nextsib, no);
if(p >= All.MaxPart) /* an internal node or pseudo particle */
{
if(p >= All.MaxPart + MaxNodes) /* a pseudo particle */
{
/* nothing to be done here because the mass of the
* pseudo-particle is still zero. This will be changed
* later.
*/
}
else
{
mass += Nodes[p].u.d.mass;
#ifdef STELLAR_FLUX
starlum += Nodes[p].starlum;
#endif
s[0] += Nodes[p].u.d.mass * Nodes[p].u.d.s[0];
s[1] += Nodes[p].u.d.mass * Nodes[p].u.d.s[1];
s[2] += Nodes[p].u.d.mass * Nodes[p].u.d.s[2];
vs[0] += Nodes[p].u.d.mass * Extnodes[p].vs[0];
vs[1] += Nodes[p].u.d.mass * Extnodes[p].vs[1];
vs[2] += Nodes[p].u.d.mass * Extnodes[p].vs[2];
if(Extnodes[p].hmax > hmax)
hmax = Extnodes[p].hmax;
#ifdef UNEQUALSOFTENINGS
#ifndef ADAPTIVE_GRAVSOFT_FORGAS
diffsoftflag |= (Nodes[p].u.d.bitflags >> 5) & 1;
if(maxsofttype == 7)
{
maxsofttype = (Nodes[p].u.d.bitflags >> 2) & 7;
}
else
{
if(((Nodes[p].u.d.bitflags >> 2) & 7) != 7)
{
if(All.ForceSoftening[((Nodes[p].u.d.bitflags >> 2) & 7)] >
All.ForceSoftening[maxsofttype])
{
maxsofttype = ((Nodes[p].u.d.bitflags >> 2) & 7);
diffsoftflag = 1;
}
else
{
if(All.ForceSoftening[((Nodes[p].u.d.bitflags >> 2) & 7)] <
All.ForceSoftening[maxsofttype])
diffsoftflag = 1;
}
}
}
#else
if(Nodes[p].maxsoft > maxsoft)
maxsoft = Nodes[p].maxsoft;
#endif
#endif
}
}
else /* a particle */
{
pa = &P[p];
mass += pa->Mass;
#ifdef STELLAR_FLUX
starlum += pa->Mass*All.HeatingPeLMRatio[pa->Type];
#endif
s[0] += pa->Mass * pa->Pos[0];
s[1] += pa->Mass * pa->Pos[1];
s[2] += pa->Mass * pa->Pos[2];
vs[0] += pa->Mass * pa->Vel[0];
vs[1] += pa->Mass * pa->Vel[1];
vs[2] += pa->Mass * pa->Vel[2];
#ifdef UNEQUALSOFTENINGS
#ifndef ADAPTIVE_GRAVSOFT_FORGAS
if(maxsofttype == 7)
{
maxsofttype = pa->Type;
}
else
{
if(All.ForceSoftening[pa->Type] > All.ForceSoftening[maxsofttype])
{
maxsofttype = pa->Type;
diffsoftflag = 1;
}
else
{
if(All.ForceSoftening[pa->Type] < All.ForceSoftening[maxsofttype])
diffsoftflag = 1;
}
}
#else
if(pa->Type == 0)
{
if(SphP[p].Hsml > maxsoft)
maxsoft = SphP[p].Hsml;
}
else
{
if(All.ForceSoftening[pa->Type] > maxsoft)
maxsoft = All.ForceSoftening[pa->Type];
}
#endif
#endif
if(pa->Type == 0)
if(SphP[p].Hsml > hmax)
hmax = SphP[p].Hsml;
}
}
}
if(mass)
{
s[0] /= mass;
s[1] /= mass;
s[2] /= mass;
vs[0] /= mass;
vs[1] /= mass;
vs[2] /= mass;
}
else
{
s[0] = Nodes[no].center[0];
s[1] = Nodes[no].center[1];
s[2] = Nodes[no].center[2];
}
Nodes[no].u.d.s[0] = s[0];
Nodes[no].u.d.s[1] = s[1];
Nodes[no].u.d.s[2] = s[2];
Nodes[no].u.d.mass = mass;
#ifdef STELLAR_FLUX
Nodes[no].starlum = starlum;
#endif
#ifdef UNEQUALSOFTENINGS
#ifndef ADAPTIVE_GRAVSOFT_FORGAS
Nodes[no].u.d.bitflags = 4 * maxsofttype + 32 * diffsoftflag;
#else
Nodes[no].u.d.bitflags = 0;
Nodes[no].maxsoft = maxsoft;
#endif
#else
Nodes[no].u.d.bitflags = 0;
#endif
Extnodes[no].vs[0] = vs[0];
Extnodes[no].vs[1] = vs[1];
Extnodes[no].vs[2] = vs[2];
Extnodes[no].hmax = hmax;
Nodes[no].u.d.sibling = sib;
Nodes[no].u.d.father = father;
}
else /* single particle or pseudo particle */
{
if(last >= 0)
{
if(last >= All.MaxPart)
{
if(last >= All.MaxPart + MaxNodes) /* a pseudo-particle */
Nextnode[last - MaxNodes] = no;
else
Nodes[last].u.d.nextnode = no;
}
else
Nextnode[last] = no;
}
last = no;
if(no < All.MaxPart) /* only set it for single particles */
Father[no] = father;
}
}
/*! This function updates the multipole moments of the pseudo-particles
* that represent the mass distribution on different CPUs. For that
* purpose, it first exchanges the necessary data, and then updates the
* top-level tree accordingly. The detailed implementation of these two
* tasks is done in separate functions.
*/
void force_update_pseudoparticles(void)
{
force_exchange_pseudodata();
force_treeupdate_pseudos();
}
/*! This function communicates the values of the multipole moments of the
* top-level tree-nodes of the domain grid. This data can then be used to
* update the pseudo-particles on each CPU accordingly.
*/
void force_exchange_pseudodata(void)
{
int i, no;
MPI_Status status;
int level, sendTask, recvTask;
for(i = DomainMyStart; i <= DomainMyLast; i++)
{
no = DomainNodeIndex[i];
/* read out the multipole moments from the local base cells */
DomainMoment[i].s[0] = Nodes[no].u.d.s[0];
DomainMoment[i].s[1] = Nodes[no].u.d.s[1];
DomainMoment[i].s[2] = Nodes[no].u.d.s[2];
DomainMoment[i].vs[0] = Extnodes[no].vs[0];
DomainMoment[i].vs[1] = Extnodes[no].vs[1];
DomainMoment[i].vs[2] = Extnodes[no].vs[2];
DomainMoment[i].mass = Nodes[no].u.d.mass;
#ifdef STELLAR_FLUX
DomainMoment[i].starlum = Nodes[no].starlum;
#endif
#ifdef UNEQUALSOFTENINGS
#ifndef ADAPTIVE_GRAVSOFT_FORGAS
DomainMoment[i].bitflags = Nodes[no].u.d.bitflags;
#else
DomainMoment[i].maxsoft = Nodes[no].maxsoft;
#endif
#endif
}
/* share the pseudo-particle data accross CPUs */
for(level = 1; level < (1 << PTask); level++)
{
sendTask = ThisTask;
recvTask = ThisTask ^ level;
if(recvTask < NTask)
MPI_Sendrecv(&DomainMoment[DomainStartList[sendTask]],
(DomainEndList[sendTask] - DomainStartList[sendTask] + 1) * sizeof(struct DomainNODE),
MPI_BYTE, recvTask, TAG_DMOM,
&DomainMoment[DomainStartList[recvTask]],
(DomainEndList[recvTask] - DomainStartList[recvTask] + 1) * sizeof(struct DomainNODE),
MPI_BYTE, recvTask, TAG_DMOM, MPI_COMM_WORLD, &status);
}
}
/*! This function updates the top-level tree after the multipole moments of
* the pseudo-particles have been updated.
*/
void force_treeupdate_pseudos(void)
{
int i, k, no;
FLOAT sold[3], vsold[3], snew[3], vsnew[3], massold, massnew, mm;
#ifdef STELLAR_FLUX
FLOAT starlumold, starlumnew, starmm;
#endif
#ifdef UNEQUALSOFTENINGS
#ifndef ADAPTIVE_GRAVSOFT_FORGAS
int maxsofttype, diffsoftflag;
#else
FLOAT maxsoft;
#endif
#endif
for(i = 0; i < NTopleaves; i++)
if(i < DomainMyStart || i > DomainMyLast)
{
no = DomainNodeIndex[i];
for(k = 0; k < 3; k++)
{
sold[k] = Nodes[no].u.d.s[k];
vsold[k] = Extnodes[no].vs[k];
}
massold = Nodes[no].u.d.mass;
#ifdef STELLAR_FLUX
starlumold = Nodes[no].starlum;
#endif
for(k = 0; k < 3; k++)
{
snew[k] = DomainMoment[i].s[k];
vsnew[k] = DomainMoment[i].vs[k];
}
massnew = DomainMoment[i].mass;
#ifdef STELLAR_FLUX
starlumnew = DomainMoment[i].starlum;
#endif
#ifdef UNEQUALSOFTENINGS
#ifndef ADAPTIVE_GRAVSOFT_FORGAS
maxsofttype = (DomainMoment[i].bitflags >> 2) & 7;
diffsoftflag = (DomainMoment[i].bitflags >> 5) & 1;
#else
maxsoft = DomainMoment[i].maxsoft;
#endif
#endif
do
{
mm = Nodes[no].u.d.mass + massnew - massold;
#ifdef STELLAR_FLUX
starmm = Nodes[no].starlum + starlumnew - starlumold;
#endif
for(k = 0; k < 3; k++)
{
if(mm > 0)
{
Nodes[no].u.d.s[k] =
(Nodes[no].u.d.mass * Nodes[no].u.d.s[k] + massnew * snew[k] - massold * sold[k]) / mm;
Extnodes[no].vs[k] =
(Nodes[no].u.d.mass * Extnodes[no].vs[k] + massnew * vsnew[k] -
massold * vsold[k]) / mm;
}
}
Nodes[no].u.d.mass = mm;
#ifdef STELLAR_FLUX
Nodes[no].starlum = starmm;
#endif
#ifdef UNEQUALSOFTENINGS
#ifndef ADAPTIVE_GRAVSOFT_FORGAS
diffsoftflag |= (Nodes[no].u.d.bitflags >> 5) & 1;
if(maxsofttype == 7)
maxsofttype = (Nodes[no].u.d.bitflags >> 2) & 7;
else
{
if(((Nodes[no].u.d.bitflags >> 2) & 7) != 7)
{
if(All.ForceSoftening[((Nodes[no].u.d.bitflags >> 2) & 7)] >
All.ForceSoftening[maxsofttype])
{
maxsofttype = ((Nodes[no].u.d.bitflags >> 2) & 7);
diffsoftflag = 1;
}
else
{
if(All.ForceSoftening[((Nodes[no].u.d.bitflags >> 2) & 7)] <
All.ForceSoftening[maxsofttype])
diffsoftflag = 1;
}
}
}
Nodes[no].u.d.bitflags = (Nodes[no].u.d.bitflags & 3) + 4 * maxsofttype + 32 * diffsoftflag;
#else
if(Nodes[no].maxsoft < maxsoft)
Nodes[no].maxsoft = maxsoft;
maxsoft = Nodes[no].maxsoft;
#endif
#endif
no = Nodes[no].u.d.father;
}
while(no >= 0);
}
}
/*! This function flags nodes in the top-level tree that are dependent on
* local particle data.
*/
void force_flag_localnodes(void)
{
int no, i;
/* mark all top-level nodes */
for(i = 0; i < NTopleaves; i++)
{
no = DomainNodeIndex[i];
while(no >= 0)
{
if((Nodes[no].u.d.bitflags & 1))
break;
Nodes[no].u.d.bitflags |= 1;
no = Nodes[no].u.d.father;
}
}
/* mark top-level nodes that contain local particles */
for(i = DomainMyStart; i <= DomainMyLast; i++)
{
/*
if(DomainMoment[i].mass > 0)
*/
{
no = DomainNodeIndex[i];
while(no >= 0)
{
if((Nodes[no].u.d.bitflags & 2))
break;
Nodes[no].u.d.bitflags |= 2;
no = Nodes[no].u.d.father;
}
}
}
}
/*! This function updates the side-length of tree nodes in case the tree is
* not reconstructed, but only drifted. The grouping of particles to tree
* nodes is not changed in this case, but some tree nodes may need to be
* enlarged because particles moved out of their original bounds.
*/
void force_update_len(void)
{
int i, no;
MPI_Status status;
int level, sendTask, recvTask;
force_update_node_len_local();
/* first update the side-lengths of all local nodes */
for(i = DomainMyStart; i <= DomainMyLast; i++)
{
no = DomainNodeIndex[i];
DomainTreeNodeLen[i] = Nodes[no].len;
}
for(level = 1; level < (1 << PTask); level++)
{
sendTask = ThisTask;
recvTask = ThisTask ^ level;
if(recvTask < NTask)
MPI_Sendrecv(&DomainTreeNodeLen[DomainStartList[sendTask]],
(DomainEndList[sendTask] - DomainStartList[sendTask] + 1) * sizeof(FLOAT),
MPI_BYTE, recvTask, TAG_NODELEN,
&DomainTreeNodeLen[DomainStartList[recvTask]],
(DomainEndList[recvTask] - DomainStartList[recvTask] + 1) * sizeof(FLOAT),
MPI_BYTE, recvTask, TAG_NODELEN, MPI_COMM_WORLD, &status);
}
/* Finally, we update the top-level tree. */
force_update_node_len_toptree();
}
/*! This function recursively enlarges nodes such that they always contain
* all their daughter nodes and daughter particles.
*/
void force_update_node_len_local(void)
{
int i, p, k, no;
FLOAT dist, distmax;
for(i = 0; i < NumPart; i++)
{
no = Father[i];
for(k = 0, distmax = 0; k < 3; k++)
{
dist = P[i].Pos[k] - Nodes[no].center[k];
if(dist < 0)
dist = -dist;
if(dist > distmax)
distmax = dist;
}
if(distmax + distmax > Nodes[no].len)
{
Nodes[no].len = distmax + distmax;
p = Nodes[no].u.d.father;
while(p >= 0)
{
distmax = Nodes[p].center[0] - Nodes[no].center[0];
if(distmax < 0)
distmax = -distmax;
distmax = distmax + distmax + Nodes[no].len;
if(0.999999 * distmax > Nodes[p].len)
{
Nodes[p].len = distmax;
no = p;
p = Nodes[p].u.d.father;
}
else
break;
}
}
}
}
/*! This function recursively enlarges nodes of the top-level tree such
* that they always contain all their daughter nodes.
*/
void force_update_node_len_toptree(void)
{
int i, no, p;
FLOAT distmax;
for(i = 0; i < NTopleaves; i++)
if(i < DomainMyStart || i > DomainMyLast)
{
no = DomainNodeIndex[i];
if(Nodes[no].len < DomainTreeNodeLen[i])
Nodes[no].len = DomainTreeNodeLen[i];
p = Nodes[no].u.d.father;
while(p >= 0)
{
distmax = Nodes[p].center[0] - Nodes[no].center[0];
if(distmax < 0)
distmax = -distmax;
distmax = distmax + distmax + Nodes[no].len;
if(0.999999 * distmax > Nodes[p].len)
{
Nodes[p].len = distmax;
no = p;
p = Nodes[p].u.d.father;
}
else
break;
}
}
}
/*! This function updates the hmax-values in tree nodes that hold SPH
* particles. These values are needed to find all neighbors in the
* hydro-force computation. Since the Hsml-values are potentially changed
* in the SPH-denity computation, force_update_hmax() should be carried
* out just before the hydrodynamical SPH forces are computed, i.e. after
* density().
*/
void force_update_hmax(void)
{
int i, no;
MPI_Status status;
int level, sendTask, recvTask;
force_update_node_hmax_local();
for(i = DomainMyStart; i <= DomainMyLast; i++)
{
no = DomainNodeIndex[i];
DomainHmax[i] = Extnodes[no].hmax;
}
/* share the hmax-data of the pseudo-particles accross CPUs */
for(level = 1; level < (1 << PTask); level++)
{
sendTask = ThisTask;
recvTask = ThisTask ^ level;
if(recvTask < NTask)
MPI_Sendrecv(&DomainHmax[DomainStartList[sendTask]],
(DomainEndList[sendTask] - DomainStartList[sendTask] + 1) * sizeof(FLOAT),
MPI_BYTE, recvTask, TAG_HMAX,
&DomainHmax[DomainStartList[recvTask]],
(DomainEndList[recvTask] - DomainStartList[recvTask] + 1) * sizeof(FLOAT),
MPI_BYTE, recvTask, TAG_HMAX, MPI_COMM_WORLD, &status);
}
force_update_node_hmax_toptree();
}
/*! This routine updates the hmax-values of local tree nodes.
*/
void force_update_node_hmax_local(void)
{
int i, p, no;
for(i = 0; i < N_gas; i++)
{
+#ifdef GAS_ACCRETION
+ if (P[i].Mass==0)
+ continue;
+#endif
+
no = Father[i];
if(SphP[i].Hsml > Extnodes[no].hmax)
{
Extnodes[no].hmax = SphP[i].Hsml;
p = Nodes[no].u.d.father;
while(p >= 0)
{
if(Extnodes[no].hmax > Extnodes[p].hmax)
{
Extnodes[p].hmax = Extnodes[no].hmax;
no = p;
p = Nodes[p].u.d.father;
}
else
break;
}
}
}
}
/*! This function recursively sets the hmax-values of the top-level tree.
*/
void force_update_node_hmax_toptree(void)
{
int i, no, p;
for(i = 0; i < NTopleaves; i++)
if(i < DomainMyStart || i > DomainMyLast)
{
no = DomainNodeIndex[i];
if(Extnodes[no].hmax < DomainHmax[i])
Extnodes[no].hmax = DomainHmax[i];
p = Nodes[no].u.d.father;
while(p >= 0)
{
if(Extnodes[no].hmax > Extnodes[p].hmax)
{
Extnodes[p].hmax = Extnodes[no].hmax;
no = p;
p = Nodes[p].u.d.father;
}
else
break;
}
}
}
/*! This routine computes the gravitational force for a given local
* particle, or for a particle in the communication buffer. Depending on
* the value of TypeOfOpeningCriterion, either the geometrical BH
* cell-opening criterion, or the `relative' opening criterion is used.
*/
int force_treeevaluate(int target, int mode, double *ewaldcountsum)
{
struct NODE *nop = 0;
int no, ninteractions, ptype;
double r2, dx, dy, dz, mass, r, fac, u, h, h_inv, h3_inv;
double acc_x, acc_y, acc_z, pos_x, pos_y, pos_z, aold;
#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
#ifdef STELLAR_FLUX
double flux=0,starlum=0;
int type=0;
double hf;
#endif
acc_x = 0;
acc_y = 0;
acc_z = 0;
ninteractions = 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;
aold = All.ErrTolForceAcc * P[target].OldAcc;
#ifdef ADAPTIVE_GRAVSOFT_FORGAS
if(ptype == 0)
soft = SphP[target].Hsml;
#endif
#ifdef STELLAR_FLUX
type = P[target].Type;
#endif
}
else
{
pos_x = GravDataGet[target].u.Pos[0];
pos_y = GravDataGet[target].u.Pos[1];
pos_z = GravDataGet[target].u.Pos[2];
#ifdef UNEQUALSOFTENINGS
ptype = GravDataGet[target].Type;
#else
ptype = P[0].Type;
#endif
aold = All.ErrTolForceAcc * GravDataGet[target].w.OldAcc;
#ifdef ADAPTIVE_GRAVSOFT_FORGAS
if(ptype == 0)
soft = GravDataGet[target].Soft;
#endif
#ifdef STELLAR_FLUX
type = GravDataGet[target].Type;
#endif
}
#ifndef UNEQUALSOFTENINGS
h = All.ForceSoftening[ptype];
h_inv = 1.0 / h;
h3_inv = h_inv * h_inv * h_inv;
#endif
no = All.MaxPart; /* root node */
while(no >= 0)
{
if(no < All.MaxPart) /* single particle */
{
/* the index of the node is the index of the particle */
/* observe the sign */
dx = P[no].Pos[0] - pos_x;
dy = P[no].Pos[1] - pos_y;
dz = P[no].Pos[2] - pos_z;
mass = P[no].Mass;
#ifdef STELLAR_FLUX
starlum = P[no].Mass*All.HeatingPeLMRatio[P[no].Type];
#endif
}
else
{
if(no >= All.MaxPart + MaxNodes) /* pseudo particle */
{
if(mode == 0)
{
Exportflag[DomainTask[no - (All.MaxPart + MaxNodes)]] = 1;
}
no = Nextnode[no - MaxNodes];
continue;
}
nop = &Nodes[no];
dx = nop->u.d.s[0] - pos_x;
dy = nop->u.d.s[1] - pos_y;
dz = nop->u.d.s[2] - pos_z;
mass = nop->u.d.mass;
#ifdef STELLAR_FLUX
starlum = nop->starlum;
#endif
}
#ifdef PERIODIC
dx = NEAREST(dx);
dy = NEAREST(dy);
dz = NEAREST(dz);
#endif
r2 = dx * dx + dy * dy + dz * dz;
if(no < All.MaxPart)
{
#ifdef UNEQUALSOFTENINGS
#ifdef ADAPTIVE_GRAVSOFT_FORGAS
if(ptype == 0)
h = soft;
else
h = All.ForceSoftening[ptype];
if(P[no].Type == 0)
{
if(h < SphP[no].Hsml)
h = SphP[no].Hsml;
}
else
{
if(h < All.ForceSoftening[P[no].Type])
h = All.ForceSoftening[P[no].Type];
}
#else
h = All.ForceSoftening[ptype];
if(h < All.ForceSoftening[P[no].Type])
h = All.ForceSoftening[P[no].Type];
#endif
#endif
no = Nextnode[no];
}
else /* we have an internal node. Need to check opening criterion */
{
if(mode == 1)
{
if((nop->u.d.bitflags & 3) == 1) /* if it's a top-level node
* which does not contain
* local particles we can
* continue to do a short-cut */
{
no = nop->u.d.sibling;
continue;
}
}
if(All.ErrTolTheta) /* check Barnes-Hut opening criterion */
{
if(nop->len * nop->len > r2 * All.ErrTolTheta * All.ErrTolTheta)
{
/* open cell */
no = nop->u.d.nextnode;
continue;
}
}
else /* check relative opening criterion */
{
if(mass * nop->len * nop->len > r2 * r2 * aold)
{
/* open cell */
no = nop->u.d.nextnode;
continue;
}
/* check in addition whether we lie inside the cell */
if(fabs(nop->center[0] - pos_x) < 0.60 * nop->len)
{
if(fabs(nop->center[1] - pos_y) < 0.60 * nop->len)
{
if(fabs(nop->center[2] - pos_z) < 0.60 * nop->len)
{
no = nop->u.d.nextnode;
continue;
}
}
}
}
#ifdef UNEQUALSOFTENINGS
#ifndef ADAPTIVE_GRAVSOFT_FORGAS
h = All.ForceSoftening[ptype];
maxsofttype = (nop->u.d.bitflags >> 2) & 7;
if(maxsofttype == 7) /* may only occur for zero mass top-level nodes */
{
if(mass > 0)
endrun(986);
no = nop->u.d.nextnode;
continue;
}
else
{
if(h < All.ForceSoftening[maxsofttype])
{
h = All.ForceSoftening[maxsofttype];
if(r2 < h * h)
{
if(((nop->u.d.bitflags >> 5) & 1)) /* bit-5 signals that there are particles of different softening in the node */
{
no = nop->u.d.nextnode;
continue;
}
}
}
}
#else
if(ptype == 0)
h = soft;
else
h = All.ForceSoftening[ptype];
if(h < nop->maxsoft)
{
h = nop->maxsoft;
if(r2 < h * h)
{
no = nop->u.d.nextnode;
continue;
}
}
#endif
#endif
no = nop->u.d.sibling; /* ok, node can be used */
if(mode == 1)
{
if(((nop->u.d.bitflags) & 1)) /* Bit 0 signals that this node belongs to top-level tree */
continue;
}
}
r = sqrt(r2);
if(r >= h)
fac = mass / (r2 * r);
else
{
#ifdef UNEQUALSOFTENINGS
h_inv = 1.0 / h;
h3_inv = h_inv * h_inv * h_inv;
#endif
u = r * h_inv;
if(u < 0.5)
fac = mass * h3_inv * (10.666666666667 + u * u * (32.0 * u - 38.4));
else
fac =
mass * h3_inv * (21.333333333333 - 48.0 * u +
38.4 * u * u - 10.666666666667 * u * u * u - 0.066666666667 / (u * u * u));
}
acc_x += dx * fac;
acc_y += dy * fac;
acc_z += dz * fac;
#ifdef STELLAR_FLUX
if (type==0) /* gas particle */
{
hf = All.SofteningTable[type];
flux += starlum / (4*PI) / (r2 + hf*hf) ;
//if ((target==0)&&(starlum!=0))
// printf("flux flux=%g\n",flux);
//if ((target==0)&&(starlum!=0))
// printf("flux r=%g starlum=%g mass=%g h=%g no=%d\n",sqrt(r2),starlum,mass,hf,no);
//if(r >= hf)
// flux += starlum/All.HeatingPeLMRatio/ (4*PI) / r2 ;
//else
// flux += starlum/All.HeatingPeLMRatio/ (4*PI) / (r2 + hf*hf) ;
}
#endif
ninteractions++;
}
/* store result at the proper place */
if(mode == 0)
{
P[target].GravAccel[0] = acc_x;
P[target].GravAccel[1] = acc_y;
P[target].GravAccel[2] = acc_z;
#ifdef STELLAR_FLUX
if (P[target].Type==0) /* only for gas */
SphP[target].EnergyFlux = flux;
#endif
P[target].GravCost = ninteractions;
}
else
{
GravDataResult[target].u.Acc[0] = acc_x;
GravDataResult[target].u.Acc[1] = acc_y;
GravDataResult[target].u.Acc[2] = acc_z;
#ifdef STELLAR_FLUX
GravDataResult[target].EnergyFlux = flux;
#endif
GravDataResult[target].w.Ninteractions = ninteractions;
}
#ifdef PERIODIC
*ewaldcountsum += force_treeevaluate_ewald_correction(target, mode, pos_x, pos_y, pos_z, aold);
#endif
return ninteractions;
}
#ifdef PMGRID
/*! In the TreePM algorithm, the tree is walked only locally around the
* target coordinate. Tree nodes that fall outside a box of half
* side-length Rcut= RCUT*ASMTH*MeshSize can be discarded. The short-range
* potential is modified by a complementary error function, multiplied
* with the Newtonian form. The resulting short-range suppression compared
* to the Newtonian force is tabulated, because looking up from this table
* is faster than recomputing the corresponding factor, despite the
* memory-access panelty (which reduces cache performance) incurred by the
* table.
*/
int force_treeevaluate_shortrange(int target, int mode)
{
struct NODE *nop = 0;
int no, ptype, ninteractions, tabindex;
double r2, dx, dy, dz, mass, r, fac, u, h, h_inv, h3_inv;
double acc_x, acc_y, acc_z, pos_x, pos_y, pos_z, aold;
double eff_dist;
double rcut, asmth, asmthfac, rcut2, dist;
#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
acc_x = 0;
acc_y = 0;
acc_z = 0;
ninteractions = 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;
aold = All.ErrTolForceAcc * P[target].OldAcc;
#ifdef ADAPTIVE_GRAVSOFT_FORGAS
if(ptype == 0)
soft = SphP[target].Hsml;
#endif
}
else
{
pos_x = GravDataGet[target].u.Pos[0];
pos_y = GravDataGet[target].u.Pos[1];
pos_z = GravDataGet[target].u.Pos[2];
#ifdef UNEQUALSOFTENINGS
ptype = GravDataGet[target].Type;
#else
ptype = P[0].Type;
#endif
aold = All.ErrTolForceAcc * GravDataGet[target].w.OldAcc;
#ifdef ADAPTIVE_GRAVSOFT_FORGAS
if(ptype == 0)
soft = GravDataGet[target].Soft;
#endif
}
rcut = All.Rcut[0];
asmth = All.Asmth[0];
#ifdef PLACEHIGHRESREGION
if(((1 << ptype) & (PLACEHIGHRESREGION)))
{
rcut = All.Rcut[1];
asmth = All.Asmth[1];
}
#endif
rcut2 = rcut * rcut;
asmthfac = 0.5 / asmth * (NTAB / 3.0);
#ifndef UNEQUALSOFTENINGS
h = All.ForceSoftening[ptype];
h_inv = 1.0 / h;
h3_inv = h_inv * h_inv * h_inv;
#endif
no = All.MaxPart; /* root node */
while(no >= 0)
{
if(no < All.MaxPart)
{
/* the index of the node is the index of the particle */
dx = P[no].Pos[0] - pos_x;
dy = P[no].Pos[1] - pos_y;
dz = P[no].Pos[2] - pos_z;
#ifdef PERIODIC
dx = NEAREST(dx);
dy = NEAREST(dy);
dz = NEAREST(dz);
#endif
r2 = dx * dx + dy * dy + dz * dz;
mass = P[no].Mass;
#ifdef UNEQUALSOFTENINGS
#ifdef ADAPTIVE_GRAVSOFT_FORGAS
if(ptype == 0)
h = soft;
else
h = All.ForceSoftening[ptype];
if(P[no].Type == 0)
{
if(h < SphP[no].Hsml)
h = SphP[no].Hsml;
}
else
{
if(h < All.ForceSoftening[P[no].Type])
h = All.ForceSoftening[P[no].Type];
}
#else
h = All.ForceSoftening[ptype];
if(h < All.ForceSoftening[P[no].Type])
h = All.ForceSoftening[P[no].Type];
#endif
#endif
no = Nextnode[no];
}
else /* we have an internal node */
{
if(no >= All.MaxPart + MaxNodes) /* pseudo particle */
{
if(mode == 0)
{
Exportflag[DomainTask[no - (All.MaxPart + MaxNodes)]] = 1;
}
no = Nextnode[no - MaxNodes];
continue;
}
nop = &Nodes[no];
if(mode == 1)
{
if((nop->u.d.bitflags & 3) == 1) /* if it's a top-level node
* which does not contain
* local particles we can
* continue at this point
*/
{
no = nop->u.d.sibling;
continue;
}
}
mass = nop->u.d.mass;
dx = nop->u.d.s[0] - pos_x;
dy = nop->u.d.s[1] - pos_y;
dz = nop->u.d.s[2] - pos_z;
#ifdef PERIODIC
dx = NEAREST(dx);
dy = NEAREST(dy);
dz = NEAREST(dz);
#endif
r2 = dx * dx + dy * dy + dz * dz;
if(r2 > rcut2)
{
/* check whether we can stop walking along this branch */
eff_dist = rcut + 0.5 * nop->len;
#ifdef PERIODIC
dist = NEAREST(nop->center[0] - pos_x);
#else
dist = nop->center[0] - pos_x;
#endif
if(dist < -eff_dist || dist > eff_dist)
{
no = nop->u.d.sibling;
continue;
}
#ifdef PERIODIC
dist = NEAREST(nop->center[1] - pos_y);
#else
dist = nop->center[1] - pos_y;
#endif
if(dist < -eff_dist || dist > eff_dist)
{
no = nop->u.d.sibling;
continue;
}
#ifdef PERIODIC
dist = NEAREST(nop->center[2] - pos_z);
#else
dist = nop->center[2] - pos_z;
#endif
if(dist < -eff_dist || dist > eff_dist)
{
no = nop->u.d.sibling;
continue;
}
}
if(All.ErrTolTheta) /* check Barnes-Hut opening criterion */
{
if(nop->len * nop->len > r2 * All.ErrTolTheta * All.ErrTolTheta)
{
/* open cell */
no = nop->u.d.nextnode;
continue;
}
}
else /* check relative opening criterion */
{
if(mass * nop->len * nop->len > r2 * r2 * aold)
{
/* open cell */
no = nop->u.d.nextnode;
continue;
}
/* check in addition whether we lie inside the cell */
if(fabs(nop->center[0] - pos_x) < 0.60 * nop->len)
{
if(fabs(nop->center[1] - pos_y) < 0.60 * nop->len)
{
if(fabs(nop->center[2] - pos_z) < 0.60 * nop->len)
{
no = nop->u.d.nextnode;
continue;
}
}
}
}
#ifdef UNEQUALSOFTENINGS
#ifndef ADAPTIVE_GRAVSOFT_FORGAS
h = All.ForceSoftening[ptype];
maxsofttype = (nop->u.d.bitflags >> 2) & 7;
if(maxsofttype == 7) /* may only occur for zero mass top-level nodes */
{
if(mass > 0)
endrun(987);
no = nop->u.d.nextnode;
continue;
}
else
{
if(h < All.ForceSoftening[maxsofttype])
{
h = All.ForceSoftening[maxsofttype];
if(r2 < h * h)
{
if(((nop->u.d.bitflags >> 5) & 1)) /* bit-5 signals that there are particles of different softening in the node */
{
no = nop->u.d.nextnode;
continue;
}
}
}
}
#else
if(ptype == 0)
h = soft;
else
h = All.ForceSoftening[ptype];
if(h < nop->maxsoft)
{
h = nop->maxsoft;
if(r2 < h * h)
{
no = nop->u.d.nextnode;
continue;
}
}
#endif
#endif
no = nop->u.d.sibling; /* ok, node can be used */
if(mode == 1)
{
if(((nop->u.d.bitflags) & 1)) /* Bit 0 signals that this node belongs to top-level tree */
continue;
}
}
r = sqrt(r2);
if(r >= h)
fac = mass / (r2 * r);
else
{
#ifdef UNEQUALSOFTENINGS
h_inv = 1.0 / h;
h3_inv = h_inv * h_inv * h_inv;
#endif
u = r * h_inv;
if(u < 0.5)
fac = mass * h3_inv * (10.666666666667 + u * u * (32.0 * u - 38.4));
else
fac =
mass * h3_inv * (21.333333333333 - 48.0 * u +
38.4 * u * u - 10.666666666667 * u * u * u - 0.066666666667 / (u * u * u));
}
tabindex = (int) (asmthfac * r);
if(tabindex < NTAB)
{
fac *= shortrange_table[tabindex];
acc_x += dx * fac;
acc_y += dy * fac;
acc_z += dz * fac;
ninteractions++;
}
}
/* store result at the proper place */
if(mode == 0)
{
P[target].GravAccel[0] = acc_x;
P[target].GravAccel[1] = acc_y;
P[target].GravAccel[2] = acc_z;
P[target].GravCost = ninteractions;
}
else
{
GravDataResult[target].u.Acc[0] = acc_x;
GravDataResult[target].u.Acc[1] = acc_y;
GravDataResult[target].u.Acc[2] = acc_z;
GravDataResult[target].w.Ninteractions = ninteractions;
}
return ninteractions;
}
#endif
#ifdef PERIODIC
/*! This function computes the Ewald correction, and is needed if periodic
* boundary conditions together with a pure tree algorithm are used. Note
* that the ordinary tree walk does not carry out this correction directly
* as it was done in Gadget-1.1. Instead, the tree is walked a second
* time. This is actually faster because the "Ewald-Treewalk" can use a
* different opening criterion than the normal tree walk. In particular,
* the Ewald correction is negligible for particles that are very close,
* but it is large for particles that are far away (this is quite
* different for the normal direct force). So we can here use a different
* opening criterion. Sufficient accuracy is usually obtained if the node
* length has dropped to a certain fraction ~< 0.25 of the
* BoxLength. However, we may only short-cut the interaction list of the
* normal full Ewald tree walk if we are sure that the whole node and all
* daughter nodes "lie on the same side" of the periodic boundary,
* i.e. that the real tree walk would not find a daughter node or particle
* that was mapped to a different nearest neighbour position when the tree
* walk would be further refined.
*/
int force_treeevaluate_ewald_correction(int target, int mode, double pos_x, double pos_y, double pos_z,
double aold)
{
struct NODE *nop = 0;
int no, cost;
double dx, dy, dz, mass, r2;
int signx, signy, signz;
int i, j, k, openflag;
double u, v, w;
double f1, f2, f3, f4, f5, f6, f7, f8;
double acc_x, acc_y, acc_z;
double boxsize, boxhalf;
boxsize = All.BoxSize;
boxhalf = 0.5 * All.BoxSize;
acc_x = 0;
acc_y = 0;
acc_z = 0;
cost = 0;
no = All.MaxPart;
while(no >= 0)
{
if(no < All.MaxPart) /* single particle */
{
/* the index of the node is the index of the particle */
/* observe the sign */
dx = P[no].Pos[0] - pos_x;
dy = P[no].Pos[1] - pos_y;
dz = P[no].Pos[2] - pos_z;
mass = P[no].Mass;
}
else
{
if(no >= All.MaxPart + MaxNodes) /* pseudo particle */
{
if(mode == 0)
{
Exportflag[DomainTask[no - (All.MaxPart + MaxNodes)]] = 1;
}
no = Nextnode[no - MaxNodes];
continue;
}
nop = &Nodes[no];
dx = nop->u.d.s[0] - pos_x;
dy = nop->u.d.s[1] - pos_y;
dz = nop->u.d.s[2] - pos_z;
mass = nop->u.d.mass;
}
dx = NEAREST(dx);
dy = NEAREST(dy);
dz = NEAREST(dz);
if(no < All.MaxPart)
no = Nextnode[no];
else /* we have an internal node. Need to check opening criterion */
{
openflag = 0;
r2 = dx * dx + dy * dy + dz * dz;
if(All.ErrTolTheta) /* check Barnes-Hut opening criterion */
{
if(nop->len * nop->len > r2 * All.ErrTolTheta * All.ErrTolTheta)
{
openflag = 1;
}
}
else /* check relative opening criterion */
{
if(mass * nop->len * nop->len > r2 * r2 * aold)
{
openflag = 1;
}
else
{
if(fabs(nop->center[0] - pos_x) < 0.60 * nop->len)
{
if(fabs(nop->center[1] - pos_y) < 0.60 * nop->len)
{
if(fabs(nop->center[2] - pos_z) < 0.60 * nop->len)
{
openflag = 1;
}
}
}
}
}
if(openflag)
{
/* now we check if we can avoid opening the cell */
u = nop->center[0] - pos_x;
if(u > boxhalf)
u -= boxsize;
if(u < -boxhalf)
u += boxsize;
if(fabs(u) > 0.5 * (boxsize - nop->len))
{
no = nop->u.d.nextnode;
continue;
}
u = nop->center[1] - pos_y;
if(u > boxhalf)
u -= boxsize;
if(u < -boxhalf)
u += boxsize;
if(fabs(u) > 0.5 * (boxsize - nop->len))
{
no = nop->u.d.nextnode;
continue;
}
u = nop->center[2] - pos_z;
if(u > boxhalf)
u -= boxsize;
if(u < -boxhalf)
u += boxsize;
if(fabs(u) > 0.5 * (boxsize - nop->len))
{
no = nop->u.d.nextnode;
continue;
}
/* if the cell is too large, we need to refine
* it further
*/
if(nop->len > 0.20 * boxsize)
{
/* cell is too large */
no = nop->u.d.nextnode;
continue;
}
}
no = nop->u.d.sibling; /* ok, node can be used */
if(mode == 1)
{
if((nop->u.d.bitflags & 1)) /* Bit 0 signals that this node belongs to top-level tree */
continue;
}
}
/* compute the Ewald correction force */
if(dx < 0)
{
dx = -dx;
signx = +1;
}
else
signx = -1;
if(dy < 0)
{
dy = -dy;
signy = +1;
}
else
signy = -1;
if(dz < 0)
{
dz = -dz;
signz = +1;
}
else
signz = -1;
u = dx * fac_intp;
i = (int) u;
if(i >= EN)
i = EN - 1;
u -= i;
v = dy * fac_intp;
j = (int) v;
if(j >= EN)
j = EN - 1;
v -= j;
w = dz * fac_intp;
k = (int) w;
if(k >= EN)
k = EN - 1;
w -= k;
/* compute factors for trilinear interpolation */
f1 = (1 - u) * (1 - v) * (1 - w);
f2 = (1 - u) * (1 - v) * (w);
f3 = (1 - u) * (v) * (1 - w);
f4 = (1 - u) * (v) * (w);
f5 = (u) * (1 - v) * (1 - w);
f6 = (u) * (1 - v) * (w);
f7 = (u) * (v) * (1 - w);
f8 = (u) * (v) * (w);
acc_x += mass * signx * (fcorrx[i][j][k] * f1 +
fcorrx[i][j][k + 1] * f2 +
fcorrx[i][j + 1][k] * f3 +
fcorrx[i][j + 1][k + 1] * f4 +
fcorrx[i + 1][j][k] * f5 +
fcorrx[i + 1][j][k + 1] * f6 +
fcorrx[i + 1][j + 1][k] * f7 + fcorrx[i + 1][j + 1][k + 1] * f8);
acc_y += mass * signy * (fcorry[i][j][k] * f1 +
fcorry[i][j][k + 1] * f2 +
fcorry[i][j + 1][k] * f3 +
fcorry[i][j + 1][k + 1] * f4 +
fcorry[i + 1][j][k] * f5 +
fcorry[i + 1][j][k + 1] * f6 +
fcorry[i + 1][j + 1][k] * f7 + fcorry[i + 1][j + 1][k + 1] * f8);
acc_z += mass * signz * (fcorrz[i][j][k] * f1 +
fcorrz[i][j][k + 1] * f2 +
fcorrz[i][j + 1][k] * f3 +
fcorrz[i][j + 1][k + 1] * f4 +
fcorrz[i + 1][j][k] * f5 +
fcorrz[i + 1][j][k + 1] * f6 +
fcorrz[i + 1][j + 1][k] * f7 + fcorrz[i + 1][j + 1][k + 1] * f8);
cost++;
}
/* add the result at the proper place */
if(mode == 0)
{
P[target].GravAccel[0] += acc_x;
P[target].GravAccel[1] += acc_y;
P[target].GravAccel[2] += acc_z;
P[target].GravCost += cost;
}
else
{
GravDataResult[target].u.Acc[0] += acc_x;
GravDataResult[target].u.Acc[1] += acc_y;
GravDataResult[target].u.Acc[2] += acc_z;
GravDataResult[target].w.Ninteractions += cost;
}
return cost;
}
#endif
/*! This routine computes the gravitational potential by walking the
* tree. The same opening criteria is used as for the gravitational force
* walk.
*/
void force_treeevaluate_potential(int target, int mode)
{
struct NODE *nop = 0;
int no, ptype;
double r2, dx, dy, dz, mass, r, u, h, h_inv, wp;
double pot, pos_x, pos_y, pos_z, aold;
#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;
aold = All.ErrTolForceAcc * P[target].OldAcc;
#ifdef ADAPTIVE_GRAVSOFT_FORGAS
if(ptype == 0)
soft = SphP[target].Hsml;
#endif
}
else
{
pos_x = GravDataGet[target].u.Pos[0];
pos_y = GravDataGet[target].u.Pos[1];
pos_z = GravDataGet[target].u.Pos[2];
#ifdef UNEQUALSOFTENINGS
ptype = GravDataGet[target].Type;
#else
ptype = P[0].Type;
#endif
aold = All.ErrTolForceAcc * GravDataGet[target].w.OldAcc;
#ifdef ADAPTIVE_GRAVSOFT_FORGAS
if(ptype == 0)
soft = GravDataGet[target].Soft;
#endif
}
#ifndef UNEQUALSOFTENINGS
h = All.ForceSoftening[ptype];
h_inv = 1.0 / h;
#endif
no = All.MaxPart;
while(no >= 0)
{
if(no < All.MaxPart) /* single particle */
{
/* the index of the node is the index of the particle */
/* observe the sign */
dx = P[no].Pos[0] - pos_x;
dy = P[no].Pos[1] - pos_y;
dz = P[no].Pos[2] - pos_z;
mass = P[no].Mass;
}
else
{
if(no >= All.MaxPart + MaxNodes) /* pseudo particle */
{
if(mode == 0)
{
Exportflag[DomainTask[no - (All.MaxPart + MaxNodes)]] = 1;
}
no = Nextnode[no - MaxNodes];
continue;
}
nop = &Nodes[no];
dx = nop->u.d.s[0] - pos_x;
dy = nop->u.d.s[1] - pos_y;
dz = nop->u.d.s[2] - pos_z;
mass = nop->u.d.mass;
}
#ifdef PERIODIC
dx = NEAREST(dx);
dy = NEAREST(dy);
dz = NEAREST(dz);
#endif
r2 = dx * dx + dy * dy + dz * dz;
if(no < All.MaxPart)
{
#ifdef UNEQUALSOFTENINGS
#ifdef ADAPTIVE_GRAVSOFT_FORGAS
if(ptype == 0)
h = soft;
else
h = All.ForceSoftening[ptype];
if(P[no].Type == 0)
{
if(h < SphP[no].Hsml)
h = SphP[no].Hsml;
}
else
{
if(h < All.ForceSoftening[P[no].Type])
h = All.ForceSoftening[P[no].Type];
}
#else
h = All.ForceSoftening[ptype];
if(h < All.ForceSoftening[P[no].Type])
h = All.ForceSoftening[P[no].Type];
#endif
#endif
no = Nextnode[no];
}
else /* we have an internal node. Need to check opening criterion */
{
if(mode == 1)
{
if((nop->u.d.bitflags & 3) == 1) /* if it's a top-level node
* which does not contain
* local particles we can make
* a short-cut
*/
{
no = nop->u.d.sibling;
continue;
}
}
if(All.ErrTolTheta) /* check Barnes-Hut opening criterion */
{
if(nop->len * nop->len > r2 * All.ErrTolTheta * All.ErrTolTheta)
{
/* open cell */
no = nop->u.d.nextnode;
continue;
}
}
else /* check relative opening criterion */
{
if(mass * nop->len * nop->len > r2 * r2 * aold)
{
/* open cell */
no = nop->u.d.nextnode;
continue;
}
if(fabs(nop->center[0] - pos_x) < 0.60 * nop->len)
{
if(fabs(nop->center[1] - pos_y) < 0.60 * nop->len)
{
if(fabs(nop->center[2] - pos_z) < 0.60 * nop->len)
{
no = nop->u.d.nextnode;
continue;
}
}
}
}
#ifdef UNEQUALSOFTENINGS
#ifndef ADAPTIVE_GRAVSOFT_FORGAS
h = All.ForceSoftening[ptype];
maxsofttype = (nop->u.d.bitflags >> 2) & 7;
if(maxsofttype == 7) /* may only occur for zero mass top-level nodes */
{
if(mass > 0)
endrun(988);
no = nop->u.d.nextnode;
continue;
}
else
{
if(h < All.ForceSoftening[maxsofttype])
{
h = All.ForceSoftening[maxsofttype];
if(r2 < h * h)
{
if(((nop->u.d.bitflags >> 5) & 1)) /* bit-5 signals that there are particles of different softening in the node */
{
no = nop->u.d.nextnode;
continue;
}
}
}
}
#else
if(ptype == 0)
h = soft;
else
h = All.ForceSoftening[ptype];
if(h < nop->maxsoft)
{
h = nop->maxsoft;
if(r2 < h * h)
{
no = nop->u.d.nextnode;
continue;
}
}
#endif
#endif
no = nop->u.d.sibling; /* node can be used */
if(mode == 1)
{
if(((nop->u.d.bitflags) & 1)) /* Bit 0 signals that this node belongs to top-level tree */
continue;
}
}
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
}
/* store result at the proper place */
if(mode == 0)
P[target].Potential = pot;
else
GravDataResult[target].u.Potential = pot;
}
#ifdef PMGRID
/*! This function computes the short-range potential when the TreePM
* algorithm is used. This potential is the Newtonian potential, modified
* by a complementary error function.
*/
void force_treeevaluate_potential_shortrange(int target, int mode)
{
struct NODE *nop = 0;
int no, ptype, tabindex;
double r2, dx, dy, dz, mass, r, u, h, h_inv, wp;
double pot, pos_x, pos_y, pos_z, aold;
double eff_dist, fac, rcut, asmth, asmthfac;
double dxx, dyy, dzz;
#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;
aold = All.ErrTolForceAcc * P[target].OldAcc;
#ifdef ADAPTIVE_GRAVSOFT_FORGAS
if(ptype == 0)
soft = SphP[target].Hsml;
#endif
}
else
{
pos_x = GravDataGet[target].u.Pos[0];
pos_y = GravDataGet[target].u.Pos[1];
pos_z = GravDataGet[target].u.Pos[2];
#ifdef UNEQUALSOFTENINGS
ptype = GravDataGet[target].Type;
#else
ptype = P[0].Type;
#endif
aold = All.ErrTolForceAcc * GravDataGet[target].w.OldAcc;
#ifdef ADAPTIVE_GRAVSOFT_FORGAS
if(ptype == 0)
soft = GravDataGet[target].Soft;
#endif
}
rcut = All.Rcut[0];
asmth = All.Asmth[0];
#ifdef PLACEHIGHRESREGION
if(((1 << ptype) & (PLACEHIGHRESREGION)))
{
rcut = All.Rcut[1];
asmth = All.Asmth[1];
}
#endif
asmthfac = 0.5 / asmth * (NTAB / 3.0);
#ifndef UNEQUALSOFTENINGS
h = All.ForceSoftening[ptype];
h_inv = 1.0 / h;
#endif
no = All.MaxPart;
while(no >= 0)
{
if(no < All.MaxPart) /* single particle */
{
/* the index of the node is the index of the particle */
/* observe the sign */
dx = P[no].Pos[0] - pos_x;
dy = P[no].Pos[1] - pos_y;
dz = P[no].Pos[2] - pos_z;
mass = P[no].Mass;
}
else
{
if(no >= All.MaxPart + MaxNodes) /* pseudo particle */
{
if(mode == 0)
{
Exportflag[DomainTask[no - (All.MaxPart + MaxNodes)]] = 1;
}
no = Nextnode[no - MaxNodes];
continue;
}
nop = &Nodes[no];
dx = nop->u.d.s[0] - pos_x;
dy = nop->u.d.s[1] - pos_y;
dz = nop->u.d.s[2] - pos_z;
mass = nop->u.d.mass;
}
#ifdef PERIODIC
dx = NEAREST(dx);
dy = NEAREST(dy);
dz = NEAREST(dz);
#endif
r2 = dx * dx + dy * dy + dz * dz;
if(no < All.MaxPart)
{
#ifdef UNEQUALSOFTENINGS
#ifdef ADAPTIVE_GRAVSOFT_FORGAS
if(ptype == 0)
h = soft;
else
h = All.ForceSoftening[ptype];
if(P[no].Type == 0)
{
if(h < SphP[no].Hsml)
h = SphP[no].Hsml;
}
else
{
if(h < All.ForceSoftening[P[no].Type])
h = All.ForceSoftening[P[no].Type];
}
#else
h = All.ForceSoftening[ptype];
if(h < All.ForceSoftening[P[no].Type])
h = All.ForceSoftening[P[no].Type];
#endif
#endif
no = Nextnode[no];
}
else /* we have an internal node. Need to check opening criterion */
{
/* check whether we can stop walking along this branch */
if(no >= All.MaxPart + MaxNodes) /* pseudo particle */
{
if(mode == 0)
{
Exportflag[DomainTask[no - (All.MaxPart + MaxNodes)]] = 1;
}
no = Nextnode[no - MaxNodes];
continue;
}
if(mode == 1)
{
if((nop->u.d.bitflags & 3) == 1) /* if it's a top-level node which does not contain local particles */
{
no = nop->u.d.sibling;
continue;
}
}
eff_dist = rcut + 0.5 * nop->len;
dxx = nop->center[0] - pos_x; /* observe the sign ! */
dyy = nop->center[1] - pos_y; /* this vector is -y in my thesis notation */
dzz = nop->center[2] - pos_z;
#ifdef PERIODIC
dxx = NEAREST(dxx);
dyy = NEAREST(dyy);
dzz = NEAREST(dzz);
#endif
if(dxx < -eff_dist || dxx > eff_dist)
{
no = nop->u.d.sibling;
continue;
}
if(dyy < -eff_dist || dyy > eff_dist)
{
no = nop->u.d.sibling;
continue;
}
if(dzz < -eff_dist || dzz > eff_dist)
{
no = nop->u.d.sibling;
continue;
}
if(All.ErrTolTheta) /* check Barnes-Hut opening criterion */
{
if(nop->len * nop->len > r2 * All.ErrTolTheta * All.ErrTolTheta)
{
/* open cell */
no = nop->u.d.nextnode;
continue;
}
}
else /* check relative opening criterion */
{
if(mass * nop->len * nop->len > r2 * r2 * aold)
{
/* open cell */
no = nop->u.d.nextnode;
continue;
}
if(fabs(nop->center[0] - pos_x) < 0.60 * nop->len)
{
if(fabs(nop->center[1] - pos_y) < 0.60 * nop->len)
{
if(fabs(nop->center[2] - pos_z) < 0.60 * nop->len)
{
no = nop->u.d.nextnode;
continue;
}
}
}
}
#ifdef UNEQUALSOFTENINGS
#ifndef ADAPTIVE_GRAVSOFT_FORGAS
h = All.ForceSoftening[ptype];
maxsofttype = (nop->u.d.bitflags >> 2) & 7;
if(maxsofttype == 7) /* may only occur for zero mass top-level nodes */
{
if(mass > 0)
endrun(989);
no = nop->u.d.nextnode;
continue;
}
else
{
if(h < All.ForceSoftening[maxsofttype])
{
h = All.ForceSoftening[maxsofttype];
if(r2 < h * h)
{
/* bit-5 signals that there are particles of
* different softening in the node
*/
if(((nop->u.d.bitflags >> 5) & 1))
{
no = nop->u.d.nextnode;
continue;
}
}
}
}
#else
if(ptype == 0)
h = soft;
else
h = All.ForceSoftening[ptype];
if(h < nop->maxsoft)
{
h = nop->maxsoft;
if(r2 < h * h)
{
no = nop->u.d.nextnode;
continue;
}
}
#endif
#endif
no = nop->u.d.sibling; /* node can be used */
if(mode == 1)
{
if(((nop->u.d.bitflags) & 1)) /* Bit 0 signals that this node belongs to top-level tree */
continue;
}
}
r = sqrt(r2);
tabindex = (int) (r * asmthfac);
if(tabindex < NTAB)
{
fac = shortrange_table_potential[tabindex];
if(r >= h)
pot -= fac * 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 += fac * mass * h_inv * wp;
}
}
}
/* store result at the proper place */
if(mode == 0)
P[target].Potential = pot;
else
GravDataResult[target].u.Potential = pot;
}
#endif
/*! This function allocates the memory used for storage of the tree and of
* auxiliary arrays needed for tree-walk and link-lists. Usually,
* maxnodes approximately equal to 0.7*maxpart is sufficient to store the
* tree for up to maxpart particles.
*/
void force_treeallocate(int maxnodes, int maxpart)
{
int i;
size_t bytes;
double allbytes = 0;
double u;
MaxNodes = maxnodes;
if(!(Nodes_base = malloc(bytes = (MaxNodes + 1) * sizeof(struct NODE))))
{
printf("failed to allocate memory for %d tree-nodes (%g MB).\n", MaxNodes, bytes / (1024.0 * 1024.0));
endrun(3);
}
allbytes += bytes;
if(!(Extnodes_base = malloc(bytes = (MaxNodes + 1) * sizeof(struct extNODE))))
{
printf("failed to allocate memory for %d tree-extnodes (%g MB).\n", MaxNodes,
bytes / (1024.0 * 1024.0));
endrun(3);
}
allbytes += bytes;
Nodes = Nodes_base - All.MaxPart;
Extnodes = Extnodes_base - All.MaxPart;
if(!(Nextnode = malloc(bytes = (maxpart + MAXTOPNODES) * sizeof(int))))
{
printf("Failed to allocate %d spaces for 'Nextnode' array (%g MB)\n", maxpart + MAXTOPNODES,
bytes / (1024.0 * 1024.0));
exit(0);
}
allbytes += bytes;
if(!(Father = malloc(bytes = (maxpart) * sizeof(int))))
{
printf("Failed to allocate %d spaces for 'Father' array (%g MB)\n", maxpart, bytes / (1024.0 * 1024.0));
exit(0);
}
allbytes += bytes;
if(first_flag == 0)
{
first_flag = 1;
if(ThisTask == 0)
printf("\nAllocated %g MByte for BH-tree. %d\n\n", allbytes / (1024.0 * 1024.0),
sizeof(struct NODE) + sizeof(struct extNODE));
tabfac = NTAB / 3.0;
for(i = 0; i < NTAB; i++)
{
u = 3.0 / NTAB * (i + 0.5);
shortrange_table[i] = erfc(u) + 2.0 * u / sqrt(M_PI) * exp(-u * u);
shortrange_table_potential[i] = erfc(u);
}
}
}
/*! This function frees the memory allocated for the tree, i.e. it frees
* the space allocated by the function force_treeallocate().
*/
void force_treefree(void)
{
free(Father);
free(Nextnode);
free(Extnodes_base);
free(Nodes_base);
}
/*! This function does the force computation with direct summation for the
* specified particle in the communication buffer. This can be useful for
* debugging purposes, in particular for explicit checks of the force
* accuracy.
*/
#ifdef FORCETEST
int force_treeevaluate_direct(int target, int mode)
{
double epsilon;
double h, h_inv, dx, dy, dz, r, r2, u, r_inv, fac;
int i, ptype;
double pos_x, pos_y, pos_z;
double acc_x, acc_y, acc_z;
#ifdef PERIODIC
double fcorr[3];
#endif
#ifdef PERIODIC
double boxsize, boxhalf;
boxsize = All.BoxSize;
boxhalf = 0.5 * All.BoxSize;
#endif
acc_x = 0;
acc_y = 0;
acc_z = 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;
}
else
{
pos_x = GravDataGet[target].u.Pos[0];
pos_y = GravDataGet[target].u.Pos[1];
pos_z = GravDataGet[target].u.Pos[2];
#ifdef UNEQUALSOFTENINGS
ptype = GravDataGet[target].Type;
#else
ptype = P[0].Type;
#endif
}
for(i = 0; i < NumPart; i++)
{
epsilon = dmax(All.ForceSoftening[P[i].Type], All.ForceSoftening[ptype]);
h = epsilon;
h_inv = 1 / h;
dx = P[i].Pos[0] - pos_x;
dy = P[i].Pos[1] - pos_y;
dz = P[i].Pos[2] - pos_z;
#ifdef PERIODIC
while(dx > boxhalf)
dx -= boxsize;
while(dy > boxhalf)
dy -= boxsize;
while(dz > boxhalf)
dz -= boxsize;
while(dx < -boxhalf)
dx += boxsize;
while(dy < -boxhalf)
dy += boxsize;
while(dz < -boxhalf)
dz += boxsize;
#endif
r2 = dx * dx + dy * dy + dz * dz;
r = sqrt(r2);
u = r * h_inv;
if(u >= 1)
{
r_inv = 1 / r;
fac = P[i].Mass * r_inv * r_inv * r_inv;
}
else
{
if(u < 0.5)
fac = P[i].Mass * h_inv * h_inv * h_inv * (10.666666666667 + u * u * (32.0 * u - 38.4));
else
fac =
P[i].Mass * h_inv * h_inv * h_inv * (21.333333333333 -
48.0 * u + 38.4 * u * u -
10.666666666667 * u * u *
u - 0.066666666667 / (u * u * u));
}
acc_x += dx * fac;
acc_y += dy * fac;
acc_z += dz * fac;
#ifdef PERIODIC
if(u > 1.0e-5)
{
ewald_corr(dx, dy, dz, fcorr);
acc_x += P[i].Mass * fcorr[0];
acc_y += P[i].Mass * fcorr[1];
acc_z += P[i].Mass * fcorr[2];
}
#endif
}
if(mode == 0)
{
P[target].GravAccelDirect[0] = acc_x;
P[target].GravAccelDirect[1] = acc_y;
P[target].GravAccelDirect[2] = acc_z;
}
else
{
GravDataResult[target].u.Acc[0] = acc_x;
GravDataResult[target].u.Acc[1] = acc_y;
GravDataResult[target].u.Acc[2] = acc_z;
}
return NumPart;
}
#endif
/*! This function dumps some of the basic particle data to a file. In case
* the tree construction fails, it is called just before the run
* terminates with an error message. Examination of the generated file may
* then give clues to what caused the problem.
*/
void dump_particles(void)
{
FILE *fd;
char buffer[200];
int i;
sprintf(buffer, "particles%d.dat", ThisTask);
fd = fopen(buffer, "w");
my_fwrite(&NumPart, 1, sizeof(int), fd);
for(i = 0; i < NumPart; i++)
my_fwrite(&P[i].Pos[0], 3, sizeof(FLOAT), fd);
for(i = 0; i < NumPart; i++)
my_fwrite(&P[i].Vel[0], 3, sizeof(FLOAT), fd);
for(i = 0; i < NumPart; i++)
my_fwrite(&P[i].ID, 1, sizeof(int), fd);
fclose(fd);
}
#ifdef PERIODIC
/*! This function initializes tables with the correction force and the
* correction potential due to the periodic images of a point mass located
* at the origin. These corrections are obtained by Ewald summation. (See
* Hernquist, Bouchet, Suto, ApJS, 1991, 75, 231) The correction fields
* are used to obtain the full periodic force if periodic boundaries
* combined with the pure tree algorithm are used. For the TreePM
* algorithm, the Ewald correction is not used.
*
* The correction fields are stored on disk once they are computed. If a
* corresponding file is found, they are loaded from disk to speed up the
* initialization. The Ewald summation is done in parallel, i.e. the
* processors share the work to compute the tables if needed.
*/
void ewald_init(void)
{
int i, j, k, beg, len, size, n, task, count;
double x[3], force[3];
char buf[200];
FILE *fd;
if(ThisTask == 0)
{
printf("initialize Ewald correction...\n");
fflush(stdout);
}
#ifdef DOUBLEPRECISION
sprintf(buf, "ewald_spc_table_%d_dbl.dat", EN);
#else
sprintf(buf, "ewald_spc_table_%d.dat", EN);
#endif
#ifdef ONLY_MASTER_READ_EWALD
/* the master check if the file exists */
int is_ewald_file=0;
if(ThisTask == 0)
{
if((fd = fopen(buf, "r")))
{
printf("\n(%d) reading Ewald tables from file `%s'\n", ThisTask,buf);
fflush(stdout);
my_fread(&fcorrx[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
my_fread(&fcorry[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
my_fread(&fcorrz[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
my_fread(&potcorr[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
fclose(fd);
is_ewald_file=1;
}
else
is_ewald_file=0;
}
MPI_Bcast(&is_ewald_file, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (is_ewald_file)
{
#ifdef DOUBLEPRECISION
MPI_Bcast(&fcorrx[0][0][0], (EN + 1) * (EN + 1) * (EN + 1), MPI_DOUBLE, 0, MPI_COMM_WORLD);
MPI_Bcast(&fcorry[0][0][0], (EN + 1) * (EN + 1) * (EN + 1), MPI_DOUBLE, 0, MPI_COMM_WORLD);
MPI_Bcast(&fcorrz[0][0][0], (EN + 1) * (EN + 1) * (EN + 1), MPI_DOUBLE, 0, MPI_COMM_WORLD);
MPI_Bcast(&potcorr[0][0][0], (EN + 1) * (EN + 1) * (EN + 1), MPI_DOUBLE, 0, MPI_COMM_WORLD);
#else
MPI_Bcast(&fcorrx[0][0][0], (EN + 1) * (EN + 1) * (EN + 1), MPI_FLOAT, 0, MPI_COMM_WORLD);
MPI_Bcast(&fcorry[0][0][0], (EN + 1) * (EN + 1) * (EN + 1), MPI_FLOAT, 0, MPI_COMM_WORLD);
MPI_Bcast(&fcorrz[0][0][0], (EN + 1) * (EN + 1) * (EN + 1), MPI_FLOAT, 0, MPI_COMM_WORLD);
MPI_Bcast(&potcorr[0][0][0], (EN + 1) * (EN + 1) * (EN + 1), MPI_FLOAT, 0, MPI_COMM_WORLD);
#endif
}
#else
if((fd = fopen(buf, "r")))
{
if(ThisTask == 0)
{
printf("\nreading Ewald tables from file `%s'\n", buf);
fflush(stdout);
}
my_fread(&fcorrx[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
my_fread(&fcorry[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
my_fread(&fcorrz[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
my_fread(&potcorr[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
fclose(fd);
}
#endif
else
{
if(ThisTask == 0)
{
printf("\nNo Ewald tables in file `%s' found.\nRecomputing them...\n", buf);
fflush(stdout);
}
/* ok, let's recompute things. Actually, we do that in parallel. */
size = (EN + 1) * (EN + 1) * (EN + 1) / NTask;
beg = ThisTask * size;
len = size;
if(ThisTask == (NTask - 1))
len = (EN + 1) * (EN + 1) * (EN + 1) - beg;
for(i = 0, count = 0; i <= EN; i++)
for(j = 0; j <= EN; j++)
for(k = 0; k <= EN; k++)
{
n = (i * (EN + 1) + j) * (EN + 1) + k;
if(n >= beg && n < (beg + len))
{
if(ThisTask == 0)
{
if((count % (len / 20)) == 0)
{
printf("%4.1f percent done\n", count / (len / 100.0));
fflush(stdout);
}
}
x[0] = 0.5 * ((double) i) / EN;
x[1] = 0.5 * ((double) j) / EN;
x[2] = 0.5 * ((double) k) / EN;
ewald_force(i, j, k, x, force);
fcorrx[i][j][k] = force[0];
fcorry[i][j][k] = force[1];
fcorrz[i][j][k] = force[2];
if(i + j + k == 0)
potcorr[i][j][k] = 2.8372975;
else
potcorr[i][j][k] = ewald_psi(x);
count++;
}
}
for(task = 0; task < NTask; task++)
{
beg = task * size;
len = size;
if(task == (NTask - 1))
len = (EN + 1) * (EN + 1) * (EN + 1) - beg;
#ifdef DOUBLEPRECISION
MPI_Bcast(&fcorrx[0][0][beg], len, MPI_DOUBLE, task, MPI_COMM_WORLD);
MPI_Bcast(&fcorry[0][0][beg], len, MPI_DOUBLE, task, MPI_COMM_WORLD);
MPI_Bcast(&fcorrz[0][0][beg], len, MPI_DOUBLE, task, MPI_COMM_WORLD);
MPI_Bcast(&potcorr[0][0][beg], len, MPI_DOUBLE, task, MPI_COMM_WORLD);
#else
MPI_Bcast(&fcorrx[0][0][beg], len, MPI_FLOAT, task, MPI_COMM_WORLD);
MPI_Bcast(&fcorry[0][0][beg], len, MPI_FLOAT, task, MPI_COMM_WORLD);
MPI_Bcast(&fcorrz[0][0][beg], len, MPI_FLOAT, task, MPI_COMM_WORLD);
MPI_Bcast(&potcorr[0][0][beg], len, MPI_FLOAT, task, MPI_COMM_WORLD);
#endif
}
if(ThisTask == 0)
{
printf("\nwriting Ewald tables to file `%s'\n", buf);
fflush(stdout);
if((fd = fopen(buf, "w")))
{
my_fwrite(&fcorrx[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
my_fwrite(&fcorry[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
my_fwrite(&fcorrz[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
my_fwrite(&potcorr[0][0][0], sizeof(FLOAT), (EN + 1) * (EN + 1) * (EN + 1), fd);
fclose(fd);
}
}
}
fac_intp = 2 * EN / All.BoxSize;
for(i = 0; i <= EN; i++)
for(j = 0; j <= EN; j++)
for(k = 0; k <= EN; k++)
{
potcorr[i][j][k] /= All.BoxSize;
fcorrx[i][j][k] /= All.BoxSize * All.BoxSize;
fcorry[i][j][k] /= All.BoxSize * All.BoxSize;
fcorrz[i][j][k] /= All.BoxSize * All.BoxSize;
}
if(ThisTask == 0)
{
printf("initialization of periodic boundaries finished.\n");
fflush(stdout);
}
}
/*! This function looks up the correction force due to the infinite number
* of periodic particle/node images. We here use trilinear interpolation
* to get it from the precomputed tables, which contain one octant
* around the target particle at the origin. The other octants are
* obtained from it by exploiting the symmetry properties.
*/
#ifdef FORCETEST
void ewald_corr(double dx, double dy, double dz, double *fper)
{
int signx, signy, signz;
int i, j, k;
double u, v, w;
double f1, f2, f3, f4, f5, f6, f7, f8;
if(dx < 0)
{
dx = -dx;
signx = +1;
}
else
signx = -1;
if(dy < 0)
{
dy = -dy;
signy = +1;
}
else
signy = -1;
if(dz < 0)
{
dz = -dz;
signz = +1;
}
else
signz = -1;
u = dx * fac_intp;
i = (int) u;
if(i >= EN)
i = EN - 1;
u -= i;
v = dy * fac_intp;
j = (int) v;
if(j >= EN)
j = EN - 1;
v -= j;
w = dz * fac_intp;
k = (int) w;
if(k >= EN)
k = EN - 1;
w -= k;
f1 = (1 - u) * (1 - v) * (1 - w);
f2 = (1 - u) * (1 - v) * (w);
f3 = (1 - u) * (v) * (1 - w);
f4 = (1 - u) * (v) * (w);
f5 = (u) * (1 - v) * (1 - w);
f6 = (u) * (1 - v) * (w);
f7 = (u) * (v) * (1 - w);
f8 = (u) * (v) * (w);
fper[0] = signx * (fcorrx[i][j][k] * f1 +
fcorrx[i][j][k + 1] * f2 +
fcorrx[i][j + 1][k] * f3 +
fcorrx[i][j + 1][k + 1] * f4 +
fcorrx[i + 1][j][k] * f5 +
fcorrx[i + 1][j][k + 1] * f6 +
fcorrx[i + 1][j + 1][k] * f7 + fcorrx[i + 1][j + 1][k + 1] * f8);
fper[1] = signy * (fcorry[i][j][k] * f1 +
fcorry[i][j][k + 1] * f2 +
fcorry[i][j + 1][k] * f3 +
fcorry[i][j + 1][k + 1] * f4 +
fcorry[i + 1][j][k] * f5 +
fcorry[i + 1][j][k + 1] * f6 +
fcorry[i + 1][j + 1][k] * f7 + fcorry[i + 1][j + 1][k + 1] * f8);
fper[2] = signz * (fcorrz[i][j][k] * f1 +
fcorrz[i][j][k + 1] * f2 +
fcorrz[i][j + 1][k] * f3 +
fcorrz[i][j + 1][k + 1] * f4 +
fcorrz[i + 1][j][k] * f5 +
fcorrz[i + 1][j][k + 1] * f6 +
fcorrz[i + 1][j + 1][k] * f7 + fcorrz[i + 1][j + 1][k + 1] * f8);
}
#endif
/*! This function looks up the correction potential due to the infinite
* number of periodic particle/node images. We here use tri-linear
* interpolation to get it from the precomputed table, which contains
* one octant around the target particle at the origin. The other
* octants are obtained from it by exploiting symmetry properties.
*/
double ewald_pot_corr(double dx, double dy, double dz)
{
int i, j, k;
double u, v, w;
double f1, f2, f3, f4, f5, f6, f7, f8;
if(dx < 0)
dx = -dx;
if(dy < 0)
dy = -dy;
if(dz < 0)
dz = -dz;
u = dx * fac_intp;
i = (int) u;
if(i >= EN)
i = EN - 1;
u -= i;
v = dy * fac_intp;
j = (int) v;
if(j >= EN)
j = EN - 1;
v -= j;
w = dz * fac_intp;
k = (int) w;
if(k >= EN)
k = EN - 1;
w -= k;
f1 = (1 - u) * (1 - v) * (1 - w);
f2 = (1 - u) * (1 - v) * (w);
f3 = (1 - u) * (v) * (1 - w);
f4 = (1 - u) * (v) * (w);
f5 = (u) * (1 - v) * (1 - w);
f6 = (u) * (1 - v) * (w);
f7 = (u) * (v) * (1 - w);
f8 = (u) * (v) * (w);
return potcorr[i][j][k] * f1 +
potcorr[i][j][k + 1] * f2 +
potcorr[i][j + 1][k] * f3 +
potcorr[i][j + 1][k + 1] * f4 +
potcorr[i + 1][j][k] * f5 +
potcorr[i + 1][j][k + 1] * f6 + potcorr[i + 1][j + 1][k] * f7 + potcorr[i + 1][j + 1][k + 1] * f8;
}
/*! This function computes the potential correction term by means of Ewald
* summation.
*/
double ewald_psi(double x[3])
{
double alpha, psi;
double r, sum1, sum2, hdotx;
double dx[3];
int i, n[3], h[3], h2;
alpha = 2.0;
for(n[0] = -4, sum1 = 0; n[0] <= 4; n[0]++)
for(n[1] = -4; n[1] <= 4; n[1]++)
for(n[2] = -4; n[2] <= 4; n[2]++)
{
for(i = 0; i < 3; i++)
dx[i] = x[i] - n[i];
r = sqrt(dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]);
sum1 += erfc(alpha * r) / r;
}
for(h[0] = -4, sum2 = 0; h[0] <= 4; h[0]++)
for(h[1] = -4; h[1] <= 4; h[1]++)
for(h[2] = -4; h[2] <= 4; h[2]++)
{
hdotx = x[0] * h[0] + x[1] * h[1] + x[2] * h[2];
h2 = h[0] * h[0] + h[1] * h[1] + h[2] * h[2];
if(h2 > 0)
sum2 += 1 / (M_PI * h2) * exp(-M_PI * M_PI * h2 / (alpha * alpha)) * cos(2 * M_PI * hdotx);
}
r = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
psi = M_PI / (alpha * alpha) - sum1 - sum2 + 1 / r;
return psi;
}
/*! This function computes the force correction term (difference between full
* force of infinite lattice and nearest image) by Ewald summation.
*/
void ewald_force(int iii, int jjj, int kkk, double x[3], double force[3])
{
double alpha, r2;
double r, val, hdotx, dx[3];
int i, h[3], n[3], h2;
alpha = 2.0;
for(i = 0; i < 3; i++)
force[i] = 0;
if(iii == 0 && jjj == 0 && kkk == 0)
return;
r2 = x[0] * x[0] + x[1] * x[1] + x[2] * x[2];
for(i = 0; i < 3; i++)
force[i] += x[i] / (r2 * sqrt(r2));
for(n[0] = -4; n[0] <= 4; n[0]++)
for(n[1] = -4; n[1] <= 4; n[1]++)
for(n[2] = -4; n[2] <= 4; n[2]++)
{
for(i = 0; i < 3; i++)
dx[i] = x[i] - n[i];
r = sqrt(dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]);
val = erfc(alpha * r) + 2 * alpha * r / sqrt(M_PI) * exp(-alpha * alpha * r * r);
for(i = 0; i < 3; i++)
force[i] -= dx[i] / (r * r * r) * val;
}
for(h[0] = -4; h[0] <= 4; h[0]++)
for(h[1] = -4; h[1] <= 4; h[1]++)
for(h[2] = -4; h[2] <= 4; h[2]++)
{
hdotx = x[0] * h[0] + x[1] * h[1] + x[2] * h[2];
h2 = h[0] * h[0] + h[1] * h[1] + h[2] * h[2];
if(h2 > 0)
{
val = 2.0 / ((double) h2) * exp(-M_PI * M_PI * h2 / (alpha * alpha)) * sin(2 * M_PI * hdotx);
for(i = 0; i < 3; i++)
force[i] -= h[i] * val;
}
}
}
#endif
diff --git a/src/gas_accretion.c b/src/gas_accretion.c
new file mode 100644
index 0000000..dcd7f23
--- /dev/null
+++ b/src/gas_accretion.c
@@ -0,0 +1,262 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <mpi.h>
+
+#include "allvars.h"
+#include "proto.h"
+
+
+#ifdef GAS_ACCRETION
+
+static double hubble_a,a3inv,a3;
+
+/*
+ * This routine compute the accretion of gas
+ */
+void init_gas_accretion(void)
+{
+ int i;
+ int *temp;
+ double MaxGasMass;
+
+ if(ThisTask == 0)
+ {
+ printf("Init gas accretion...\n");
+ fflush(stdout);
+ }
+
+ if(All.ComovingIntegrationOn)
+ {
+ if(ThisTask==0)
+ printf("gas accretion will fail if cosmological integration is used\nThis is due to the usage of dt in gas_accretion(). This should be changed.\n");
+
+ endrun(75463);
+ }
+
+
+
+ MaxGasMass=-1;
+ /* loop over all gasous particles */
+ for(i = 0, N_acc = 0; i < N_gas; i++)
+ {
+
+ MaxGasMass = dmax(MaxGasMass,P[i].Mass);
+
+ if (P[i].Mass == 0)
+ {
+ N_acc++;
+ //printf("i=%d ID=%d enropy=%g\n",i,P[i].ID,SphP[i].Entropy);
+
+ /* force to be inactive */
+ P[i].Ti_endstep = -1;
+
+ SphP[i].ActiveFlag=0;
+
+ }
+
+ }
+
+
+ MPI_Allreduce(&MaxGasMass, &All.GasAccretionParticleMass, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
+
+ if(ThisTask == 0)
+ {
+ printf("(%d) GasAccretionParticleMass=%g\n",ThisTask,All.GasAccretionParticleMass);
+ fflush(stdout);
+ }
+
+
+
+ /* because ntot_type_all[] is of type `long long', we cannot do a simple
+ * MPI_Allreduce() to sum the total particle numbers
+ */
+
+
+ temp = malloc(NTask * sizeof(int));
+ MPI_Allgather(&N_acc, 1, MPI_INT, temp, 1, MPI_INT, MPI_COMM_WORLD);
+
+
+ for(i = 0; i < NTask; i++)
+ Ntotacc += temp[i];
+
+ free(temp);
+
+
+ if(ThisTask == 0)
+ {
+ printf("Number of gas accretion particles found : %6d%09d \n",(int) (Ntotacc / 1000000000), (int) (Ntotacc % 1000000000));
+ printf("gas accretion init done.\n\n");
+ fflush(stdout);
+ }
+
+
+}
+
+
+/*
+ * This routine compute the accretion of gas
+ */
+double gas_accretion_rate(float t)
+{
+
+ double dMdt;
+
+ /* accretion rate in Msol/yr (including little h) */
+ dMdt = 1; /* [Msol/yr] */
+
+ /* return the value in code units (this is independent of h) */
+ return dMdt * (SOLAR_MASS/All.UnitMass_in_g) / (31536000/All.UnitTime_in_s);
+}
+
+
+
+
+
+
+
+/*
+ * This routine compute the accretion of gas
+ */
+void gas_accretion(void)
+{
+
+ int i,N;
+ double dM,M,p,dt,Macc,Macctot;
+ int *temp;
+
+ if(ThisTask == 0)
+ {
+ printf("Start gas accretion...\n");
+ fflush(stdout);
+ }
+
+
+ if(All.ComovingIntegrationOn)
+ {
+ hubble_a = All.Omega0 / (All.Time * All.Time * All.Time)
+ + (1 - All.Omega0 - All.OmegaLambda) / (All.Time * All.Time) + All.OmegaLambda;
+
+ hubble_a = All.Hubble * sqrt(hubble_a);
+ a3inv = 1 / (All.Time * All.Time * All.Time);
+ a3 = (All.Time * All.Time * All.Time);
+ }
+ else
+ {
+ hubble_a = 1.;
+ a3inv = 1.;
+ a3 = 1;
+ }
+
+ /* count the available mass */
+ for(i = 0, M = 0, N=0; i < N_gas; i++)
+ {
+ if (P[i].Mass == 0)
+ N++;
+ }
+
+ temp = malloc(NTask * sizeof(int));
+ MPI_Allgather(&N, 1, MPI_INT, temp, 1, MPI_INT, MPI_COMM_WORLD);
+
+
+ for(i = 0,Ntotacc=0; i < NTask; i++)
+ Ntotacc += temp[i];
+
+ free(temp);
+
+
+
+ /* total remaining gass */
+ M = Ntotacc*All.GasAccretionParticleMass;
+
+
+ /* compute the total accreated mass during the time step
+ */
+
+ dt = All.TimeStep / hubble_a;
+ dM=gas_accretion_rate(All.Time)*dt; /* mass to be accteated during the timestep */
+
+ /* probability */
+ p = dM/M;
+
+
+ if(ThisTask == 0)
+ {
+ printf("Number of gas accretion particles remaining : %6d%09d \n",(int) (Ntotacc / 1000000000), (int) (Ntotacc % 1000000000));
+ printf("Nass left : %g.\n",M);
+ fflush(stdout);
+ }
+
+
+
+ for(i = 0,Macc=0; i < N_gas; i++)
+ {
+
+ if (P[i].Mass == 0)
+ {
+
+ if (get_gasAccretion_random_number(P[i].ID) < p)
+ {
+ P[i].Mass=All.GasAccretionParticleMass;
+ P[i].Ti_endstep=All.Ti_Current;
+ SphP[i].Hsml=All.SofteningTable[P[i].Type];
+ SphP[i].ActiveFlag=1;
+ Macc+=P[i].Mass;
+ //printf("(%d) ==================> i=%d ID=%d Macc=%g %g\n",ThisTask,i,P[i].ID,Macc,All.GasAccretionParticleMass);
+ }
+ }
+
+ }
+
+
+ MPI_Allreduce(&Macc, &Macctot, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
+
+
+
+ /* force to update the domain and build the tree */
+ if (Macctot>0)
+ {
+ //TreeReconstructFlag=1; /* seems not to be sufficent */
+ All.NumForcesSinceLastDomainDecomp = All.TotNumPart * All.TreeDomainUpdateFrequency + 1;
+ }
+
+
+
+ if (ThisTask==0)
+ {
+ fprintf(FdGasAccretion, "%15g %15g %6d%09d %15g %15g %15g %15g\n", All.Time,All.TimeStep, (int) (Ntotacc / 1000000000), (int) (Ntotacc % 1000000000) ,M,dM,p,Macctot);
+ fflush(FdGasAccretion);
+ }
+
+
+
+ if(ThisTask == 0)
+ {
+ printf("gas accretion done.\n");
+ fflush(stdout);
+ }
+
+
+}
+
+
+/*
+ * This routine compute the accretion of gas
+ */
+void update_entropy_for_accreated_particles(void)
+{
+ int i;
+
+ for (i=0;i<N_gas;i++)
+ if (SphP[i].ActiveFlag)
+ {
+ //printf("------------------------ end of density id=%d rho=%g Hsml=%g entr=%g %g\n",P[i].ID,SphP[i].Density,SphP[i].Hsml,SphP[i].Entropy,P[i].Mass);
+ SphP[i].Entropy = GAMMA_MINUS1 * SphP[i].Entropy / pow(SphP[i].Density / a3, GAMMA_MINUS1);
+ //printf("------------------------ end of density id=%d rho=%g Hsml=%g entr=%g %g\n",P[i].ID,SphP[i].Density,SphP[i].Hsml,SphP[i].Entropy,P[i].Mass);
+ SphP[i].ActiveFlag=0;
+ }
+}
+
+
+#endif /* GAS_ACCRETION */
diff --git a/src/init.c b/src/init.c
index 68dd60d..46b796f 100644
--- a/src/init.c
+++ b/src/init.c
@@ -1,715 +1,718 @@
#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;
#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 */
All.SnapshotFileCount = 0;
if(RestartFlag == 2)
All.SnapshotFileCount = atoi(All.InitCondFile + strlen(All.InitCondFile) - 3) + 1;
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 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 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;
}
SphP[i].DtEntropy = 0;
#ifdef COOLING
//SphP[i].EntropyRad = 0;
SphP[i].DtEntropyRad = 0;
SphP[i].DtEnergyRad = 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
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
}
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
#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++)
{
SphP[i].Metal[j] = (pow(10,All.InitGasMetallicity)-1e-10)*get_SolarAbundance(j);
//if (j==FE)
// SphP[i].Metal[j] = (pow(10,All.InitGasMetallicity)-1e-10)*All.CoolingParameters_FeHSolar;
//else
// SphP[i].Metal[j] = 0;
}
}
#ifdef CHIMIE_THERMAL_FEEDBACK
SphP[i].DeltaEgySpec = 0;
SphP[i].NumberOfSNIa = 0;
SphP[i].NumberOfSNII = 0;
SphP[i].SNIaThermalTime = -1;
SphP[i].SNIIThermalTime = -1;
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
SphP[i].WindTime = All.TimeBegin-2*All.ChimieWindTime;
SphP[i].WindFlag = 0;
#endif
}
#endif /* chimie */
#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
#endif
/* 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*/
-
-
-
-
+#ifdef GAS_ACCRETION
+ init_gas_accretion();
+#endif
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 ISOTHERM_EQS
#ifndef DENSITY_INDEPENDENT_SPH
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;
- }
+#ifdef GAS_ACCRETION
+ if (P[i].Mass==0)
+ break;
+#endif
+
+#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);
+ SphP[i].Entropy = GAMMA_MINUS1 * SphP[i].Entropy / pow(SphP[i].Density / a3, GAMMA_MINUS1);
#endif
+ }
}
#endif
#endif
#ifdef ENTROPYPRED
for(i = 0; i < N_gas; i++)
SphP[i].EntropyPred = SphP[i].Entropy;
#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)
{
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].Entropy = GAMMA_MINUS1 * SphP[i].Entropy / pow(SphP[i].EgyWtDensity/a3 , GAMMA_MINUS1);
SphP[i].EntVarPred = pow(SphP[i].Entropy,1/GAMMA);
}
density(0);
}
}
#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)
{
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/lambda_depraz.c b/src/lambda_depraz.c
index 6950dae..e14600e 100644
--- a/src/lambda_depraz.c
+++ b/src/lambda_depraz.c
@@ -1,838 +1,834 @@
#ifdef PY_INTERFACE
#include <Python.h>
#else
#include <stdio.h>
#include <string.h>
#endif
#include "proto.h"
#include <stdlib.h>
#include <math.h>
#include <mpi.h>
//standard C POSIX library for file handling
//(opendir, readdir, etc)
#include <dirent.h>
#ifdef COOLING
#ifdef LAMBDA_DEPRAZ
#include <hdf5.h>
int withLinInterpolation = 1;
int withDebugMessages = 1;
int Z_global_index_solar = 4;
/*******************************************************************************/
// Update gloval variable All.*_TABLE with current values
int updateCoolingTable(){
printf("Updating cooling tables...\n");
//FIXME (make general use of type_name)
char* type_name = "/Total_Metals";
//hdf5 tables location
char* tables_dir = "/home/epfl/revaz/code/gear/PyCool/tables_wiersma/coolingtables/";
if(withDebugMessages == 1){
printf("tables location: %s\n", tables_dir);
}
//load corresponding hdf5 table
int err = 0;
int hdf5 = 0;
float z_file = 0.0;
float diff = 0.0;
float min = 1.0e10;
DIR *dir;
struct dirent* content;
char* file_name = "";
//open directory containing the tables
dir = opendir(tables_dir);
if(dir == NULL){
printf("an error occured while opening hdf5 directory %s\n", tables_dir);
return 1;
}
/*********************** z ***********************/
float z = 0.0;
#ifndef PY_INTERFACE
float a = get_a_from_CosmicTime(All.Time);
float actual_z = get_Redshift_from_a(a);
#else
float actual_z = 4.0;
#endif
if(withDebugMessages == 1){
printf("Redshift z = %g\n", actual_z);
}
//scan directory content
while((content = readdir(dir)) != NULL){
//consider only files having the extension .hdf5
hdf5 = endsWith(content->d_name, ".hdf5");
if(hdf5 == 1){
//scan file name to determine the redshift value
err = sscanf(content->d_name, "z_%f.hdf5", &z_file);
if(err != 1){
printf("an error occured while reading file %s in directory %s\n",
content->d_name, tables_dir);
return 1;
}
//determine the file closest to the redshift value given as input
diff = fabs(z_file - actual_z);
if(diff < min){
file_name = content->d_name;
z = z_file;
min = diff;
}
}
}
if(withDebugMessages == 1){
printf("loading data from file %s\n", file_name);
}
All.CURRENT_TABLE_REDSHIFT = z;
//close directory
err = closedir(dir);
if (err != 0){
printf("an error occured while closing directory %s\n", tables_dir);
return 1;
}
//variables types specific to the hdf5 library
hid_t table;
//store path to table file
char file_path[(int)strlen(tables_dir)+(int)strlen(file_name)];
strcpy(file_path, tables_dir);
strcat(file_path, file_name);
//load hdf5 table
table = H5Fopen(file_path, H5F_ACC_RDONLY, H5P_DEFAULT);
/*********************** T ***********************/
char* T_key = "/Temperature_bins";
char T_table_key[(int)strlen(type_name)+(int)strlen(T_key)+1];
strcpy(T_table_key, type_name);
strcat(T_table_key, T_key);
loadDataInTable1D(table, T_table_key, &All.TEMPERATURE_TABLES, &All.SIZE_TEMPERATURE_TABLES);
/********************* rho_H *********************/
char* rho_H_key = "/Hydrogen_density_bins";
char rho_H_table_key[(int)strlen(type_name)+(int)strlen(rho_H_key)+1];
strcpy(rho_H_table_key, type_name);
strcat(rho_H_table_key, rho_H_key);
loadDataInTable1D(table, rho_H_table_key, &All.HYDROGEN_TABLES, &All.SIZE_HYDROGEN_TABLES);
/********************** nHe **********************/
char* nHe_key = "/Helium_mass_fraction_bins";
//or
//char* nHe_key = "/Helium_number_ratio_bins";
char nHe_table_key[(int)strlen("/Metal_free")+(int)strlen(nHe_key)+1];
strcpy(nHe_table_key, "/Metal_free");
strcat(nHe_table_key, nHe_key);
loadDataInTable1D(table, nHe_table_key, &All.HELIUM_ABOUNDANCE_TABLES, &All.SIZE_HELIUM_ABOUNDANCE_TABLES);
/********************* ne/n_H *********************/
char* ne_over_nH_key = "/Electron_density_over_n_h";
char ne_over_nH_table_key[(int)strlen("/Metal_free")+(int)strlen(ne_over_nH_key)+1];
strcpy(ne_over_nH_table_key, "/Metal_free");
strcat(ne_over_nH_table_key, ne_over_nH_key);
loadDataInTable3D(table, ne_over_nH_table_key, &All.ELECTRON_DENSITY_OVER_N_H_TABLES);
/******************** ne/n_H (Solar) ********************/
char* ne_over_nH_solar_key = "/Electron_density_over_n_h";
char ne_over_nH_solar_table_key[(int)strlen("/Solar")+(int)strlen(ne_over_nH_solar_key)+1];
strcpy(ne_over_nH_solar_table_key, "/Solar");
strcat(ne_over_nH_solar_table_key, ne_over_nH_solar_key);
loadDataInTable2D(table, ne_over_nH_solar_table_key, &All.ELECTRON_DENSITY_OVER_N_H_TABLES_SOLAR);
/********************* lambda *********************/
//load corresponding lambda value for metal
char* lambda_key = "/Net_cooling"; // /!\ sometimes written "/Net_Cooling"
char lambda_table_key[(int)strlen(type_name)+(int)strlen(lambda_key)+1];
strcpy(lambda_table_key, type_name);
strcat(lambda_table_key, lambda_key);
loadDataInTable2D(table, lambda_table_key, &All.COOLING_TABLES_TOTAL_METAL);
/**************** lambda Metal Free ****************/
//load corresponding lambda value for metal free
char* lambda_key_mf = "/Net_Cooling"; // /!\ sometimes written "/Net_cooling"
char lambda_table_key_mf[(int)strlen("/Metal_free")+(int)strlen(lambda_key_mf)+1];
strcpy(lambda_table_key_mf, "/Metal_free");
strcat(lambda_table_key_mf, lambda_key_mf);
loadDataInTable3D(table, lambda_table_key_mf, &All.COOLING_TABLES_METAL_FREE);
//close file
H5Fclose(table);
return 0;
}
/*******************************************************************************/
// Compute the resulting value of the cooling function using the data stored in
// the global variables
//
// variables ending with "_in" are user input, other variables are closest match
// in the hdf5 tables
float computeLambda(float rho_H_in, float T_in, float nHe_in, float metalicity){
float lambda_metal_free = 0.0;
float lambda_metals = 0.0;
float total_lambda = 0.0;
float ne_over_nH = 0.0;
float ne_over_nH_solar = 0.0;
float epsilon_diff = 1.0e-7;
float epsilon = 1.0e-38;
-
- printf("--> in computeLambda: %g %g %g\n",T_in,rho_H_in,nHe_in);
-
+
//find the indices for temperature, hydrogen density and
//helium mass fraction that correspond to the closest
//input values
/*********************** T ***********************/
float T [2] = {0.0, 0.0};
int T_index[2] = {0,0};
- printf("--> in computeLambda: %g %g %g\n",T_in,rho_H_in,nHe_in);
closestMatch1D(All.TEMPERATURE_TABLES, All.SIZE_TEMPERATURE_TABLES, T_in, T, T_index);
/********************* rho_H *********************/
float rho_H [2] = {0.0, 0.0};
int rho_H_index[2] = {0,0};
closestMatch1D(All.HYDROGEN_TABLES, All.SIZE_HYDROGEN_TABLES, rho_H_in, rho_H, rho_H_index);
/********************** nHe **********************/
float nHe [2] = {0.0, 0.0};
int nHe_index[2] = {0,0};
closestMatch1D(All.HELIUM_ABOUNDANCE_TABLES, All.SIZE_HELIUM_ABOUNDANCE_TABLES, nHe_in, nHe, nHe_index);
/********************* ne/n_H *********************/
//read electron density value from indices position
ne_over_nH = All.ELECTRON_DENSITY_OVER_N_H_TABLES[nHe_index[0]][T_index[0]][rho_H_index[0]];
if(withLinInterpolation == 1){
//linear interpolation of the results
//the derivative is computed by a simple finite difference method.
//f(c) ~ \-/f(a) * (c-a) ~ (f(b)-f(a))/(b-a) * (c-a)
ne_over_nH += (All.ELECTRON_DENSITY_OVER_N_H_TABLES[nHe_index[0]][T_index[0]][rho_H_index[0]]
- All.ELECTRON_DENSITY_OVER_N_H_TABLES[nHe_index[1]][T_index[0]][rho_H_index[0]])
/ fmax(nHe[0]-nHe[1], epsilon_diff) * (nHe_in - nHe[0]);
ne_over_nH += (All.ELECTRON_DENSITY_OVER_N_H_TABLES[nHe_index[0]][T_index[0]][rho_H_index[0]]
- All.ELECTRON_DENSITY_OVER_N_H_TABLES[nHe_index[0]][T_index[1]][rho_H_index[0]])
/ fmax(T[0]-T[1], epsilon_diff) * (T_in - T[0]);
ne_over_nH += (All.ELECTRON_DENSITY_OVER_N_H_TABLES[nHe_index[0]][T_index[0]][rho_H_index[0]]
- All.ELECTRON_DENSITY_OVER_N_H_TABLES[nHe_index[0]][T_index[0]][rho_H_index[1]])
/ fmax(rho_H[0]-rho_H[1], epsilon_diff) * (rho_H_in - rho_H[0]);
}
//contribution of metals
ne_over_nH_solar = All.ELECTRON_DENSITY_OVER_N_H_TABLES_SOLAR[T_index[0]][rho_H_index[0]];
if(withLinInterpolation == 1){
//linear interpolation of the results
//the derivative is computed by a simple finite difference method.
//f(c) ~ \-/f(a) * (c-a) ~ (f(b)-f(a))/(b-a) * (c-a)
ne_over_nH_solar += (All.ELECTRON_DENSITY_OVER_N_H_TABLES_SOLAR[T_index[0]][rho_H_index[0]]
- All.ELECTRON_DENSITY_OVER_N_H_TABLES_SOLAR[T_index[1]][rho_H_index[0]])
/ fmax(T[0]-T[1], epsilon_diff) * (T_in - T[0]);
ne_over_nH_solar += (All.ELECTRON_DENSITY_OVER_N_H_TABLES_SOLAR[T_index[0]][rho_H_index[0]]
- All.ELECTRON_DENSITY_OVER_N_H_TABLES_SOLAR[T_index[0]][rho_H_index[1]])
/ fmax(rho_H[0]-rho_H[1], epsilon_diff) * (rho_H_in - rho_H[0]);
}
/********************* lambda *********************/
//read lambda value from indices position
//contribution of hydrogen and helium
lambda_metal_free = All.COOLING_TABLES_METAL_FREE[nHe_index[0]][T_index[0]][rho_H_index[0]];
if(withLinInterpolation == 1){
//linear interpolation of the results
//the derivative is computed by a simple finite difference method.
//f(c) ~ \-/f(a) * (c-a) ~ (f(b)-f(a))/(b-a) * (c-a)
lambda_metal_free += (All.COOLING_TABLES_METAL_FREE[nHe_index[0]][T_index[0]][rho_H_index[0]]
- All.COOLING_TABLES_METAL_FREE[nHe_index[1]][T_index[0]][rho_H_index[0]])
/ fmax(nHe[0]-nHe[1], epsilon_diff) * (nHe_in - nHe[0]);
lambda_metal_free += (All.COOLING_TABLES_METAL_FREE[nHe_index[0]][T_index[0]][rho_H_index[0]]
- All.COOLING_TABLES_METAL_FREE[nHe_index[0]][T_index[1]][rho_H_index[0]])
/ fmax(T[0]-T[1], epsilon_diff) * (T_in - T[0]);
lambda_metal_free += (All.COOLING_TABLES_METAL_FREE[nHe_index[0]][T_index[0]][rho_H_index[0]]
- All.COOLING_TABLES_METAL_FREE[nHe_index[0]][T_index[0]][rho_H_index[1]])
/ fmax(rho_H[0]-rho_H[1], epsilon_diff) * (rho_H_in - rho_H[0]);
}
//contribution of metals
lambda_metals = All.COOLING_TABLES_TOTAL_METAL[T_index[0]][rho_H_index[0]];
if(withLinInterpolation == 1){
//linear interpolation of the results
//the derivative is computed by a simple finite difference method.
//f(c) ~ \-/f(a) * (c-a) ~ (f(b)-f(a))/(b-a) * (c-a)
lambda_metals += (All.COOLING_TABLES_TOTAL_METAL[T_index[0]][rho_H_index[0]]
- All.COOLING_TABLES_TOTAL_METAL[T_index[1]][rho_H_index[0]])
/ fmax(T[0]-T[1], epsilon_diff) * (T_in - T[0]);
lambda_metals += (All.COOLING_TABLES_TOTAL_METAL[T_index[0]][rho_H_index[0]]
- All.COOLING_TABLES_TOTAL_METAL[T_index[0]][rho_H_index[1]])
/ fmax(rho_H[0]-rho_H[1], epsilon_diff) * (rho_H_in - rho_H[0]);
}
// formula from taken from:
// "The effect of photoionization on the cooling rates of enriched,
// astrophysical plasmas"
// Robert P.C. Wiersma, J. Schaye & B.D. Smith
// p.101, eq. (5)
// http://onlinelibrary.wiley.com/doi/10.1111/j.1365-2966.2008.14191.x/pdf
//
#ifndef PY_INTERFACE
total_lambda = lambda_metal_free + lambda_metals * ne_over_nH/ne_over_nH_solar
* metalicity/fmax(chimie_extraheader.SolarAbundances[Z_global_index_solar], epsilon);
#else
//chimie_extraheader.SolarAbundances[] not defined, use constant value instead
total_lambda = lambda_metal_free + lambda_metals * ne_over_nH/ne_over_nH_solar
* metalicity/0.02;
#endif
//denormalized value (not used for now...)
/*
if(withLinInterpolation == 1){
total_lambda *= pow( ((All.HYDROGEN_TABLES[rho_H_index[0]] - All.HYDROGEN_TABLES[rho_H_index[1]])
/ fmax(rho_H[0]-rho_H[1], epsilon_diff) * (rho_H_in - rho_H[0])) ,2);
} else {
total_lambda *= pow(All.HYDROGEN_TABLES[rho_H_index[0]], 2);
}
*/
if(withDebugMessages == 1){
printf("lambda = %g\n", total_lambda);
}
return total_lambda;
}
/*******************************************************************************/
// write data from hdf5 tables to global variable TABLE (1D) and write the
// corresponding array size in SIZE_TABLE
void loadDataInTable1D(hid_t table, char* table_key, float** TABLE, int* SIZE_TABLE){
hid_t dataset;
hid_t dataspace;
hid_t memspace;
herr_t status;
hsize_t size[1];
int rank;
dataset = H5Dopen2(table, table_key, H5P_DEFAULT); // open dataset (key)
dataspace = H5Dget_space(dataset); // get dataspace
rank = H5Sget_simple_extent_ndims(dataspace); // compute dataspace rank
status = H5Sget_simple_extent_dims(dataspace, size, NULL);// save dataspace dimensions in dims
memspace = H5Screate_simple(rank, size, NULL); // determine memory space required
//read data
float data[size[0]];
status = H5Dread(dataset, H5T_NATIVE_FLOAT, memspace, dataspace, H5P_DEFAULT, data);
if(withDebugMessages == 1){
printf("%s: rank %d, dimension %d \n", table_key, rank, (int)size[0]);
}
*TABLE = (float*)malloc(size[0]*sizeof(float));
if(TABLE == NULL){
printf("\nMemory allocation failed in loadDataInTable1D()\n");
return;
}
//store data in global variables
*SIZE_TABLE = size[0];
int k=0;
for(k=0; k<size[0]; k++){
(*TABLE)[k] = data[k];
}
//close instances
H5Sclose(memspace);
H5Sclose(dataspace);
H5Dclose(dataset);
}
/*******************************************************************************/
// write data from hdf5 tables to global variable TABLE (2D)
void loadDataInTable2D(hid_t table, char* table_key, float*** TABLE){
hid_t dataset;
hid_t dataspace;
hid_t memspace;
herr_t status;
hsize_t dims[2];
int rank;
dataset = H5Dopen2(table, table_key, H5P_DEFAULT); // open dataset (key)
dataspace = H5Dget_space(dataset); // get dataspace
rank = H5Sget_simple_extent_ndims(dataspace); // compute dataspace rank
status = H5Sget_simple_extent_dims(dataspace, dims, NULL);// save dataspace dimensions in dims
memspace = H5Screate_simple(rank, dims, NULL); // determine memory space required
float* temp;
int i = 0;
int j = 0;
//format of the data: data[T][nH]
float data[dims[0]][dims[1]];
status = H5Dread(dataset, H5T_NATIVE_FLOAT, memspace, dataspace, H5P_DEFAULT, data);
//allocate contiguous memory to enable the later use of MPI_Bcast()
temp = (float*)malloc(dims[0]*dims[1]*sizeof(float));
//allocate memory for TABLE accordingly
*TABLE = (float**)malloc(dims[0]*sizeof(float*));
for(i=0; i<dims[0]; i++){
(*TABLE)[i] = &(temp[i*dims[1]]);
}
if(TABLE == NULL){
printf("\nMemory allocation failed in loadDataInTable2D()\n");
free(temp);
return;
}
for(i=0; i<dims[0]; i++){
for(j=0; j<dims[1]; j++){
(*TABLE)[i][j] = data[i][j];
}
}
if(withDebugMessages == 1){
printf("%s loaded with dimensions: %d x %d\n", table_key, (int)dims[0], (int)dims[1]);
}
//close instances
H5Sclose(memspace);
H5Sclose(dataspace);
H5Dclose(dataset);
}
/*******************************************************************************/
// write data from hdf5 tables to global variable TABLE (3D)
void loadDataInTable3D(hid_t table, char* table_key, float**** TABLE){
hid_t dataset;
hid_t dataspace;
hid_t memspace;
herr_t status;
hsize_t dims[3];
int rank;
dataset = H5Dopen2(table, table_key, H5P_DEFAULT); // open dataset (key)
dataspace = H5Dget_space(dataset); // get dataspace
rank = H5Sget_simple_extent_ndims(dataspace); // compute dataspace rank
status = H5Sget_simple_extent_dims(dataspace, dims, NULL);// save dataspace dimensions in dims
memspace = H5Screate_simple(rank, dims, NULL); // determine memory space required
float** temp1;
float* temp2;
int i = 0;
int j = 0;
int k = 0;
//format of the data: data[nHe][T][nH]
float data[dims[0]][dims[1]][dims[2]];
status = H5Dread(dataset, H5T_NATIVE_FLOAT, memspace, dataspace, H5P_DEFAULT, data);
//allocate contiguous memory to enable the later use of MPI_Bcast()
temp1 = (float**)malloc(dims[0]*dims[1]*sizeof(float*));
temp2 = (float*)malloc(dims[0]*dims[1]*dims[2]*sizeof(float));
for(i=0, j=0; i<dims[0]*dims[1]; i++, j++){
temp1[i] = &(temp2[j*dims[2]]);
}
*TABLE = (float***)malloc(dims[0]*sizeof(float**));
for(i=0, j=0; j<dims[0]; i++, j++){
(*TABLE)[i] = &(temp1[j*dims[1]]);
}
if(TABLE == NULL){
printf("\nMemory allocation failed in loadDataInTable3D()\n");
free(temp1);
free(temp2);
return;
}
for(i=0; i<dims[0]; i++){
for(j=0; j<dims[1]; j++){
for(k=0; k<dims[2]; k++){
(*TABLE)[i][j][k] = data[i][j][k];
}
}
}
if(withDebugMessages == 1){
printf("%s loaded with dimensions: %d x %d x %d\n",
table_key, (int)dims[0], (int)dims[1], (int)dims[2]);
}
//close instances
H5Sclose(memspace);
H5Sclose(dataspace);
H5Dclose(dataset);
}
/*******************************************************************************/
//determine if the string str ends by the string suffix
//function used here to determine the extension of file given their name
int endsWith(const char *str, const char *suffix) {
if (!str || !suffix)
return 0;
size_t lenstr = strlen(str);
size_t lensuffix = strlen(suffix);
if (lensuffix > lenstr)
return 0;
return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
}
/*******************************************************************************/
//return the indices of the 2 closest element of the hdf5 table matching the user
// input. Note that the dimension of the data has to be 1D
void closestMatch1D(float* TABLE, int SIZE, float input, float match[2], int index[2]){
- printf("oooooo %d\n",SIZE);
//determine the index of the closest values (above and below)
int k = 0;
int oldk = 0;
float min1 = 1e30;
float min2 = 1e30;
float oldmin = 1e30;
float oldmatch = 0.0;
float diff = 0.0;
//the values having the smallest difference
//to the input are computed and the indeces are stored
for(k=0; k<SIZE; k++){
diff = fabs(input - TABLE[k]);
if(diff < min1){
oldmatch = match[0];
match[0] = TABLE[k];
oldk = index[0];
index[0] = k;
oldmin = min1;
min1 = diff;
}
if(diff < min2 && diff != min1){
if(min2 < oldmin){
match[1] = TABLE[k];
index[1] = k;
min2 = diff;
} else {
match[1] = oldmatch;
index[1] = oldk;
min2 = oldmin;
}
}
}
if(withDebugMessages == 1){
printf("closest match#1 for %f is %f with index %d\n", input, match[0], index[0]);
printf("closest match#2 for %f is %f with index %d\n", input, match[1], index[1]);
}
}
/*******************************************************************************/
// Check if the file that is read currently still has the correct redshift value
void checkRedshiftForUpdate(){
#ifndef PY_INTERFACE
float a = get_a_from_CosmicTime(All.Time);
float z = get_Redshift_from_a(a);
#else
float z = 0.0;
#endif
if(fabs(All.CURRENT_TABLE_REDSHIFT - z) >= 0.04){
freeMemory();
if(ThisTask == 0){
updateCoolingTable();
}
BroadcastTablesToAllFromMaster();
}
}
/*******************************************************************************/
// Broadcast tables to all other procs from proc 0
void BroadcastTablesToAllFromMaster(){
if(withDebugMessages == 1 && ThisTask == 0){
printf("broadcasting cooling tables...\n");
}
//broadcast array sizes
MPI_Bcast(&All.SIZE_HYDROGEN_TABLES, 1, MPI_FLOAT, 0, MPI_COMM_WORLD);
MPI_Bcast(&All.SIZE_TEMPERATURE_TABLES, 1, MPI_FLOAT, 0, MPI_COMM_WORLD);
MPI_Bcast(&All.SIZE_HELIUM_ABOUNDANCE_TABLES, 1, MPI_FLOAT, 0, MPI_COMM_WORLD);
//for safety
MPI_Barrier(MPI_COMM_WORLD);
//allocate memory for all procs (except proc 0)
if(ThisTask != 0){
//temporary arrays used to allocate contiguous memory
float* temp1;
float* temp2;
float* temp3;
float** temp4;
float* temp5;
float** temp6;
int i=0;
int j=0;
// 1D arrays
All.HYDROGEN_TABLES = (float*)malloc(All.SIZE_HYDROGEN_TABLES*sizeof(float));
All.TEMPERATURE_TABLES = (float*)malloc(All.SIZE_TEMPERATURE_TABLES*sizeof(float));
All.HELIUM_ABOUNDANCE_TABLES = (float*)malloc(All.SIZE_HELIUM_ABOUNDANCE_TABLES*sizeof(float));
// 2D arrays
// allocate contiguous memory
temp1 = (float*)malloc(All.SIZE_TEMPERATURE_TABLES*All.SIZE_HYDROGEN_TABLES*sizeof(float));
temp2 = (float*)malloc(All.SIZE_TEMPERATURE_TABLES*All.SIZE_HYDROGEN_TABLES*sizeof(float));
//allocate arrays
All.COOLING_TABLES_TOTAL_METAL = (float**)malloc(All.SIZE_TEMPERATURE_TABLES*sizeof(float*));
for(i=0; i<All.SIZE_TEMPERATURE_TABLES; i++){
All.COOLING_TABLES_TOTAL_METAL[i] = &(temp1[i*All.SIZE_HYDROGEN_TABLES]);
}
All.ELECTRON_DENSITY_OVER_N_H_TABLES_SOLAR = (float**)malloc(All.SIZE_TEMPERATURE_TABLES*sizeof(float*));
for(i=0; i<All.SIZE_TEMPERATURE_TABLES; i++){
All.ELECTRON_DENSITY_OVER_N_H_TABLES_SOLAR[i] = &(temp2[i*All.SIZE_HYDROGEN_TABLES]);
}
// 3D arrays
// allocate contiguous memory
temp3 = (float*)malloc(All.SIZE_HELIUM_ABOUNDANCE_TABLES*All.SIZE_TEMPERATURE_TABLES*All.SIZE_HYDROGEN_TABLES*sizeof(float));
temp4 = (float**)malloc(All.SIZE_HELIUM_ABOUNDANCE_TABLES*All.SIZE_TEMPERATURE_TABLES*sizeof(float*));
for(i=0, j=0; i<All.SIZE_HELIUM_ABOUNDANCE_TABLES*All.SIZE_TEMPERATURE_TABLES; i++, j++){
temp4[i] = &(temp3[j*All.SIZE_HYDROGEN_TABLES]);
}
All.COOLING_TABLES_METAL_FREE = (float***)malloc(All.SIZE_HELIUM_ABOUNDANCE_TABLES*sizeof(float**));
for(i=0, j=0; j<All.SIZE_HELIUM_ABOUNDANCE_TABLES; i++, j++){
All.COOLING_TABLES_METAL_FREE[i] = &(temp4[j*All.SIZE_TEMPERATURE_TABLES]);
}
temp5 = (float*)malloc(All.SIZE_HELIUM_ABOUNDANCE_TABLES*All.SIZE_TEMPERATURE_TABLES*All.SIZE_HYDROGEN_TABLES*sizeof(float));
temp6 = (float**)malloc(All.SIZE_HELIUM_ABOUNDANCE_TABLES*All.SIZE_TEMPERATURE_TABLES*sizeof(float*));
for(i=0, j=0; i<All.SIZE_HELIUM_ABOUNDANCE_TABLES*All.SIZE_TEMPERATURE_TABLES; i++, j++){
temp6[i] = &(temp5[j*All.SIZE_HYDROGEN_TABLES]);
}
All.ELECTRON_DENSITY_OVER_N_H_TABLES = (float***)malloc(All.SIZE_HELIUM_ABOUNDANCE_TABLES*sizeof(float**));
for(i=0, j=0; j<All.SIZE_HELIUM_ABOUNDANCE_TABLES; i++, j++){
All.ELECTRON_DENSITY_OVER_N_H_TABLES[i] = &(temp6[j*All.SIZE_TEMPERATURE_TABLES]);
}
}
//broadcast global arrays to all procs from 0
MPI_Bcast(&(All.COOLING_TABLES_TOTAL_METAL[0][0]),
All.SIZE_TEMPERATURE_TABLES*All.SIZE_HYDROGEN_TABLES, MPI_FLOAT,0, MPI_COMM_WORLD);
MPI_Bcast(&(All.COOLING_TABLES_METAL_FREE[0][0][0]),
All.SIZE_HELIUM_ABOUNDANCE_TABLES*All.SIZE_TEMPERATURE_TABLES*All.SIZE_HYDROGEN_TABLES, MPI_FLOAT, 0, MPI_COMM_WORLD);
MPI_Bcast(&(All.ELECTRON_DENSITY_OVER_N_H_TABLES_SOLAR[0][0]),
All.SIZE_TEMPERATURE_TABLES*All.SIZE_HYDROGEN_TABLES, MPI_FLOAT, 0, MPI_COMM_WORLD);
MPI_Bcast(&(All.ELECTRON_DENSITY_OVER_N_H_TABLES[0][0][0]),
All.SIZE_HELIUM_ABOUNDANCE_TABLES*All.SIZE_TEMPERATURE_TABLES*All.SIZE_HYDROGEN_TABLES, MPI_FLOAT, 0, MPI_COMM_WORLD);
MPI_Bcast(All.HYDROGEN_TABLES, All.SIZE_HYDROGEN_TABLES, MPI_FLOAT, 0, MPI_COMM_WORLD);
MPI_Bcast(All.TEMPERATURE_TABLES, All.SIZE_TEMPERATURE_TABLES, MPI_FLOAT, 0, MPI_COMM_WORLD);
MPI_Bcast(All.HELIUM_ABOUNDANCE_TABLES, All.SIZE_HELIUM_ABOUNDANCE_TABLES, MPI_FLOAT, 0, MPI_COMM_WORLD);
MPI_Bcast(&All.CURRENT_TABLE_REDSHIFT, 1, MPI_FLOAT, 0, MPI_COMM_WORLD);
if(withDebugMessages == 1 && ThisTask == 0){
printf("cooling tables broadcasted to all procs\n");
}
}
/*******************************************************************************/
// Function that free memory to avoid overflows
// copy in allocate.c
int freeMemory(){
int error = 0;
// free 3D arrays
if(All.COOLING_TABLES_METAL_FREE){
free(&((All.COOLING_TABLES_METAL_FREE)[0][0]));
free(All.COOLING_TABLES_METAL_FREE);
All.COOLING_TABLES_METAL_FREE = NULL;
}
if(All.ELECTRON_DENSITY_OVER_N_H_TABLES){
free(&((All.ELECTRON_DENSITY_OVER_N_H_TABLES)[0][0]));
free(All.ELECTRON_DENSITY_OVER_N_H_TABLES);
All.ELECTRON_DENSITY_OVER_N_H_TABLES = NULL;
}
// free 2D arrays
if(All.COOLING_TABLES_TOTAL_METAL){
free(All.COOLING_TABLES_TOTAL_METAL);
All.COOLING_TABLES_TOTAL_METAL = NULL;
}
if(All.ELECTRON_DENSITY_OVER_N_H_TABLES_SOLAR){
free(All.ELECTRON_DENSITY_OVER_N_H_TABLES_SOLAR);
All.ELECTRON_DENSITY_OVER_N_H_TABLES_SOLAR = NULL;
}
// free 1D arrays
if(All.HYDROGEN_TABLES){
free(All.HYDROGEN_TABLES);
All.HYDROGEN_TABLES = NULL;
}
if(All.TEMPERATURE_TABLES){
free(All.TEMPERATURE_TABLES);
All.TEMPERATURE_TABLES = NULL;
}
if(All.HELIUM_ABOUNDANCE_TABLES){
free(All.HELIUM_ABOUNDANCE_TABLES);
All.HELIUM_ABOUNDANCE_TABLES = NULL;
}
if(withDebugMessages == 1 && ThisTask == 0){
printf("cooling table memory freed\n");
}
return error;
}
/************************************* Python Interface ************************************/
#ifdef PY_INTERFACE
/*****************************************************/
/* functions declarations */
/*****************************************************/
static PyObject* updateCoolingTableInterface(PyObject *self, PyObject *args) {
int error_status = 0;
error_status = updateCoolingTable();
return Py_BuildValue("d", error_status);
}
static PyObject* BroadcastTablesToAllFromMasterInterface(PyObject *self, PyObject *args) {
BroadcastTablesToAllFromMaster();
return Py_BuildValue("d", 0);
}
static PyObject* computeLambdaInterface(PyObject *self, PyObject *args) {
float rho_H_in;
float T_in;
float nHe_in;
float metalicity;
float lambda = 0.0;
if (!PyArg_ParseTuple(args, "ffff", &rho_H_in, &T_in, &nHe_in, &metalicity)) {
return NULL;
}
//printf("%s\n","computing function with parameters:");
//printf("%s: %g\n","hydrogen density", rho_H_in);
//printf("%s: %g\n","temperature", T_in);
//printf("%s: %g\n","helium aboundance", nHe_in);
//printf("%s: %g\n","metalicity", metalicity);
lambda = computeLambda(rho_H_in, T_in, nHe_in, metalicity);
return Py_BuildValue("f",lambda);
}
static PyObject* freeMemoryInterface(PyObject *self, PyObject *args) {
int error_status;
error_status = freeMemory();
return Py_BuildValue("d",error_status);
}
/*****************************************************/
/* Method table */
/*****************************************************/
static PyMethodDef computeLambdaMethods[] = {
{"updateCoolingTable", updateCoolingTableInterface, METH_VARARGS,
"Update cooling table data using HDF5 tables."},
{"BroadcastTablesToAllFromMaster", BroadcastTablesToAllFromMasterInterface, METH_VARARGS,
"Broadcast tables to all other procs from proc 0."},
{"computeLambda", computeLambdaInterface, METH_VARARGS,
"Compute the cooling from given inputs."},
{"freeMemory", freeMemoryInterface, METH_VARARGS,
"Free allocated memory."},
{NULL, NULL, 0, NULL} /* Sentinel */
};
/*****************************************************/
/* initialization */
/*****************************************************/
//void initcompute_lambda_interface(void)
PyMODINIT_FUNC initcompute_lambda_interface(void) {
(void) Py_InitModule("compute_lambda_interface", computeLambdaMethods);
}
#endif //PY_INTERFACE
#endif //LAMBDA_DEPRAZ
#endif //COOLING
diff --git a/src/predict.c b/src/predict.c
index d2570d6..1c489ef 100644
--- a/src/predict.c
+++ b/src/predict.c
@@ -1,183 +1,190 @@
#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"
/*! \file predict.c
* \brief drift particles by a small time interval
*
* This function contains code to implement a drift operation on all the
* particles, which represents one part of the leapfrog integration scheme.
*/
/*! This function drifts all particles from the current time to the future:
* time0 - > time1
*
* If there is no explicit tree construction in the following timestep, the
* tree nodes are also drifted and updated accordingly. Note: For periodic
* boundary conditions, the mapping of coordinates onto the interval
* [0,All.BoxSize] is only done before the domain decomposition, or for
* outputs to snapshot files. This simplifies dynamic tree updates, and
* allows the domain decomposition to be carried out only every once in a
* while.
*/
void move_particles(int time0, int time1)
{
int i, j;
double dt_drift, dt_gravkick, dt_hydrokick, dt_entr;
double t0, t1;
t0 = second();
if(All.ComovingIntegrationOn)
{
dt_drift = get_drift_factor(time0, time1);
dt_gravkick = get_gravkick_factor(time0, time1);
dt_hydrokick = get_hydrokick_factor(time0, time1);
}
else
{
dt_drift = dt_gravkick = dt_hydrokick = (time1 - time0) * All.Timebase_interval;
}
for(i = 0; i < NumPart; i++)
{
+
+#ifdef GAS_ACCRETION
+ if(P[i].Mass == 0)
+ continue;
+#endif
+
+
for(j = 0; j < 3; j++)
P[i].Pos[j] += P[i].Vel[j] * dt_drift;
if(P[i].Type == 0)
{
#ifdef PMGRID
for(j = 0; j < 3; j++)
{
SphP[i].VelPred[j] += (P[i].GravAccel[j] + P[i].GravPM[j]) * dt_gravkick + SphP[i].HydroAccel[j] * dt_hydrokick;
}
#else
for(j = 0; j < 3; j++)
{
SphP[i].VelPred[j] += P[i].GravAccel[j] * dt_gravkick + SphP[i].HydroAccel[j] * dt_hydrokick;
}
#endif
SphP[i].Density *= exp(-SphP[i].DivVel * dt_drift);
SphP[i].Hsml *= exp(0.333333333333 * SphP[i].DivVel * dt_drift);
if(SphP[i].Hsml < All.MinGasHsml)
SphP[i].Hsml = All.MinGasHsml;
dt_entr = (time1 - (P[i].Ti_begstep + P[i].Ti_endstep) / 2) * All.Timebase_interval;
#ifdef DENSITY_INDEPENDENT_SPH
SphP[i].EgyWtDensity *= exp(-SphP[i].DivVel * dt_drift);
SphP[i].EntVarPred = pow(SphP[i].Entropy + SphP[i].DtEntropy * dt_entr, 1/GAMMA);
SphP[i].Pressure = (SphP[i].Entropy + SphP[i].DtEntropy * dt_entr) * pow(SphP[i].EgyWtDensity, GAMMA);
#else
SphP[i].Pressure = (SphP[i].Entropy + SphP[i].DtEntropy * dt_entr) * pow(SphP[i].Density, GAMMA);
#endif
#ifdef ENTROPYPRED
SphP[i].EntropyPred = (SphP[i].Entropy + SphP[i].DtEntropy * dt_entr);
#endif
#ifdef CHECK_ENTROPY_SIGN
if ((SphP[i].EntropyPred < 0)||(SphP[i].Entropy < 0))
{
printf("\ntask=%d: EntropyPred less than zero in move_particles !\n", ThisTask);
printf("ID=%d Entropy=%g EntropyPred=%g DtEntropy=%g dt_entr=%g\n",P[i].ID,SphP[i].Entropy,SphP[i].EntropyPred,SphP[i].DtEntropy,dt_entr);
fflush(stdout);
endrun(333021);
}
#endif
#ifdef NO_NEGATIVE_PRESSURE
if (SphP[i].Pressure<0)
{
printf("\ntask=%d: pressure less than zero in move_particles !\n", ThisTask);
printf("ID=%d Entropy=%g DtEntropy*dt=%g Density=%g DtEntropy=%g dt=%g\n",P[i].ID,SphP[i].Entropy,SphP[i].DtEntropy*dt_entr,SphP[i].Density,SphP[i].DtEntropy,dt_entr);
fflush(stdout);
endrun(333022);
}
#endif
/***********************************************************/
/* compute art visc coeff */
/***********************************************************/
#if defined(ART_VISCO_MM)|| defined(ART_VISCO_RO) || defined(ART_VISCO_CD)
move_art_visc(i,dt_drift);
#endif
}
}
/* if domain-decomp and tree are not going to be reconstructed, update dynamically. */
if(All.NumForcesSinceLastDomainDecomp < All.TotNumPart * All.TreeDomainUpdateFrequency)
{
for(i = 0; i < Numnodestree; i++)
for(j = 0; j < 3; j++)
Nodes[All.MaxPart + i].u.d.s[j] += Extnodes[All.MaxPart + i].vs[j] * dt_drift;
force_update_len();
force_update_pseudoparticles();
}
t1 = second();
All.CPU_Predict += timediff(t0, t1);
}
/*! This function makes sure that all particle coordinates (Pos) are
* periodically mapped onto the interval [0, BoxSize]. After this function
* has been called, a new domain decomposition should be done, which will
* also force a new tree construction.
*/
#ifdef PERIODIC
void do_box_wrapping(void)
{
int i, j;
double boxsize[3];
for(j = 0; j < 3; j++)
boxsize[j] = All.BoxSize;
#ifdef LONG_X
boxsize[0] *= LONG_X;
#endif
#ifdef LONG_Y
boxsize[1] *= LONG_Y;
#endif
#ifdef LONG_Z
boxsize[2] *= LONG_Z;
#endif
for(i = 0; i < NumPart; i++)
for(j = 0; j < 3; j++)
{
while(P[i].Pos[j] < 0)
P[i].Pos[j] += boxsize[j];
while(P[i].Pos[j] >= boxsize[j])
P[i].Pos[j] -= boxsize[j];
}
}
#endif
diff --git a/src/proto.h b/src/proto.h
index 5fe52e1..670edc3 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -1,553 +1,579 @@
/*! \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 LAMBDA_DEPRAZ
+#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);
+#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_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 chimie_evaluate(int target, int mode);
int chimie_compare_key(const void *a, const void *b);
int get_nelts();
char* get_Element(i);
float get_SolarAbundance(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
#endif
#ifdef OUTERPOTENTIAL
void init_outer_potential(void);
void outer_forces(void);
void outer_potential(void);
#ifdef NFW
void init_outer_potential_nfw(void);
void outer_forces_nfw(void);
void outer_potential_nfw(void);
#endif
#ifdef PLUMMER
void init_outer_potential_plummer(void);
void outer_forces_plummer(void);
void outer_potential_plummer(void);
#endif
#ifdef PISOTHERM
void init_outer_potential_pisotherm(void);
void outer_forces_pisotherm(void);
void outer_potential_pisotherm(void);
double potential_f(double r, void * params);
double get_potential(double r);
#endif
#ifdef CORIOLIS
void init_outer_potential_coriolis(void);
void set_outer_potential_coriolis(void);
void outer_forces_coriolis(void);
void outer_potential_coriolis(void);
#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
#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
void get_sigvel(void);
void get_sigvel_evaluate(int target, int mode);
FLOAT updated_pressure(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 LAMBDA_DEPRAZ
+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 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
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);
#endif
diff --git a/src/run.c b/src/run.c
index 0708276..582e476 100644
--- a/src/run.c
+++ b/src/run.c
@@ -1,837 +1,863 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <mpi.h>
#include <unistd.h>
#include "allvars.h"
#include "proto.h"
/*! \file run.c
* \brief iterates over timesteps, main loop
*/
/*! This routine contains the main simulation loop that iterates over single
* timesteps. The loop terminates when the cpu-time limit is reached, when a
* `stop' file is found in the output directory, or when the simulation ends
* because we arrived at TimeMax.
*/
void run(void)
{
FILE *fd;
int stopflag = 0;
char stopfname[200], contfname[200];
double t0, t1;
#ifdef DETAILED_CPU
double tstart,tend;
#endif
sprintf(stopfname, "%sstop", All.OutputDir);
sprintf(contfname, "%scont", All.OutputDir);
unlink(contfname);
do /* main loop */
{
t0 = second();
find_next_sync_point_and_drift(); /* find next synchronization point and drift particles to this time.
* If needed, this function will also write an output file
* at the desired time.
*/
-
every_timestep_stuff(); /* write some info to log-files */
-
#ifdef PNBODY
compute_pnbody();
#endif
#ifdef OUTPUT_EVERY_TIMESTEP
savepositions(All.SnapshotFileCount++); /* write snapshot file */
#endif
#ifdef DETAILED_CPU
tstart = second();
#endif
#ifdef AGN_ACCRETION
compute_agn_accretion(); /* compute accretion */
#endif
#ifdef BONDI_ACCRETION
compute_bondi_accretion(); /* compute bondi accretion */
#endif
#ifdef BUBBLES
make_bubble(); /* create a bubble */
#endif
#ifdef MULTIPHASE
update_phase(); /* allow particles to change their phase */
#endif
#ifdef CORIOLIS
set_outer_potential_coriolis(); /* coriolis */
#endif
#ifdef CHIMIE
chimie();
#endif
#ifdef SFR
#ifdef COMPUTE_SFR_ENERGY
density(1);
force_update_hmax();
sfr_compute_energy_int(1);
#endif
star_formation(); /* starformation */
#endif
+#ifdef GAS_ACCRETION
+ gas_accretion();
+#endif
+
#ifdef MULTIPHASE
sticky();
#endif
#ifdef DETAILED_CPU
tend = second();
All.CPU_Physics += timediff(tstart, tend);
#endif
-
domain_Decomposition(); /* do domain decomposition if needed */
compute_accelerations(0); /* compute accelerations for
* the particles that are to be advanced
*/
#if defined(SFR) && defined(COMPUTE_SFR_ENERGY)
#ifdef DETAILED_CPU
tstart = second();
#endif
//sfr_compute_energy_int(2);
#ifdef DETAILED_CPU
tend = second();
All.CPU_Physics += timediff(tstart, tend);
#endif
#endif
/* check whether we want a full energy statistics */
if((All.Time - All.TimeLastStatistics) >= All.TimeBetStatistics)
{
#ifdef COMPUTE_POTENTIAL_ENERGY
compute_potential();
#endif
#ifndef ADVANCEDSTATISTICS
energy_statistics(); /* compute and output energy statistics */
#else
advanced_energy_statistics(); /* compute and output energy statistics */
#endif
All.TimeLastStatistics += All.TimeBetStatistics;
}
advance_and_find_timesteps(); /* 'kick' active particles in
* momentum space and compute new
* timesteps for them
*/
All.NumCurrentTiStep++;
/* Check whether we need to interrupt the run */
if(ThisTask == 0)
{
/* Is the stop-file present? If yes, interrupt the run. */
if((fd = fopen(stopfname, "r")))
{
fclose(fd);
stopflag = 1;
unlink(stopfname);
}
/* are we running out of CPU-time ? If yes, interrupt run. */
//if(CPUThisRun > 0.85 * All.TimeLimitCPU)
if(CPUThisRun > 1.0 * All.TimeLimitCPU)
{
printf("reaching time-limit. stopping.\n");
stopflag = 2;
}
}
MPI_Bcast(&stopflag, 1, MPI_INT, 0, MPI_COMM_WORLD);
if(stopflag)
{
restart(0); /* write restart file */
MPI_Barrier(MPI_COMM_WORLD);
if(stopflag == 2 && ThisTask == 0)
{
if((fd = fopen(contfname, "w")))
fclose(fd);
}
if(stopflag == 2 && All.ResubmitOn && ThisTask == 0)
{
close_outputfiles();
system(All.ResubmitCommand);
}
return;
}
/* is it time to write a regular restart-file? (for security) */
if(ThisTask == 0)
{
if((CPUThisRun - All.TimeLastRestartFile) >= All.CpuTimeBetRestartFile)
{
All.TimeLastRestartFile = CPUThisRun;
stopflag = 3;
}
else
stopflag = 0;
}
MPI_Bcast(&stopflag, 1, MPI_INT, 0, MPI_COMM_WORLD);
if(stopflag == 3)
{
restart(0); /* write an occasional restart file */
stopflag = 0;
}
t1 = second();
All.CPU_Total += timediff(t0, t1);
CPUThisRun += timediff(t0, t1);
}
while(All.Ti_Current < TIMEBASE && All.Time <= All.TimeMax);
restart(0);
savepositions(All.SnapshotFileCount++); /* write a last snapshot
* file at final time (will
* be overwritten if
* All.TimeMax is increased
* and the run is continued)
*/
}
/*! This function finds the next synchronization point of the system (i.e. the
* earliest point of time any of the particles needs a force computation),
* and drifts the system to this point of time. If the system drifts over
* the desired time of a snapshot file, the function will drift to this
* moment, generate an output, and then resume the drift.
*/
void find_next_sync_point_and_drift(void)
{
int n, min, min_glob, flag, *temp;
double timeold;
double t0, t1;
#ifdef DETAILED_CPU
double tstart,tend;
#endif
t0 = second();
#ifdef DETAILED_CPU
tstart = t0;
#endif
timeold = All.Time;
+
+
+#ifdef GAS_ACCRETION
+
+ for(n = 0; n < NumPart; n++)
+ if(P[n].Mass!=0)
+ {
+ min = P[n].Ti_endstep;
+ break;
+ }
+
+ for(n = 0; n < NumPart; n++)
+ {
+
+ if(P[n].Mass==0)
+ continue;
+
+ if(min > P[n].Ti_endstep)
+ min = P[n].Ti_endstep;
+ }
+
+#else
for(n = 1, min = P[0].Ti_endstep; n < NumPart; n++)
if(min > P[n].Ti_endstep)
min = P[n].Ti_endstep;
+#endif
+
+
MPI_Allreduce(&min, &min_glob, 1, MPI_INT, MPI_MIN, MPI_COMM_WORLD);
/* We check whether this is a full step where all particles are synchronized */
flag = 1;
for(n = 0; n < NumPart; n++)
if(P[n].Ti_endstep > min_glob)
flag = 0;
MPI_Allreduce(&flag, &Flag_FullStep, 1, MPI_INT, MPI_MIN, MPI_COMM_WORLD);
#ifdef PMGRID
if(min_glob >= All.PM_Ti_endstep)
{
min_glob = All.PM_Ti_endstep;
Flag_FullStep = 1;
}
#endif
/* Determine 'NumForceUpdate', i.e. the number of particles on this processor that are going to be active */
for(n = 0, NumForceUpdate = 0; n < NumPart; n++)
{
if(P[n].Ti_endstep == min_glob)
#ifdef SELECTIVE_NO_GRAVITY
if(!((1 << P[n].Type) & (SELECTIVE_NO_GRAVITY)))
#endif
NumForceUpdate++;
}
/* note: NumForcesSinceLastDomainDecomp has type "long long" */
temp = malloc(NTask * sizeof(int));
MPI_Allgather(&NumForceUpdate, 1, MPI_INT, temp, 1, MPI_INT, MPI_COMM_WORLD);
for(n = 0; n < NTask; n++)
All.NumForcesSinceLastDomainDecomp += temp[n];
#ifdef COUNT_ACTIVE_PARTICLES
long long NumActivePatricles;
NumActivePatricles=0;
for(n = 0; n < NTask; n++)
NumActivePatricles+=temp[n];
#endif
free(temp);
t1 = second();
All.CPU_Predict += timediff(t0, t1);
while(min_glob >= All.Ti_nextoutput && All.Ti_nextoutput >= 0)
{
move_particles(All.Ti_Current, All.Ti_nextoutput);
All.Ti_Current = All.Ti_nextoutput;
if(All.ComovingIntegrationOn)
All.Time = All.TimeBegin * exp(All.Ti_Current * All.Timebase_interval);
else
All.Time = All.TimeBegin + All.Ti_Current * All.Timebase_interval;
#ifdef OUTPUTPOTENTIAL
All.NumForcesSinceLastDomainDecomp = 1 + All.TotNumPart * All.TreeDomainUpdateFrequency;
domain_Decomposition();
compute_potential();
#endif
#ifndef OUTPUT_EVERY_TIMESTEP
savepositions(All.SnapshotFileCount++); /* write snapshot file */
#endif
All.Ti_nextoutput = find_next_outputtime(All.Ti_nextoutput + 1);
}
move_particles(All.Ti_Current, min_glob);
All.Ti_Current = min_glob;
if(All.ComovingIntegrationOn)
All.Time = All.TimeBegin * exp(All.Ti_Current * All.Timebase_interval);
else
All.Time = All.TimeBegin + All.Ti_Current * All.Timebase_interval;
All.TimeStep = All.Time - timeold;
#ifdef COUNT_ACTIVE_PARTICLES
if (ThisTask==0)
{
fprintf(FdTimings,"===========================================================================================\n");
fprintf(FdTimings,"Step = %06d Time = %g \n\n",All.NumCurrentTiStep,All.Time);
fprintf(FdTimings,"%g %g : Total number of active particles : %d%09d\n\n",All.Time,All.TimeStep,(int) (NumActivePatricles / 1000000000), (int) (NumActivePatricles % 1000000000));
}
int *numpartlist;
int i;
int tot;
numpartlist = malloc(sizeof(int) * NTask*6);
MPI_Gather(&N_gas, 1, MPI_INT, &numpartlist[NTask*0], 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Gather(&N_stars, 1, MPI_INT, &numpartlist[NTask*1], 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Gather(&NumPart, 1, MPI_INT, &numpartlist[NTask*2], 1, MPI_INT, 0, MPI_COMM_WORLD);
if (ThisTask==0)
{
tot = 0;
fprintf(FdTimings,"gas ");
for (i=0;i<NTask;i++)
{
fprintf(FdTimings, "%12d ",numpartlist[NTask*0+i]); /* nombre de part par proc */
tot += numpartlist[NTask*0+i];
}
fprintf(FdTimings, " : %12d ",tot);
fprintf(FdTimings,"\n");
tot = 0;
fprintf(FdTimings,"stars ");
for (i=0;i<NTask;i++)
{
fprintf(FdTimings, "%12d ",numpartlist[NTask*1+i]); /* nombre de part par proc */
tot += numpartlist[NTask*1+i];
}
fprintf(FdTimings, " : %12d ",tot);
fprintf(FdTimings,"\n");
tot = 0;
fprintf(FdTimings,"remaining ");
for (i=0;i<NTask;i++)
{
fprintf(FdTimings, "%12d ",numpartlist[NTask*2+i]-numpartlist[NTask*1+i]-numpartlist[NTask*0+i]); /* nombre de part par proc */
tot += numpartlist[NTask*2+i]-numpartlist[NTask*1+i]-numpartlist[NTask*0+i];
}
fprintf(FdTimings, " : %12d ",tot);
fprintf(FdTimings,"\n\n");
tot = 0;
fprintf(FdTimings,"total ");
for (i=0;i<NTask;i++)
{
fprintf(FdTimings, "%12d ",numpartlist[NTask*2+i]); /* nombre de part par proc */
tot += numpartlist[NTask*2+i];
}
fprintf(FdTimings, " : %12d ",tot);
fprintf(FdTimings,"\n\n");
fflush(FdTimings);
}
free(numpartlist);
#endif
#ifdef DETAILED_CPU
tend = second();
All.CPU_Leapfrog += timediff(tstart, tend);
#endif
}
/*! this function returns the next output time that is equal or larger to
* ti_curr
*/
int find_next_outputtime(int ti_curr)
{
int i, ti, ti_next, iter = 0;
double next, time;
ti_next = -1;
if(All.OutputListOn)
{
for(i = 0; i < All.OutputListLength; i++)
{
time = All.OutputListTimes[i];
if(time >= All.TimeBegin && time <= All.TimeMax)
{
if(All.ComovingIntegrationOn)
ti = log(time / All.TimeBegin) / All.Timebase_interval;
else
ti = (time - All.TimeBegin) / All.Timebase_interval;
if(ti >= ti_curr)
{
if(ti_next == -1)
ti_next = ti;
if(ti_next > ti)
ti_next = ti;
}
}
}
}
else
{
if(All.ComovingIntegrationOn)
{
if(All.TimeBetSnapshot <= 1.0)
{
printf("TimeBetSnapshot > 1.0 required for your simulation.\n");
endrun(13123);
}
}
else
{
if(All.TimeBetSnapshot <= 0.0)
{
printf("TimeBetSnapshot > 0.0 required for your simulation.\n");
endrun(13123);
}
}
time = All.TimeOfFirstSnapshot;
iter = 0;
while(time < All.TimeBegin)
{
if(All.ComovingIntegrationOn)
time *= All.TimeBetSnapshot;
else
time += All.TimeBetSnapshot;
iter++;
if(iter > 1000000)
{
printf("Can't determine next output time.\n");
endrun(110);
}
}
while(time <= All.TimeMax)
{
if(All.ComovingIntegrationOn)
ti = log(time / All.TimeBegin) / All.Timebase_interval;
else
ti = (time - All.TimeBegin) / All.Timebase_interval;
if(ti >= ti_curr)
{
ti_next = ti;
break;
}
if(All.ComovingIntegrationOn)
time *= All.TimeBetSnapshot;
else
time += All.TimeBetSnapshot;
iter++;
if(iter > 1000000)
{
printf("Can't determine next output time.\n");
endrun(111);
}
}
}
if(ti_next == -1)
{
ti_next = 2 * TIMEBASE; /* this will prevent any further output */
if(ThisTask == 0)
printf("\nThere is no valid time for a further snapshot file.\n");
}
else
{
if(All.ComovingIntegrationOn)
next = All.TimeBegin * exp(ti_next * All.Timebase_interval);
else
next = All.TimeBegin + ti_next * All.Timebase_interval;
if(ThisTask == 0)
printf("\nSetting next time for snapshot file to Time_next= %g\n\n", next);
}
return ti_next;
}
/*! This routine writes one line for every timestep to two log-files. In
* FdInfo, we just list the timesteps that have been done, while in FdCPU the
* cumulative cpu-time consumption in various parts of the code is stored.
*/
void every_timestep_stuff(void)
{
double z;
#ifdef DETAILED_CPU
double tstart,tend;
tstart = second();
#endif
if(ThisTask == 0)
{
if(All.ComovingIntegrationOn)
{
z = 1.0 / (All.Time) - 1;
fprintf(FdInfo, "\nBegin Step %d, Time: %g, Redshift: %g, Systemstep: %g, Dloga: %g\n",
All.NumCurrentTiStep, All.Time, z, All.TimeStep,
log(All.Time) - log(All.Time - All.TimeStep));
printf("\nBegin Step %d, Time: %g, Redshift: %g, Systemstep: %g, Dloga: %g\n", All.NumCurrentTiStep,
All.Time, z, All.TimeStep, log(All.Time) - log(All.Time - All.TimeStep));
fflush(FdInfo);
}
else
{
fprintf(FdInfo, "\nBegin Step %d, Time: %g, Systemstep: %g\n", All.NumCurrentTiStep, All.Time,
All.TimeStep);
printf("\nBegin Step %d, Time: %g, Systemstep: %g\n", All.NumCurrentTiStep, All.Time, All.TimeStep);
fflush(FdInfo);
}
printf("-------------------------------------------------------------\n");
fflush(stdout);
#ifdef ADVANCEDCPUSTATISTICS
fprintf(FdCPU, "%d ", All.NumCurrentTiStep);
fprintf(FdCPU, "%g ", All.Time);
fprintf(FdCPU, "%d ", NTask);
fprintf(FdCPU,"%10.2f ",All.CPU_Total);
#ifdef DETAILED_CPU
fprintf(FdCPU,"%10.2f ",All.CPU_Leapfrog);
fprintf(FdCPU,"%10.2f ",All.CPU_Physics);
fprintf(FdCPU,"%10.2f ",All.CPU_Residual);
fprintf(FdCPU,"%10.2f ",All.CPU_Accel);
fprintf(FdCPU,"%10.2f ",All.CPU_Begrun);
#endif
fprintf(FdCPU,"%10.2f ",All.CPU_Gravity);
fprintf(FdCPU,"%10.2f ",All.CPU_Hydro);
#ifdef COOLING
fprintf(FdCPU,"%10.2f ",All.CPU_Cooling);
#endif
#ifdef SFR
fprintf(FdCPU,"%10.2f ",All.CPU_StarFormation);
#endif
#ifdef CHIMIE
fprintf(FdCPU,"%10.2f ",All.CPU_Chimie);
#endif
#ifdef MULTIPHASE
fprintf(FdCPU,"%10.2f ",All.CPU_Sticky);
#endif
fprintf(FdCPU,"%10.2f ",All.CPU_Domain);
fprintf(FdCPU,"%10.2f ",All.CPU_Potential);
fprintf(FdCPU,"%10.2f ",All.CPU_Predict);
fprintf(FdCPU,"%10.2f ",All.CPU_TimeLine);
fprintf(FdCPU,"%10.2f ",All.CPU_Snapshot);
fprintf(FdCPU,"%10.2f ",All.CPU_TreeWalk);
fprintf(FdCPU,"%10.2f ",All.CPU_TreeConstruction);
fprintf(FdCPU,"%10.2f ",All.CPU_CommSum);
fprintf(FdCPU,"%10.2f ",All.CPU_Imbalance);
fprintf(FdCPU,"%10.2f ",All.CPU_HydCompWalk);
fprintf(FdCPU,"%10.2f ",All.CPU_HydCommSumm);
fprintf(FdCPU,"%10.2f ",All.CPU_HydImbalance);
fprintf(FdCPU,"%10.2f ",All.CPU_EnsureNgb);
fprintf(FdCPU,"%10.2f ",All.CPU_PM);
fprintf(FdCPU,"%10.2f ",All.CPU_Peano);
#ifdef DETAILED_CPU_DOMAIN
fprintf(FdCPU,"%10.2f ",All.CPU_Domain_findExtend);
fprintf(FdCPU,"%10.2f ",All.CPU_Domain_determineTopTree);
fprintf(FdCPU,"%10.2f ",All.CPU_Domain_sumCost);
fprintf(FdCPU,"%10.2f ",All.CPU_Domain_findSplit);
fprintf(FdCPU,"%10.2f ",All.CPU_Domain_shiftSplit);
fprintf(FdCPU,"%10.2f ",All.CPU_Domain_countToGo);
fprintf(FdCPU,"%10.2f ",All.CPU_Domain_exchange);
#endif
#ifdef DETAILED_CPU_GRAVITY
fprintf(FdCPU,"%10.2f ",All.CPU_Gravity_TreeWalk1);
fprintf(FdCPU,"%10.2f ",All.CPU_Gravity_TreeWalk2);
fprintf(FdCPU,"%10.2f ",All.CPU_Gravity_CommSum1);
fprintf(FdCPU,"%10.2f ",All.CPU_Gravity_CommSum2);
fprintf(FdCPU,"%10.2f ",All.CPU_Gravity_Imbalance1);
fprintf(FdCPU,"%10.2f ",All.CPU_Gravity_Imbalance2);
#endif
fprintf(FdCPU,"\n");
fflush(FdCPU);
#else
fprintf(FdCPU, "Step %d, Time: %g, CPUs: %d\n", All.NumCurrentTiStep, All.Time, NTask);
fprintf(FdCPU,
"%10.2f %10.2f %10.2f %10.2f %10.2f %10.2f %10.2f %10.2f %10.2f %10.2f %10.2f %10.2f %10.2f %10.2f %10.2f %10.2f %10.2f %10.2f\n",
All.CPU_Total, All.CPU_Gravity, All.CPU_Hydro, All.CPU_Domain, All.CPU_Potential,
All.CPU_Predict, All.CPU_TimeLine, All.CPU_Snapshot, All.CPU_TreeWalk, All.CPU_TreeConstruction,
All.CPU_CommSum, All.CPU_Imbalance, All.CPU_HydCompWalk, All.CPU_HydCommSumm,
All.CPU_HydImbalance, All.CPU_EnsureNgb, All.CPU_PM, All.CPU_Peano);
fflush(FdCPU);
#endif
}
set_random_numbers();
#ifdef DETAILED_CPU
tend = second();
All.CPU_Residual += timediff(tstart, tend);
#endif
}
/*! This routine first calls a computation of various global quantities of the
* particle distribution, and then writes some statistics about the energies
* in the various particle components to the file FdEnergy.
*/
void energy_statistics(void)
{
compute_global_quantities_of_system();
if(ThisTask == 0)
{
fprintf(FdEnergy,
"%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g\n",
All.Time, SysState.EnergyInt, SysState.EnergyPot, SysState.EnergyKin, SysState.EnergyIntComp[0],
SysState.EnergyPotComp[0], SysState.EnergyKinComp[0], SysState.EnergyIntComp[1],
SysState.EnergyPotComp[1], SysState.EnergyKinComp[1], SysState.EnergyIntComp[2],
SysState.EnergyPotComp[2], SysState.EnergyKinComp[2], SysState.EnergyIntComp[3],
SysState.EnergyPotComp[3], SysState.EnergyKinComp[3], SysState.EnergyIntComp[4],
SysState.EnergyPotComp[4], SysState.EnergyKinComp[4], SysState.EnergyIntComp[5],
SysState.EnergyPotComp[5], SysState.EnergyKinComp[5], SysState.MassComp[0],
SysState.MassComp[1], SysState.MassComp[2], SysState.MassComp[3], SysState.MassComp[4],
SysState.MassComp[5]);
fflush(FdEnergy);
}
}
/*! This routine first calls a computation of various global quantities of the
* particle distribution, and then writes some statistics about the energies
* in the various particle components to the file FdEnergy.
*/
#ifdef ADVANCEDSTATISTICS
void advanced_energy_statistics(void)
{
int i;
#ifdef DETAILED_CPU
double tstart,tend;
tstart = second();
#endif
compute_global_quantities_of_system();
if(ThisTask == 0)
{
/**************/
/* energy */
/**************/
/* time */
fprintf(FdEnergy,"%g ",All.Time);
/* total */
fprintf(FdEnergy,"%g %g %g ",SysState.EnergyInt, SysState.EnergyPot, SysState.EnergyKin);
#ifdef COOLING
fprintf(FdEnergy,"%g ",SysState.EnergyRadSph);
#endif
#ifdef AGN_HEATING
fprintf(FdEnergy,"%g ",SysState.EnergyAGNHeat);
#endif
#ifdef MULTIPHASE
fprintf(FdEnergy,"%g ",SysState.EnergyRadSticky);
#endif
#ifdef FEEDBACK_WIND
fprintf(FdEnergy,"%g ",SysState.EnergyFeedbackWind);
#endif
#ifdef BUBBLES
fprintf(FdEnergy,"%g ",SysState.EnergyBubbles);
#endif
#ifdef CHIMIE_THERMAL_FEEDBACK
fprintf(FdEnergy,"%g ",SysState.EnergyThermalFeedback);
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
fprintf(FdEnergy,"%g ",SysState.EnergyKineticFeedback);
#endif
/* comp */
for (i=0;i<6;i++)
{
fprintf(FdEnergy,"%g %g %g ",SysState.EnergyIntComp[i],SysState.EnergyPotComp[i], SysState.EnergyKinComp[i]);
#ifdef COOLING
fprintf(FdEnergy,"%g ",SysState.EnergyRadSphComp[i]);
#endif
#ifdef AGN_HEATING
fprintf(FdEnergy,"%g ",SysState.EnergyAGNHeatComp[i]);
#endif
#ifdef MULTIPHASE
fprintf(FdEnergy,"%g ",SysState.EnergyRadStickyComp[i]);
#endif
#ifdef FEEDBACK_WIND
fprintf(FdEnergy,"%g ",SysState.EnergyFeedbackWindComp[i]);
#endif
#ifdef BUBBLES
fprintf(FdEnergy,"%g ",SysState.EnergyBubblesComp[i]);
#endif
#ifdef CHIMIE_THERMAL_FEEDBACK
fprintf(FdEnergy,"%g ",SysState.EnergyThermalFeedbackComp[i]);
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
fprintf(FdEnergy,"%g ",SysState.EnergyKineticFeedbackComp[i]);
#endif
}
/* mass */
for (i=0;i<6;i++)
{
fprintf(FdEnergy,"%g ",SysState.MassComp[i]);
}
/* return */
fprintf(FdEnergy,"\n");
fflush(FdEnergy);
#ifdef SYSTEMSTATISTICS
/**************/
/* system */
/**************/
fprintf(FdSystem,"%g %g %g %g %g %g %g %g %g %g %g %g %g\n",
All.Time,
SysState.Momentum[0], SysState.Momentum[1], SysState.Momentum[2], SysState.Momentum[3],
SysState.AngMomentum[0], SysState.AngMomentum[1], SysState.AngMomentum[2], SysState.AngMomentum[3],
SysState.CenterOfMass[0], SysState.CenterOfMass[1], SysState.CenterOfMass[2], SysState.CenterOfMass[3]);
fflush(FdSystem);
#endif
}
#ifdef DETAILED_CPU
tend = second();
All.CPU_Residual += timediff(tstart, tend);
#endif
}
#endif
diff --git a/src/stars_density.c b/src/stars_density.c
index 7aca1fe..6ecb1e6 100644
--- a/src/stars_density.c
+++ b/src/stars_density.c
@@ -1,719 +1,723 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <mpi.h>
#include "allvars.h"
#include "proto.h"
/*! \file density.c
* \brief SPH density computation and smoothing length determination
*
* This file contains the "first SPH loop", where the SPH densities and
* some auxiliary quantities are computed. If the number of neighbours
* obtained falls outside the target range, the correct smoothing
* length is determined iteratively, if needed.
*/
#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
#ifdef CHIMIE
/*! This function computes the local density for each active SPH particle,
* the number of neighbours in the current smoothing radius, and the
* divergence and curl of the velocity field. The pressure is updated as
* well. If a particle with its smoothing region is fully inside the
* local domain, it is not exported to the other processors. The function
* also detects particles that have a number of neighbours outside the
* allowed tolerance range. For these particles, the smoothing length is
* adjusted accordingly, and the density computation is executed again.
* Note that the smoothing length is not allowed to fall below the lower
* bound set by MinGasHsml.
*/
void stars_density(void)
{
long long ntot, ntotleft;
int *noffset, *nbuffer, *nsend, *nsend_local, *numlist, *ndonelist;
int i, j, n,m, ndone, npleft, maxfill, source, iter = 0;
int level, ngrp, sendTask, recvTask, place, nexport;
double tstart, tend, tstart_ngb = 0, tend_ngb = 0;
double sumt, sumcomm, timengb, sumtimengb;
double timecomp = 0, timeimbalance = 0, timecommsumm = 0, sumimbalance;
MPI_Status status;
#ifdef DETAILED_CPU_OUTPUT_IN_STARS_DENSITY
double *timengblist;
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
if (ThisTask==0)
printf("Start star density computation.\n");
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);
/* `NumStUpdate' gives the number of particles on this processor that want a chimie computation */
for(n = N_gas, NumStUpdate = 0; n < N_gas+N_stars; n++)
{
m = P[n].StPIdx;
StP[m].Left = StP[m].Right = 0;
#ifdef AVOIDNUMNGBPROBLEM
StP[m].OldNumNgb = -1;
#endif
if(P[n].Ti_endstep == All.Ti_Current)
NumStUpdate++;
}
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);
/* we will repeat the whole thing for those particles where we didn't
* find enough neighbours
*/
do
{
i = N_gas; /* beginn with the first star */
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 */
tstart = second();
for(nexport = 0, ndone = 0; i < N_gas+N_stars && nexport < All.BunchSizeDensity - NTask; i++)
if(P[i].Ti_endstep == All.Ti_Current)
{
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(666001);
}
ndone++;
m = P[i].StPIdx;
for(j = 0; j < NTask; j++)
Exportflag[j] = 0;
stars_density_evaluate(i, 0);
for(j = 0; j < NTask; j++)
{
if(Exportflag[j])
{
StarsDensDataIn[nexport].Pos[0] = P[i].Pos[0];
StarsDensDataIn[nexport].Pos[1] = P[i].Pos[1];
StarsDensDataIn[nexport].Pos[2] = P[i].Pos[2];
StarsDensDataIn[nexport].Hsml = StP[m].Hsml;
StarsDensDataIn[nexport].Index = i;
StarsDensDataIn[nexport].Task = j;
nexport++;
nsend_local[j]++;
}
}
}
tend = second();
timecomp += timediff(tstart, tend);
qsort(StarsDensDataIn, nexport, sizeof(struct starsdensdata_in), stars_dens_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.BunchSizeDensity)
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(&StarsDensDataIn[noffset[recvTask]],
nsend_local[recvTask] * sizeof(struct starsdensdata_in), MPI_BYTE,
recvTask, TAG_DENS_A,
&StarsDensDataGet[nbuffer[ThisTask]],
nsend[recvTask * NTask + ThisTask] * sizeof(struct starsdensdata_in),
MPI_BYTE, recvTask, TAG_DENS_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);
tstart = second();
for(j = 0; j < nbuffer[ThisTask]; j++)
stars_density_evaluate(j, 1);
tend = second();
timecomp += timediff(tstart, tend);
/* do a block to explicitly 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.BunchSizeDensity)
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(&StarsDensDataResult[nbuffer[ThisTask]],
nsend[recvTask * NTask + ThisTask] * sizeof(struct starsdensdata_out),
MPI_BYTE, recvTask, TAG_DENS_B,
&StarsDensDataPartialResult[noffset[recvTask]],
nsend_local[recvTask] * sizeof(struct starsdensdata_out),
MPI_BYTE, recvTask, TAG_DENS_B, MPI_COMM_WORLD, &status);
/* add the result to the particles */
for(j = 0; j < nsend_local[recvTask]; j++)
{
source = j + noffset[recvTask];
place = P[StarsDensDataIn[source].Index].StPIdx;
StP[place].NumNgb += StarsDensDataPartialResult[source].Ngb;
StP[place].Density += StarsDensDataPartialResult[source].Rho;
StP[place].Volume += StarsDensDataPartialResult[source].Volume;
#ifdef CHIMIE_KINETIC_FEEDBACK
StP[place].NgbMass += StarsDensDataPartialResult[source].NgbMass;
#endif
StP[place].DhsmlDensityFactor += StarsDensDataPartialResult[source].DhsmlDensity;
}
}
}
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];
}
/* do final operations on results */
tstart = second();
for(i = N_gas, npleft = 0; i < N_gas+N_stars; i++)
{
if((P[i].Ti_endstep == All.Ti_Current))
{
m = P[i].StPIdx;
StP[m].DhsmlDensityFactor =
1 / (1 + StP[m].Hsml * StP[m].DhsmlDensityFactor / (NUMDIMS * StP[m].Density));
/* now check whether we had enough neighbours */
if(StP[m].NumNgb < (All.DesNumNgb - All.MaxNumNgbDeviation) ||
(StP[m].NumNgb > (All.DesNumNgb + All.MaxNumNgbDeviation)
&& StP[m].Hsml > (1.01 * All.MinGasHsml)))
{
#ifdef AVOIDNUMNGBPROBLEM
// if((StP[m].NumNgb>StP[m].OldNumNgb-All.MaxNumNgbDeviation/10000.)
// &&(StP[m].NumNgb<StP[m].OldNumNgb+All.MaxNumNgbDeviation/10000.))
if(StP[m].NumNgb==StP[m].OldNumNgb)
{
P[i].Ti_endstep = -P[i].Ti_endstep - 1;
printf("ID=%d NumNgb=%g OldNumNgb=%g\n",P[i].ID,StP[m].NumNgb,StP[m].OldNumNgb);
continue;
}
StP[m].OldNumNgb = StP[m].NumNgb;
#endif
/* need to redo this particle */
npleft++;
if(StP[m].Left > 0 && StP[m].Right > 0)
if((StP[m].Right - StP[m].Left) < 1.0e-3 * StP[m].Left)
{
/* this one should be ok */
npleft--;
P[i].Ti_endstep = -P[i].Ti_endstep - 1; /* Mark as inactive */
continue;
}
if(StP[m].NumNgb < (All.DesNumNgb - All.MaxNumNgbDeviation))
StP[m].Left = dmax(StP[m].Hsml, StP[m].Left);
else
{
if(StP[m].Right != 0)
{
if(StP[m].Hsml < StP[m].Right)
StP[m].Right = StP[m].Hsml;
}
else
StP[m].Right = StP[m].Hsml;
}
if(iter >= MAXITER - 10)
{
printf
("i=%d task=%d ID=%d Hsml=%g Left=%g Right=%g Ngbs=%g Right-Left=%g\n pos=(%g|%g|%g)\n",
i, ThisTask, (int) P[i].ID, StP[m].Hsml, StP[m].Left, StP[m].Right,
(float) StP[m].NumNgb, StP[m].Right - StP[m].Left, P[i].Pos[0], P[i].Pos[1],
P[i].Pos[2]);
fflush(stdout);
}
if(StP[m].Right > 0 && StP[m].Left > 0)
StP[m].Hsml = pow(0.5 * (pow(StP[m].Left, 3) + pow(StP[m].Right, 3)), 1.0 / 3);
else
{
if(StP[m].Right == 0 && StP[m].Left == 0)
{
printf
("i=%d task=%d ID=%d Hsml=%g Left=%g Right=%g Ngbs=%g Right-Left=%g\n pos=(%g|%g|%g)\n",
i, ThisTask, (int) P[i].ID, StP[m].Hsml, StP[m].Left, StP[m].Right,
(float) StP[m].NumNgb, StP[m].Right - StP[m].Left, P[i].Pos[0], P[i].Pos[1],
P[i].Pos[2]);
fflush(stdout);
endrun(8188); /* can't occur */
}
if(StP[m].Right == 0 && StP[m].Left > 0)
{
if(P[i].Type == ST && fabs(StP[m].NumNgb - All.DesNumNgb) < 0.5 * All.DesNumNgb)
{
StP[m].Hsml *=
1 - (StP[m].NumNgb -
All.DesNumNgb) / (NUMDIMS * StP[m].NumNgb) * StP[m].DhsmlDensityFactor;
}
else
StP[m].Hsml *= 1.26;
}
if(StP[m].Right > 0 && StP[m].Left == 0)
{
if(P[i].Type == ST && fabs(StP[m].NumNgb - All.DesNumNgb) < 0.5 * All.DesNumNgb)
{
StP[m].Hsml *=
1 - (StP[m].NumNgb -
All.DesNumNgb) / (NUMDIMS * StP[m].NumNgb) * StP[m].DhsmlDensityFactor;
}
else
StP[m].Hsml /= 1.26;
}
}
if(StP[m].Hsml < All.MinGasHsml)
StP[m].Hsml = All.MinGasHsml;
}
else
P[i].Ti_endstep = -P[i].Ti_endstep - 1; /* Mark as inactive */
}
}
tend = second();
timecomp += timediff(tstart, tend);
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)
{
if(iter == 0)
tstart_ngb = second();
iter++;
if(iter > 0 && ThisTask == 0)
{
printf("ngb iteration %d: need to repeat for %d%09d particles.\n", iter,
(int) (ntot / 1000000000), (int) (ntot % 1000000000));
fflush(stdout);
}
if(iter > MAXITER)
{
printf("failed to converge in neighbour iteration in density()\n");
fflush(stdout);
endrun(1155);
}
}
else
tend_ngb = second();
}
while(ntot > 0);
/* mark as active again */
for(i = 0; i < NumPart; i++)
if(P[i].Ti_endstep < 0)
- P[i].Ti_endstep = -P[i].Ti_endstep - 1;
+#ifdef GAS_ACCRETION
+ if (P[i].Mass!=0)
+#endif
+ P[i].Ti_endstep = -P[i].Ti_endstep - 1;
+
free(ndonelist);
free(nsend);
free(nsend_local);
free(nbuffer);
free(noffset);
/* collect some timing information */
if(iter > 0)
timengb = timediff(tstart_ngb, tend_ngb);
else
timengb = 0;
MPI_Reduce(&timengb, &sumtimengb, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
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);
#ifdef DETAILED_CPU_OUTPUT_IN_STARS_DENSITY
numlist = malloc(sizeof(int) * NTask);
timengblist = malloc(sizeof(double) * 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(&timengb, 1, MPI_DOUBLE, timengblist, 1, MPI_DOUBLE, 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 stars density \n\n");
fprintf(FdTimings, "Nupdate ");
for (i=0;i<NTask;i++)
fprintf(FdTimings, "%12d ",numlist[i]);
fprintf(FdTimings, "\n");
fprintf(FdTimings, "timengb ");
for (i=0;i<NTask;i++)
fprintf(FdTimings, "%12g ",timengblist[i]);
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(timengblist);
free(numlist);
#endif
if(ThisTask == 0)
{
All.CPU_ChimieDensCompWalk += sumt / NTask;
All.CPU_ChimieDensCommSumm += sumcomm / NTask;
All.CPU_ChimieDensImbalance += sumimbalance / NTask;
All.CPU_ChimieDensEnsureNgb += sumtimengb / NTask;
}
if (ThisTask==0)
printf("Stars density computation done.\n");
}
/*! This function represents the core of the SPH density computation. The
* target particle may either be local, or reside in the communication
* buffer.
*/
void stars_density_evaluate(int target, int mode)
{
int j, n, startnode, numngb, numngb_inbox;
double h, h2, hinv, hinv3, hinv4;
double rho, volume, wk, dwk;
double dx, dy, dz, r, r2, u, mass_j,rho_j;
double weighted_numngb, dhsmlrho;
int target_stp;
FLOAT *pos;
#ifdef CHIMIE_KINETIC_FEEDBACK
double ngbmass;
#endif
if(mode == 0)
{
pos = P[target].Pos;
target_stp = P[target].StPIdx;
h = StP[target_stp].Hsml;
}
else
{
pos = StarsDensDataGet[target].Pos;
h = StarsDensDataGet[target].Hsml;
}
h2 = h * h;
hinv = 1.0 / h;
#ifndef TWODIMS
hinv3 = hinv * hinv * hinv;
#else
hinv3 = hinv * hinv / boxSize_Z;
#endif
hinv4 = hinv3 * hinv;
rho = 0;
volume = 0;
weighted_numngb = 0;
dhsmlrho = 0;
#ifdef CHIMIE_KINETIC_FEEDBACK
ngbmass=0;
#endif
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);
dwk = hinv4 * u * (KERNEL_COEFF_3 * u - KERNEL_COEFF_4);
}
else
{
wk = hinv3 * KERNEL_COEFF_5 * (1.0 - u) * (1.0 - u) * (1.0 - u);
dwk = hinv4 * KERNEL_COEFF_6 * (1.0 - u) * (1.0 - u);
}
mass_j = P[j].Mass;
rho_j = SphP[j].Density;
rho += mass_j * wk;
volume += mass_j/rho_j * wk;
weighted_numngb += NORM_COEFF * wk / hinv3;
dhsmlrho += -mass_j * (NUMDIMS * hinv * wk + u * dwk);
#ifdef CHIMIE_KINETIC_FEEDBACK
ngbmass += mass_j;
#endif
}
}
}
while(startnode >= 0);
if(mode == 0)
{
StP[target_stp].NumNgb = weighted_numngb;
StP[target_stp].Density = rho;
StP[target_stp].Volume = volume;
StP[target_stp].DhsmlDensityFactor = dhsmlrho;
#ifdef CHIMIE_KINETIC_FEEDBACK
StP[target_stp].NgbMass = ngbmass;
#endif
}
else
{
StarsDensDataResult[target].Rho = rho;
StarsDensDataResult[target].Volume = volume;
StarsDensDataResult[target].Ngb = weighted_numngb;
StarsDensDataResult[target].DhsmlDensity = dhsmlrho;
#ifdef CHIMIE_KINETIC_FEEDBACK
StarsDensDataResult[target].NgbMass = ngbmass;
#endif
}
}
/*! This routine is a comparison kernel used in a sort routine to group
* particles that are exported to the same processor.
*/
int stars_dens_compare_key(const void *a, const void *b)
{
if(((struct starsdensdata_in *) a)->Task < (((struct starsdensdata_in *) b)->Task))
return -1;
if(((struct starsdensdata_in *) a)->Task > (((struct starsdensdata_in *) b)->Task))
return +1;
return 0;
}
#endif
diff --git a/src/system.c b/src/system.c
index 1c9d257..e761625 100644
--- a/src/system.c
+++ b/src/system.c
@@ -1,178 +1,191 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <signal.h>
#include <gsl/gsl_rng.h>
#include <mpi.h>
#include "allvars.h"
#include "proto.h"
/*! \file system.c
* \brief contains miscellaneous routines, e.g. elapsed time measurements
*/
/*! This routine returns a random number taken from a table of random numbers,
* which is refilled every timestep. This method is used to allow random
* number application to particles independent of the number of processors
* used, and independent of the particular order the particles have. In order
* to work properly, the particle IDs should be set properly to unique
* integer values.
*/
double get_random_number(int id)
{
return RndTable[(id % RNDTABLE)];
}
#ifdef SFR
double get_StarFormation_random_number(int id)
{
return StarFormationRndTable[(id % RNDTABLE)];
}
#endif
#ifdef FEEDBACK_WIND
double get_FeedbackWind_random_number(int id)
{
return FeedbackWindRndTable[(id % RNDTABLE)];
}
#endif
#ifdef CHIMIE
double get_Chimie_random_number(int id)
{
return ChimieRndTable[(id % RNDTABLE)];
}
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
double get_ChimieKineticFeedback_random_number(int id)
{
return ChimieKineticFeedbackRndTable[(id % RNDTABLE)];
}
#endif
+#ifdef GAS_ACCRETION
+double get_gasAccretion_random_number(int id)
+{
+ return gasAccretionRndTable[(id % RNDTABLE)];
+}
+#endif
+
/*! This routine fills the random number table.
*/
void set_random_numbers(void)
{
int i;
for(i = 0; i < RNDTABLE; i++)
RndTable[i] = gsl_rng_uniform(random_generator);
#ifdef SFR
for(i = 0; i < RNDTABLE; i++)
StarFormationRndTable[i] = gsl_rng_uniform(random_generator);
#endif
#ifdef FEEDBACK_WIND
for(i = 0; i < RNDTABLE; i++)
FeedbackWindRndTable[i] = gsl_rng_uniform(random_generator);
#endif
#ifdef CHIMIE
for(i = 0; i < RNDTABLE; i++)
ChimieRndTable[i] = gsl_rng_uniform(random_generator);
#endif
#ifdef CHIMIE_KINETIC_FEEDBACK
for(i = 0; i < RNDTABLE; i++)
ChimieKineticFeedbackRndTable[i] = gsl_rng_uniform(random_generator);
#endif
+
+#ifdef GAS_ACCRETION
+ for(i = 0; i < RNDTABLE; i++)
+ gasAccretionRndTable[i] = gsl_rng_uniform(random_generator);
+#endif
+
}
/*! returns the number of cpu-ticks in seconds that have elapsed, or the
* wall-clock time obtained with MPI_Wtime().
*/
double second(void)
{
#ifdef WALLCLOCK
return MPI_Wtime();
#else
return ((double) clock()) / CLOCKS_PER_SEC;
#endif
/* note: on AIX and presumably many other 32bit systems,
* clock() has only a resolution of 10ms=0.01sec
*/
}
/*! returns the time difference between two measurements obtained with
* second(). The routine takes care of the possible overflow of the tick
* counter on 32bit systems, but depending on the system, this may not always
* work properly. Similarly, in some MPI implementations, the MPI_Wtime()
* function may also overflow, in which case a negative time difference would
* be returned. The routine returns instead a time difference equal to 0.
*/
double timediff(double t0, double t1)
{
double dt;
dt = t1 - t0;
if(dt < 0) /* overflow has occured (for systems with 32bit tick counter) */
{
#ifdef WALLCLOCK
dt = 0;
#else
dt = t1 + pow(2, 32) / CLOCKS_PER_SEC - t0;
#endif
}
return dt;
}
/*! returns the maximum of two double
*/
double dmax(double x, double y)
{
if(x > y)
return x;
else
return y;
}
/*! returns the minimum of two double
*/
double dmin(double x, double y)
{
if(x < y)
return x;
else
return y;
}
/*! returns the maximum of two integers
*/
int imax(int x, int y)
{
if(x > y)
return x;
else
return y;
}
/*! returns the minimum of two integers
*/
int imin(int x, int y)
{
if(x < y)
return x;
else
return y;
}

Event Timeline