Peano
Loading...
Searching...
No Matches
makeIC-multiscale.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2
3import h5py
4import argparse
5import numpy as np
6
7"""!
8Generates 3D randomized particle distribution with
9multiple scales, i.e. recursively nested boxes
10such that the grid will contain multiple scales.
11"""
12
13fileName = "test_sml_multiscale_3D.hdf5"
14boxSize = 1.0
15
16parser = argparse.ArgumentParser(description="SPH benchmarking script")
17parser.add_argument(
18 "-np",
19 "--particle-number",
20 dest="particle_number",
21 required=True,
22 type=int,
23 help="Particle number per dimension",
24)
25parser.add_argument(
26 "-s",
27 "--seed",
28 dest="random_seed",
29 required=True,
30 type=int,
31 help="Seed for RNG",
32)
33parser.add_argument(
34 "-p",
35 "--plot",
36 dest="plot",
37 action="store_true",
38 default=False,
39 help="Plot historgram of particle positions",
40)
41parser.add_argument(
42 "-dx",
43 "--displacement",
44 dest="max_displacement",
45 required=False,
46 default=0.12499,
47 type=float,
48 help="Maximal displacement in units of interparticle distance",
49)
50
51
52args = parser.parse_args()
53npart = args.particle_number
54seed = args.random_seed
55max_displacement = args.max_displacement
56
57
58# ---------------------------------------------------
59
60# Build the arrays
61npart_tot = 4 * (npart**3)
62coords = np.zeros((npart_tot, 3))
63v = np.zeros((npart_tot, 3))
64ids = np.linspace(1, npart_tot, npart_tot)
65m = np.ones(npart_tot)
66dx = boxSize / npart
67h = np.ones(npart_tot) * 2.0 * dx
68u = np.ones(npart_tot)
69
70
71rng = np.random.RandomState(seed=seed)
72
73
74def get_coords(box_xmin, box_xmax, box_ymin, box_ymax, box_zmin, box_zmax, npart):
75 """
76 Generate coordinates for particles between box_min and box_max
77 npart: number of particles in each dimension
78 """
79
80 dx = (box_xmax - box_xmin) / npart
81 dy = (box_ymax - box_ymin) / npart
82 dz = (box_zmax - box_zmin) / npart
83
84 npart3 = npart**3
85
86 # First get uniform coordinates.
87 new_coords = np.zeros((npart3, 3))
88 ind = 0
89 for i in range(npart):
90 x = (i + 0.5) * dx
91 for j in range(npart):
92 y = (j + 0.5) * dy
93 for k in range(npart):
94 z = (k + 0.5) * dy
95 new_coords[ind, 0] = box_xmin + x
96 new_coords[ind, 1] = box_ymin + y
97 new_coords[ind, 2] = box_zmin + z
98 ind += 1
99
100 # Now randomize them a bit.
101 # Taking a completely randomly sampled particle distribution may lead
102 # to trouble the codes aren't set up to handle, such as particles which
103 # are either too close or too far from each other. So use a somewhat
104 # regular distribution instead, by randomly displacing an initially
105 # uniform particle distribution.
106
107 # rng.random returns random numbers in [0, 1). Scale that to [-1, 1)
108 displacement_x = (2.0 * rng.random((npart3, 1)) - 1.0) * max_displacement * dx
109 displacement_y = (2.0 * rng.random((npart3, 1)) - 1.0) * max_displacement * dy
110 displacement_z = (2.0 * rng.random((npart3, 1)) - 1.0) * max_displacement * dz
111 new_coords[:, 0] += displacement_x[:, 0]
112 new_coords[:, 1] += displacement_y[:, 0]
113 new_coords[:, 2] += displacement_z[:, 0]
114
115 return new_coords
116
117
118# Now generate actual coordinates
119# First the "background"
120npart3 = npart**3
121new_coords = get_coords(0.0, boxSize, 0.0, boxSize, 0.0, boxSize, npart)
122coords[:npart3, :3] = new_coords[:, :3]
123
124new_coords = get_coords(
125 0.0, 2.0 / 3 * boxSize, 0.0, 2.0 / 3 * boxSize, 0.0, 2.0 / 3 * boxSize, npart
126)
127coords[npart3 : 2 * npart3, :3] = new_coords[:, :3]
128
129new_coords = get_coords(
130 1.0 / 6,
131 2.0 / 3 * boxSize,
132 1.0 / 6,
133 2.0 / 3 * boxSize,
134 1.0 / 6,
135 2.0 / 3 * boxSize,
136 npart,
137)
138coords[2 * npart3 : 3 * npart3, :3] = new_coords[:, :3]
139
140new_coords = get_coords(
141 2.0 / 6,
142 2.0 / 3 * boxSize,
143 2.0 / 6,
144 2.0 / 3 * boxSize,
145 2.0 / 6,
146 2.0 / 3 * boxSize,
147 npart,
148)
149coords[3 * npart3 :, :3] = new_coords[:, :3]
150
151
152# too many particles mean that the comparison python script takes ages.
153# too few particles mean that the search radii are going to be too big
154# for the cell size.
155# So let's scale the particles down into a smaller box than the actual
156# box size.
157scale = 0.4
158coords *= scale
159h *= scale
160# and shift them into the center
161coords += 0.3
162
163
164if args.plot:
165 from matplotlib import pyplot as plt
166
167 plt.figure()
168 plt.scatter(coords[:, 0], coords[:, 1], s=1, marker=",")
169 plt.show()
170
171
172# File
173file = h5py.File(fileName, "w")
174
175# Header
176grp = file.create_group("/Header")
177grp.attrs["BoxSize"] = boxSize
178grp.attrs["NumPart_Total"] = [npart**3, 0, 0, 0, 0, 0]
179grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0]
180grp.attrs["NumPart_ThisFile"] = [npart**3, 0, 0, 0, 0, 0]
181# This is an addition for this test to be able to estimate the search radius.
182grp.attrs["NumPart_base"] = [npart]
183grp.attrs["Time"] = 0.0
184grp.attrs["NumFilesPerSnapshot"] = 1
185grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
186grp.attrs["Flag_Entropy_ICs"] = 0
187grp.attrs["Dimension"] = 3
188# Non-swift additions
189grp.attrs["RandomSeed"] = seed
190grp.attrs["MaxDisplacement"] = max_displacement
191grp.attrs["NumpyVersion"] = np.__version__
192
193# Units
194grp = file.create_group("/Units")
195grp.attrs["Unit length in cgs (U_L)"] = 1.0
196grp.attrs["Unit mass in cgs (U_M)"] = 1.0
197grp.attrs["Unit time in cgs (U_t)"] = 1.0
198grp.attrs["Unit current in cgs (U_I)"] = 1.0
199grp.attrs["Unit temperature in cgs (U_T)"] = 1.0
200
201# Particle group
202grp = file.create_group("/PartType0")
203grp.create_dataset("Coordinates", data=coords, dtype="d")
204grp.create_dataset("Velocities", data=v, dtype="f")
205grp.create_dataset("Masses", data=m, dtype="f")
206grp.create_dataset("SmoothingLength", data=h, dtype="f")
207grp.create_dataset("InternalEnergy", data=u, dtype="f")
208grp.create_dataset("ParticleIDs", data=ids, dtype="L")
209
210
211file.close()
get_coords(box_min, box_max, npart)
Generate coordinates for particles between box_min and box_max.