Skip to content
Snippets Groups Projects
Commit 961a5ca3 authored by Tom Theuns's avatar Tom Theuns
Browse files

added isothermal potential, gravity only

parent 7a73ec6d
No related branches found
No related tags found
1 merge request!205Isothermal potential
# Define the system of units to use internally.
InternalUnitSystem:
UnitMass_in_cgs: 1.9885e33 # Grams
UnitLength_in_cgs: 3.0856776e21 # Centimeters
UnitVelocity_in_cgs: 1e5 # Centimeters per second
UnitCurrent_in_cgs: 1 # Amperes
UnitTemp_in_cgs: 1 # Kelvin
# Parameters governing the time integration
TimeIntegration:
time_begin: 0. # The starting time of the simulation (in internal units).
time_end: 8. # The end time of the simulation (in internal units).
dt_min: 1e-7 # The minimal time-step size of the simulation (in internal units).
dt_max: 1e-1 # The maximal time-step size of the simulation (in internal units).
# Parameters governing the conserved quantities statistics
Statistics:
delta_time: 1e-2 # Time between statistics output
# Parameters governing the snapshots
Snapshots:
basename: Isothermal # Common part of the name of output files
time_first: 0. # Time of the first output (in internal units)
delta_time: 0.02 # Time difference between consecutive outputs (in internal units)
# Parameters for the task scheduling
Scheduler:
nr_threads: 8 # The number of threads per MPI rank to use.
nr_queues: 0 # The number of task queues to use. Use 0 to let the system decide.
cell_max_size: 8000000 # Maximal number of interactions per task (this is the default value).
cell_sub_size: 8000000 # Maximal number of interactions per sub-task (this is the default value).
cell_split_size: 400 # Maximal number of particles per cell (this is the default value).
# Parameters for the hydrodynamics scheme
SPH:
resolution_eta: 1.2349 # Target smoothing length in units of the mean inter-particle separation (1.2349 == 48Ngbs with the cubic spline kernel).
delta_neighbours: 1. # The tolerance for the targetted number of neighbours.
CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration.
max_ghost_iterations: 30 # Maximal number of iterations allowed to converge towards the smoothing length.
max_smoothing_length: 40. # Maximal smoothing length allowed (in internal units).
# Parameters related to the initial conditions
InitialConditions:
file_name: Isothermal.hdf5 # The file to read
h_scaling: 1. # A scaling factor to apply to all smoothing lengths in the ICs.
shift_x: 100. # A shift to apply to all particles read from the ICs (in internal units).
shift_y: 100.
shift_z: 100.
# Parameters govering domain decomposition
DomainDecomposition:
initial_type: m # The initial strategy ("g", "m", "w", or "v"). See documentation for details.
initial_grid_x: 10 # Grid size if the 'g' strategy is chosen.
initial_grid_y: 10
initial_grid_z: 10
repartition_type: b # The re-decomposition strategy ("n", "b", "v", "e" or "x"). See documentation for details.
# External potential parameters
PointMass:
position_x: 50. # location of external point mass in internal units
position_y: 50.
position_z: 50.
mass: 1e10 # mass of external point mass in internal units
IsothermalPotential:
position_x: 100. # location of external point mass in internal units
position_y: 100.
position_z: 100.
vrot: 200. # rotation speed of isothermal potential in internal units
This diff is collapsed.
###############################################################################
# This file is part of SWIFT.
# Copyright (c) 2016 John A. Regan (john.a.regan@durham.ac.uk)
# Tom Theuns (tom.theuns@durham.ac.uk)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import h5py
import sys
import numpy
import math
import random
# Generates N particles in a spherical distribution centred on [0,0,0], to be moved in an isothermal potential
# usage: python makeIC.py 1000 0 : generate 1000 particles on circular orbits
# python makeIC.py 1000 1 : generate 1000 particles with Lz/L uniform in [0,1]
# all particles move in the xy plane, and start at y=0
# physical constants in cgs
NEWTON_GRAVITY_CGS = 6.672e-8
SOLAR_MASS_IN_CGS = 1.9885e33
PARSEC_IN_CGS = 3.0856776e18
PROTON_MASS_IN_CGS = 1.6726231e24
YEAR_IN_CGS = 3.154e+7
# choice of units
const_unit_length_in_cgs = (1000*PARSEC_IN_CGS)
const_unit_mass_in_cgs = (SOLAR_MASS_IN_CGS)
const_unit_velocity_in_cgs = (1e5)
print "UnitMass_in_cgs: ", const_unit_mass_in_cgs
print "UnitLength_in_cgs: ", const_unit_length_in_cgs
print "UnitVelocity_in_cgs: ", const_unit_velocity_in_cgs
# rotation speed of isothermal potential [km/s]
vrot_kms = 200.
# derived units
const_unit_time_in_cgs = (const_unit_length_in_cgs / const_unit_velocity_in_cgs)
const_G = ((NEWTON_GRAVITY_CGS*const_unit_mass_in_cgs*const_unit_time_in_cgs*const_unit_time_in_cgs/(const_unit_length_in_cgs*const_unit_length_in_cgs*const_unit_length_in_cgs)))
print 'G=', const_G
vrot = vrot_kms * 1e5 / const_unit_velocity_in_cgs
# Parameters
periodic= 1 # 1 For periodic box
boxSize = 400. # [kpc]
Radius = 100. # maximum radius of particles [kpc]
G = const_G
N = int(sys.argv[1]) # Number of particles
icirc = int(sys.argv[2]) # if = 0, all particles are on circular orbits, if = 1, Lz/Lcirc uniform in ]0,1[
L = N**(1./3.)
# these are not used but necessary for I/O
rho = 2. # Density
P = 1. # Pressure
gamma = 5./3. # Gas adiabatic index
fileName = "Isothermal.hdf5"
#---------------------------------------------------
numPart = N
mass = 1
internalEnergy = P / ((gamma - 1.)*rho)
#--------------------------------------------------
#File
file = h5py.File(fileName, 'w')
#Units
grp = file.create_group("/Units")
grp.attrs["Unit length in cgs (U_L)"] = const_unit_length_in_cgs
grp.attrs["Unit mass in cgs (U_M)"] = const_unit_mass_in_cgs
grp.attrs["Unit time in cgs (U_t)"] = const_unit_length_in_cgs / const_unit_velocity_in_cgs
grp.attrs["Unit current in cgs (U_I)"] = 1.
grp.attrs["Unit temperature in cgs (U_T)"] = 1.
# Header
grp = file.create_group("/Header")
grp.attrs["BoxSize"] = boxSize
grp.attrs["NumPart_Total"] = [0, numPart, 0, 0, 0, 0]
grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0]
grp.attrs["NumPart_ThisFile"] = [0, numPart, 0, 0, 0, 0]
grp.attrs["Time"] = 0.0
grp.attrs["NumFilesPerSnapshot"] = 1
grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0]
#Runtime parameters
grp = file.create_group("/RuntimePars")
grp.attrs["PeriodicBoundariesOn"] = periodic
# set seed for random number
numpy.random.seed(1234)
#Particle group
#grp0 = file.create_group("/PartType0")
grp1 = file.create_group("/PartType1")
#generate particle positions
radius = Radius * (numpy.random.rand(N))**(1./3.)
ctheta = -1. + 2 * numpy.random.rand(N)
stheta = numpy.sqrt(1.-ctheta**2)
phi = 2 * math.pi * numpy.random.rand(N)
r = numpy.zeros((numPart, 3))
#r[:,0] = radius * stheta * numpy.cos(phi)
#r[:,1] = radius * stheta * numpy.sin(phi)
#r[:,2] = radius * ctheta
r[:,0] = radius
#
speed = vrot
v = numpy.zeros((numPart, 3))
omega = speed / radius
period = 2.*math.pi/omega
print 'period = minimum = ',min(period), ' maximum = ',max(period)
omegav = omega
if (icirc != 0):
omegav = omega * numpy.random.rand(N)
v[:,0] = -omegav * r[:,1]
v[:,1] = omegav * r[:,0]
ds = grp1.create_dataset('Velocities', (numPart, 3), 'f')
ds[()] = v
v = numpy.zeros(1)
m = numpy.full((numPart, ), mass)
ds = grp1.create_dataset('Masses', (numPart,), 'f')
ds[()] = m
m = numpy.zeros(1)
h = numpy.full((numPart, ), 1.1255 * boxSize / L)
ds = grp1.create_dataset('SmoothingLength', (numPart,), 'f')
ds[()] = h
h = numpy.zeros(1)
u = numpy.full((numPart, ), internalEnergy)
ds = grp1.create_dataset('InternalEnergy', (numPart,), 'f')
ds[()] = u
u = numpy.zeros(1)
ids = 1 + numpy.linspace(0, numPart, numPart, endpoint=False, dtype='L')
ds = grp1.create_dataset('ParticleIDs', (numPart, ), 'L')
ds[()] = ids
ds = grp1.create_dataset('Coordinates', (numPart, 3), 'd')
ds[()] = r
file.close()
;
; this probelm generates a set of gravity particles in an isothermal
; potential and follows their orbits. Tests verify consdevation of
; energy and angular momentum
;
;
#!/bin/bash
# Generate the initial conditions if they are not present.
if [ ! -e Isothermal.hdf5 ]
then
echo "Generating initial conditions for the point mass potential box example..."
python makeIC.py 1000
fi
../swift -g -t 2 externalGravity.yml
;
; test energy / angular momentum conservation of test problem
;
iplot = 1 ; if iplot = 1, make plot of E/Lz conservation, else, simply compare final and initial energy
; set physical constants
@physunits
indir = './'
basefile = 'Isothermal_'
; set properties of potential
uL = 1e3 * phys.pc ; unit of length
uM = phys.msun ; unit of mass
uV = 1d5 ; unit of velocity
vrot = 200. ; km/s
r200 = 100. ; virial radius
; derived units
constG = 10.^(alog10(phys.g)+alog10(uM)-2d0*alog10(uV)-alog10(uL)) ;
pcentre = [100.,100.,100.] * 1d3 * pc / uL
;
infile = indir + basefile + '*'
spawn,'ls -1 '+infile,res
nfiles = n_elements(res)
; choose: calculate change of energy and Lz, comparing first and last
; snapshots for all particles, or do so for a subset
; compare all
ifile = 0
inf = indir + basefile + strtrim(string(ifile,'(i3.3)'),1) + '.hdf5'
id = h5rd(inf,'PartType1/ParticleIDs')
nfollow = n_elements(id)
; follow a subset
nfollow = 500 ; number of particles to follow
;
if (iplot eq 1) then begin
nskip = 1
nsave = nfiles
endif else begin
nskip = nfiles - 2
nsave = 2
endelse
;
lout = fltarr(nfollow, nsave) ; Lz
xout = fltarr(nfollow, nsave) ; x
yout = fltarr(nfollow, nsave) ; y
zout = fltarr(nfollow, nsave) ; z
eout = fltarr(nfollow, nsave) ; energies
ekin = fltarr(nfollow, nsave)
epot = fltarr(nfollow, nsave)
tout = fltarr(nsave)
ifile = 0
isave = 0
for ifile=0,nfiles-1,nskip do begin
inf = indir + basefile + strtrim(string(ifile,'(i3.3)'),1) + '.hdf5'
time = h5ra(inf, 'Header','Time')
p = h5rd(inf,'PartType1/Coordinates')
v = h5rd(inf,'PartType1/Velocities')
id = h5rd(inf,'PartType1/ParticleIDs')
indx = sort(id)
;
id = id[indx]
for ic=0,2 do begin
tmp = reform(p[ic,*]) & p[ic,*] = tmp[indx]
tmp = reform(v[ic,*]) & v[ic,*] = tmp[indx]
endfor
; calculate energy
dd = size(p,/dimen) & npart = dd[1]
ener = fltarr(npart)
dr = fltarr(npart) & dv = dr
for ic=0,2 do dr[*] = dr[*] + (p[ic,*]-pcentre[ic])^2
for ic=0,2 do dv[*] = dv[*] + v[ic,*]^2
xout[*,isave] = p[0,0:nfollow-1]-pcentre[0]
yout[*,isave] = p[1,0:nfollow-1]-pcentre[1]
zout[*,isave] = p[2,0:nfollow-1]-pcentre[2]
Lz = (p[0,*]-pcentre[0]) * v[1,*] - (p[1,*]-pcentre[1]) * v[0,*]
dr = sqrt(dr)
; print,'time = ',time,p[0,0],v[0,0],id[0]
ek = 0.5 * dv
; ep = - constG * mextern / dr
ep = -vrot*vrot * (1 + alog(r200/dr))
ener = ek + ep
tout(isave) = time
lout[*,isave] = lz[0:nfollow-1]
eout(*,isave) = ener[0:nfollow-1]
ekin(*,isave) = ek[0:nfollow-1]
epot(*,isave) = ep[0:nfollow-1]
; write some output
; print,' time= ',time,' e= ',eout[0],' Lz= ',lz[0],format='(%a %f %a
; %f)'
print,format='('' time= '',f7.1,'' E= '',f9.2,'' Lz= '',e9.2)', time,eout[0],lz[0]
isave = isave + 1
endfor
x0 = reform(xout[0,*])
y0 = reform(xout[1,*])
z0 = reform(xout[2,*])
; calculate relative energy change
de = 0.0 * eout
dl = 0.0 * lout
nsave = isave
for ifile=1, nsave-1 do de[*,ifile] = (eout[*,ifile]-eout[*,0])/eout[*,0]
for ifile=1, nsave-1 do dl[*,ifile] = (lout[*,ifile] - lout[*,0])/lout[*,0]
; calculate statistics of energy changes
print,' relatve energy change: (per cent) ',minmax(de) * 100.
print,' relative Lz change: (per cent) ',minmax(dl) * 100.
; plot enery and Lz conservation for some particles
if(iplot eq 1) then begin
; plot results on energy conservation for some particles
nplot = min(10, nfollow)
wset,0
xr = [min(tout), max(tout)]
yr = [-2,2]*1d-2 ; in percent
plot,[0],[0],xr=xr,yr=yr,/xs,/ys,/nodata,xtitle='time',ytitle='dE/E, dL/L (%)'
for i=0,nplot-1 do oplot,tout,de[i,*]
for i=0,nplot-1 do oplot,tout,dl[i,*],color=red
legend,['dE/E','dL/L'],linestyle=[0,0],color=[black,red],box=0,/bottom,/left
screen_to_png,'e-time.png'
; plot orbits of those particles
wset,2
xr = [-100,100]
yr = xr
plot,[0],[0],xr=xr,yr=yr,/xs,/ys,/iso,/nodata,xtitle='x',ytitle='y'
color = floor(findgen(nplot)*255/float(nplot))
for i=0,nplot-1 do oplot,xout[i,*],yout[i,*],color=color(i)
screen_to_png,'orbit.png'
; plot radial position of these particles
wset,4
xr = [min(tout), max(tout)]
yr = [0,80]
plot,[0],[0],xr=xr,yr=yr,/xs,/ys,/nodata,xtitle='t',ytitle='r'
color = floor(findgen(nplot)*255/float(nplot))
for i=0,nplot-1 do begin dr = sqrt(reform(xout[i,*])^2 + reform(yout[i,*])^2) & oplot,tout,dr,color=color[i] & endfor
screen_to_png,'r-time.png'
; make histogram of energy changes at end
wset,6
ohist,de,x,y,-0.05,0.05,0.001
plot,x,y,psym=10,xtitle='de (%)'
screen_to_png,'de-hist.png'
endif
end
...@@ -60,7 +60,8 @@ ...@@ -60,7 +60,8 @@
//#define DEFAULT_SPH //#define DEFAULT_SPH
/* Gravity properties */ /* Gravity properties */
#define EXTERNAL_POTENTIAL_POINTMASS /* #define EXTERNAL_POTENTIAL_POINTMASS */
#define EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL
/* Are we debugging ? */ /* Are we debugging ? */
//#define SWIFT_DEBUG_CHECKS //#define SWIFT_DEBUG_CHECKS
......
...@@ -42,6 +42,9 @@ gravity_compute_timestep_external(const struct external_potential* potential, ...@@ -42,6 +42,9 @@ gravity_compute_timestep_external(const struct external_potential* potential,
dt = dt =
fminf(dt, external_gravity_pointmass_timestep(potential, phys_const, gp)); fminf(dt, external_gravity_pointmass_timestep(potential, phys_const, gp));
#endif #endif
#ifdef EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL
dt = fminf(dt, external_gravity_isothermalpotential_timestep(potential, phys_const, gp));
#endif
return dt; return dt;
} }
...@@ -117,6 +120,9 @@ __attribute__((always_inline)) INLINE static void external_gravity( ...@@ -117,6 +120,9 @@ __attribute__((always_inline)) INLINE static void external_gravity(
#ifdef EXTERNAL_POTENTIAL_POINTMASS #ifdef EXTERNAL_POTENTIAL_POINTMASS
external_gravity_pointmass(potential, phys_const, gp); external_gravity_pointmass(potential, phys_const, gp);
#endif #endif
#ifdef EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL
external_gravity_isothermalpotential(potential, phys_const, gp);
#endif
} }
/** /**
......
...@@ -48,6 +48,16 @@ void potential_init(const struct swift_params* parameter_file, ...@@ -48,6 +48,16 @@ void potential_init(const struct swift_params* parameter_file,
parser_get_param_double(parameter_file, "PointMass:mass"); parser_get_param_double(parameter_file, "PointMass:mass");
#endif /* EXTERNAL_POTENTIAL_POINTMASS */ #endif /* EXTERNAL_POTENTIAL_POINTMASS */
#ifdef EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL
potential -> isothermal_potential.x =
parser_get_param_double(parameter_file, "IsothermalPotential:position_x");
potential -> isothermal_potential.y =
parser_get_param_double(parameter_file, "IsothermalPotential:position_y");
potential -> isothermal_potential.z =
parser_get_param_double(parameter_file, "IsothermalPotential:position_z");
potential -> isothermal_potential.vrot =
parser_get_param_double(parameter_file, "IsothermalPotential:vrot");
#endif /* EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL */
} }
/** /**
...@@ -62,4 +72,9 @@ void potential_print(const struct external_potential* potential) { ...@@ -62,4 +72,9 @@ void potential_print(const struct external_potential* potential) {
potential->point_mass.x, potential->point_mass.y, potential->point_mass.x, potential->point_mass.y,
potential->point_mass.z, potential->point_mass.mass); potential->point_mass.z, potential->point_mass.mass);
#endif /* EXTERNAL_POTENTIAL_POINTMASS */ #endif /* EXTERNAL_POTENTIAL_POINTMASS */
#ifdef EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL
message("Isothermal potential properties are (x,y,z) = (%e, %e, %e), vrot = %e",
potential->isothermal_potential.x, potential->isothermal_potential.y,
potential->isothermal_potential.z, potential->isothermal_potential.vrot);
#endif /* EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL */
} }
...@@ -44,7 +44,68 @@ struct external_potential { ...@@ -44,7 +44,68 @@ struct external_potential {
double mass; double mass;
} point_mass; } point_mass;
#endif #endif
#ifdef EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL
struct {
double x, y, z;
double vrot;
} isothermal_potential;
#endif
}; };
/* Include external isothermal potential */
#ifdef EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL
#define EXTERNAL_GRAVITY_TIMESTEP_PREFACTOR 0.03f
/**
* @brief Computes the time-step due to the acceleration from a point mass
*
* @param phys_cont The physical constants in internal units.
* @param gp Pointer to the g-particle data.
*/
__attribute__((always_inline))
INLINE static float external_gravity_isothermalpotential_timestep(
const struct external_potential* potential,
const struct phys_const* const phys_const,
const struct gpart* const g) {
const float dx = g->x[0] - potential->isothermal_potential.x;
const float dy = g->x[1] - potential->isothermal_potential.y;
const float dz = g->x[2] - potential->isothermal_potential.z;
const float rinv2 = 1.f / (dx * dx + dy * dy + dz * dz);
const float drdv = dx * (g->v_full[0]) + dy * (g->v_full[1]) + dz * (g->v_full[2]);
const double vrot = potential->isothermal_potential.vrot;
const float dota_x = vrot * vrot * rinv2 * (g->v_full[0] - 2 * drdv * dx * rinv2);
const float dota_y = vrot * vrot * rinv2 * (g->v_full[1] - 2 * drdv * dy * rinv2);
const float dota_z = vrot * vrot * rinv2 * (g->v_full[2] - 2 * drdv * dz * rinv2);
const float dota_2 = dota_x * dota_x + dota_y * dota_y + dota_z * dota_z;
const float a_2 = g->a_grav[0] * g->a_grav[0] + g->a_grav[1] * g->a_grav[1] +
g->a_grav[2] * g->a_grav[2];
// error(" dx= %e dvx= %e rinv2= %e a2= %e dota_2= %e dt= %e", dx, g->v_full[1], rinv2, a_2, dota_2, 0.03f * sqrtf(a_2 / dota_2));
return EXTERNAL_GRAVITY_TIMESTEP_PREFACTOR * sqrtf(a_2 / dota_2);
}
/**
* @brief Computes the gravitational acceleration of a particle due to a point
* mass
*
* @param phys_cont The physical constants in internal units.
* @param gp Pointer to the g-particle data.
*/
__attribute__((always_inline)) INLINE static void external_gravity_isothermalpotential(const struct external_potential* potential, const struct phys_const* const phys_const, struct gpart* g) {
const float dx = g->x[0] - potential->isothermal_potential.x;
const float dy = g->x[1] - potential->isothermal_potential.y;
const float dz = g->x[2] - potential->isothermal_potential.z;
const float rinv2 = 1.f / (dx * dx + dy * dy + dz * dz);
const double vrot = potential->isothermal_potential.vrot;
g->a_grav[0] += -vrot * vrot * rinv2 * dx;
g->a_grav[1] += -vrot * vrot * rinv2 * dy;
g->a_grav[2] += -vrot * vrot * rinv2 * dz;
// error(" %f %f %f %f", vrot, rinv2, dx, g->a_grav[0]);
}
#endif /* EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL */
/* Include exteral pointmass potential */ /* Include exteral pointmass potential */
#ifdef EXTERNAL_POTENTIAL_POINTMASS #ifdef EXTERNAL_POTENTIAL_POINTMASS
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment