fargopy 0.2.1__py3-none-any.whl → 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fargopy/__init__.py +202 -87
- fargopy/fields.py +221 -0
- fargopy/simulation.py +845 -0
- fargopy/sys.py +41 -18
- fargopy/util.py +4 -0
- fargopy/version.py +1 -1
- {fargopy-0.2.1.dist-info → fargopy-0.3.0.dist-info}/LICENSE +0 -0
- fargopy-0.3.0.dist-info/METADATA +243 -0
- fargopy-0.3.0.dist-info/RECORD +13 -0
- {fargopy-0.2.1.dist-info → fargopy-0.3.0.dist-info}/WHEEL +1 -1
- fargopy/__cycle1.py +0 -880
- fargopy/conf.py +0 -20
- fargopy/fargo3d.py +0 -561
- fargopy-0.2.1.dist-info/METADATA +0 -470
- fargopy-0.2.1.dist-info/RECORD +0 -14
- {fargopy-0.2.1.data → fargopy-0.3.0.data}/scripts/ifargopy +0 -0
- {fargopy-0.2.1.dist-info → fargopy-0.3.0.dist-info}/entry_points.txt +0 -0
- {fargopy-0.2.1.dist-info → fargopy-0.3.0.dist-info}/top_level.txt +0 -0
fargopy/conf.py
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
###############################################################
|
|
2
|
-
# FARGOpy interdependencies
|
|
3
|
-
###############################################################
|
|
4
|
-
import fargopy
|
|
5
|
-
|
|
6
|
-
###############################################################
|
|
7
|
-
# Required packages
|
|
8
|
-
###############################################################
|
|
9
|
-
|
|
10
|
-
###############################################################
|
|
11
|
-
# Classes
|
|
12
|
-
###############################################################
|
|
13
|
-
|
|
14
|
-
#/////////////////////////////////////
|
|
15
|
-
# CONFIGURATION CLASS
|
|
16
|
-
#/////////////////////////////////////
|
|
17
|
-
class Conf(object):
|
|
18
|
-
"""Configuration class.
|
|
19
|
-
"""
|
|
20
|
-
|
fargopy/fargo3d.py
DELETED
|
@@ -1,561 +0,0 @@
|
|
|
1
|
-
###############################################################
|
|
2
|
-
# FARGOpy interdependencies
|
|
3
|
-
###############################################################
|
|
4
|
-
import fargopy
|
|
5
|
-
|
|
6
|
-
###############################################################
|
|
7
|
-
# Required packages
|
|
8
|
-
###############################################################
|
|
9
|
-
import os
|
|
10
|
-
import numpy as np
|
|
11
|
-
import re
|
|
12
|
-
|
|
13
|
-
###############################################################
|
|
14
|
-
# Constants
|
|
15
|
-
###############################################################
|
|
16
|
-
KB = 1.380650424e-16 # Boltzmann constant: erg/K, erg = g cm^2 / s^2
|
|
17
|
-
MP = 1.672623099e-24 # Mass of the proton, g
|
|
18
|
-
GCONST = 6.67259e-8 # Gravitational constant, cm^3/g/s^2
|
|
19
|
-
RGAS = 8.314472e7 # Gas constant, erg /K/mol
|
|
20
|
-
MSUN = 1.9891e33 # g
|
|
21
|
-
AU = 1.49598e13 # cm
|
|
22
|
-
YEAR = 31557600.0 # s
|
|
23
|
-
|
|
24
|
-
# Map of coordinates into FARGO3D coordinates
|
|
25
|
-
COORDS_MAP = dict(
|
|
26
|
-
cartesian = dict(x='x',y='y',z='z'),
|
|
27
|
-
cylindrical = dict(phi='x',r='y',z='z'),
|
|
28
|
-
spherical = dict(phi='x',r='y',theta='z'),
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
###############################################################
|
|
32
|
-
# Classes
|
|
33
|
-
###############################################################
|
|
34
|
-
class Fargobj(object):
|
|
35
|
-
def __init__(self):
|
|
36
|
-
self.fobject = True
|
|
37
|
-
|
|
38
|
-
def has(self,key):
|
|
39
|
-
if key in self.__dict__.keys():
|
|
40
|
-
return True
|
|
41
|
-
else:
|
|
42
|
-
return False
|
|
43
|
-
|
|
44
|
-
class Fargo3d(Fargobj):
|
|
45
|
-
|
|
46
|
-
def __init__(self):
|
|
47
|
-
super().__init__()
|
|
48
|
-
|
|
49
|
-
def compile_fargo3d(self,clean=True):
|
|
50
|
-
if Conf._check_fargo(Conf.FARGO3D_FULLDIR):
|
|
51
|
-
if clean:
|
|
52
|
-
Util.sysrun(f'make -C {Conf.FARGO3D_FULLDIR} clean mrproper',verbose=False)
|
|
53
|
-
|
|
54
|
-
error,out = Util.sysrun(f'make -C {Conf.FARGO3D_FULLDIR} PARALLEL={self.parallel} GPU={self.gpu}',verbose=False)
|
|
55
|
-
if error:
|
|
56
|
-
if not Conf._check_fargo_binary(Conf.FARGO3D_FULLDIR,quiet=True):
|
|
57
|
-
print("An error compiling the code arose. Check dependencies.")
|
|
58
|
-
print(Util.STDERR)
|
|
59
|
-
return False
|
|
60
|
-
|
|
61
|
-
return True
|
|
62
|
-
|
|
63
|
-
class Field(Fargobj):
|
|
64
|
-
"""Fields:
|
|
65
|
-
|
|
66
|
-
Attributes:
|
|
67
|
-
coordinates: type of coordinates (cartesian, cylindrical, spherical)
|
|
68
|
-
data: numpy arrays with data of the field
|
|
69
|
-
|
|
70
|
-
Methods:
|
|
71
|
-
slice: get an slice of a field along a given spatial direction.
|
|
72
|
-
Examples:
|
|
73
|
-
density.slice(r=0.5) # Take the closest slice to r = 0.5
|
|
74
|
-
density.slice(ir=20) # Take the slice through the 20 shell
|
|
75
|
-
density.slice(phi=30*RAD,interp='nearest') # Take a slice interpolating to the nearest
|
|
76
|
-
"""
|
|
77
|
-
|
|
78
|
-
def __init__(self,data=None,coordinates='cartesian',domains=None,type='scalar'):
|
|
79
|
-
self.data = data
|
|
80
|
-
self.coordinates = coordinates
|
|
81
|
-
self.domains = domains
|
|
82
|
-
self.type = type
|
|
83
|
-
|
|
84
|
-
def meshslice(self,slice=None,component=0):
|
|
85
|
-
"""Perform a slice on a field and produce as an output the
|
|
86
|
-
corresponding field slice and the associated matrices of
|
|
87
|
-
coordinates for plotting.
|
|
88
|
-
"""
|
|
89
|
-
# Analysis of the slice
|
|
90
|
-
if slice is None:
|
|
91
|
-
raise ValueError("You must provide a slice option.")
|
|
92
|
-
|
|
93
|
-
# Perform the slice
|
|
94
|
-
slice_cmd = f"self.slice({slice},pattern=True)"
|
|
95
|
-
slice,pattern = eval(slice_cmd)
|
|
96
|
-
|
|
97
|
-
# Create the mesh
|
|
98
|
-
if self.coordinates == 'cartesian':
|
|
99
|
-
z,y,x = np.meshgrid(self.domains.z,self.domains.y,self.domains.x,indexing='ij')
|
|
100
|
-
x = eval(f"x[{pattern}]")
|
|
101
|
-
y = eval(f"y[{pattern}]")
|
|
102
|
-
z = eval(f"z[{pattern}]")
|
|
103
|
-
|
|
104
|
-
mesh = fargopy.Dictobj(dict=dict(x=x,y=y,z=z))
|
|
105
|
-
|
|
106
|
-
if self.coordinates == 'cylindrical':
|
|
107
|
-
z,r,phi = np.meshgrid(self.domains.z,self.domains.r,self.domains.phi,indexing='ij')
|
|
108
|
-
x,y,z = r*np.cos(phi),r*np.sin(phi),z
|
|
109
|
-
|
|
110
|
-
x = eval(f"x[{pattern}]")
|
|
111
|
-
y = eval(f"y[{pattern}]")
|
|
112
|
-
z = eval(f"z[{pattern}]")
|
|
113
|
-
r = eval(f"r[{pattern}]")
|
|
114
|
-
phi = eval(f"phi[{pattern}]")
|
|
115
|
-
|
|
116
|
-
mesh = fargopy.Dictobj(dict=dict(r=r,phi=phi,x=x,y=y,z=z))
|
|
117
|
-
|
|
118
|
-
if self.coordinates == 'spherical':
|
|
119
|
-
theta,r,phi = np.meshgrid(self.domains.theta,self.domains.r,self.domains.phi,indexing='ij')
|
|
120
|
-
x,y,z = r*np.sin(theta)*np.cos(phi),r*np.sin(theta)*np.sin(phi),r*np.cos(theta)
|
|
121
|
-
|
|
122
|
-
x = eval(f"x[{pattern}]")
|
|
123
|
-
y = eval(f"y[{pattern}]")
|
|
124
|
-
z = eval(f"z[{pattern}]")
|
|
125
|
-
r = eval(f"r[{pattern}]")
|
|
126
|
-
phi = eval(f"phi[{pattern}]")
|
|
127
|
-
theta = eval(f"theta[{pattern}]")
|
|
128
|
-
|
|
129
|
-
mesh = fargopy.Dictobj(dict=dict(r=r,phi=phi,theta=theta,x=x,y=y,z=z))
|
|
130
|
-
|
|
131
|
-
return slice,mesh
|
|
132
|
-
|
|
133
|
-
def slice(self,quiet=True,pattern=False,**kwargs):
|
|
134
|
-
"""Extract an slice of a 3-dimensional FARGO3D field
|
|
135
|
-
|
|
136
|
-
Parameters:
|
|
137
|
-
quiet: boolean, default = False:
|
|
138
|
-
If True extract the slice quietly.
|
|
139
|
-
Else, print some control messages.
|
|
140
|
-
|
|
141
|
-
pattern: boolean, default = False:
|
|
142
|
-
If True return the pattern of the slice, eg. [:,:,:]
|
|
143
|
-
|
|
144
|
-
ir, iphi, itheta, ix, iy, iz: string or integer:
|
|
145
|
-
Index or range of indexes of the corresponding coordinate.
|
|
146
|
-
|
|
147
|
-
r, phi, theta, x, y, z: float:
|
|
148
|
-
Value for slicing. The slicing search for the closest
|
|
149
|
-
value in the domain.
|
|
150
|
-
|
|
151
|
-
Returns:
|
|
152
|
-
slice: sliced field.
|
|
153
|
-
|
|
154
|
-
Examples:
|
|
155
|
-
# 0D: Get the value of the field in iphi = 0, itheta = -1 and close to r = 0.82
|
|
156
|
-
gasvz.slice(iphi=0,itheta=-1,r=0.82)
|
|
157
|
-
|
|
158
|
-
# 1D: Get all values of the field in radial direction at iphi = 0, itheta = -1
|
|
159
|
-
gasvz.slice(iphi=0,itheta=-1)
|
|
160
|
-
|
|
161
|
-
# 2D: Get all values of the field for values close to phi = 0
|
|
162
|
-
gasvz.slice(phi=0)
|
|
163
|
-
"""
|
|
164
|
-
# By default slice
|
|
165
|
-
ivar = dict(x=':',y=':',z=':')
|
|
166
|
-
|
|
167
|
-
if len(kwargs.keys()) == 0:
|
|
168
|
-
pattern_str = f"{ivar['z']},{ivar['y']},{ivar['x']}"
|
|
169
|
-
if pattern:
|
|
170
|
-
return self.data, pattern_str
|
|
171
|
-
return self.data
|
|
172
|
-
|
|
173
|
-
# Check all conditions
|
|
174
|
-
for key,item in kwargs.items():
|
|
175
|
-
match = re.match('^i(.+)',key)
|
|
176
|
-
if match:
|
|
177
|
-
index = item
|
|
178
|
-
coord = match.group(1)
|
|
179
|
-
if not quiet:
|
|
180
|
-
print(f"Index condition {index} for coordinate {coord}")
|
|
181
|
-
ivar[COORDS_MAP[self.coordinates][coord]] = index
|
|
182
|
-
else:
|
|
183
|
-
if not quiet:
|
|
184
|
-
print(f"Numeric condition found for coordinate {key}")
|
|
185
|
-
if key in self.domains.keys():
|
|
186
|
-
# Check if value provided is in range
|
|
187
|
-
domain = self.domains.item(key)
|
|
188
|
-
extrema = self.domains.extrema[key]
|
|
189
|
-
min, max = extrema[0][1], extrema[1][1]
|
|
190
|
-
if (item<min) or (item>max):
|
|
191
|
-
raise ValueError(f"You are attempting to get a slice in {key} = {item}, but the valid range for this variable is [{min},{max}]")
|
|
192
|
-
find = abs(self.domains.item(key) - item)
|
|
193
|
-
ivar[COORDS_MAP[self.coordinates][key]] = find.argmin()
|
|
194
|
-
|
|
195
|
-
pattern_str = f"{ivar['z']},{ivar['y']},{ivar['x']}"
|
|
196
|
-
|
|
197
|
-
if self.type == 'scalar':
|
|
198
|
-
slice_cmd = f"self.data[{pattern_str}]"
|
|
199
|
-
if not quiet:
|
|
200
|
-
print(f"Slice: {slice_cmd}")
|
|
201
|
-
slice = eval(slice_cmd)
|
|
202
|
-
|
|
203
|
-
elif self.type == 'vector':
|
|
204
|
-
slice = np.array(
|
|
205
|
-
[eval(f"self.data[0,{pattern_str}]"),
|
|
206
|
-
eval(f"self.data[1,{pattern_str}]"),
|
|
207
|
-
eval(f"self.data[2,{pattern_str}]")]
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
if pattern:
|
|
211
|
-
return slice,pattern_str
|
|
212
|
-
return slice
|
|
213
|
-
|
|
214
|
-
def to_cartesian(self):
|
|
215
|
-
if self.type == 'scalar':
|
|
216
|
-
# Scalar fields are invariant under coordinate transformations
|
|
217
|
-
return self
|
|
218
|
-
elif self.type == 'vector':
|
|
219
|
-
# Vector fields must be transformed according to domain
|
|
220
|
-
if self.coordinates == 'cartesian':
|
|
221
|
-
return self
|
|
222
|
-
|
|
223
|
-
if self.coordinates == 'cylindrical':
|
|
224
|
-
z,r,phi = np.meshgrid(self.domains.z,self.domains.r,self.domains.phi,indexing='ij')
|
|
225
|
-
vphi = self.data[0]
|
|
226
|
-
vr = self.data[1]
|
|
227
|
-
vz = self.data[2]
|
|
228
|
-
vx = vr*np.cos(phi)
|
|
229
|
-
vy = vr*np.sin(phi)
|
|
230
|
-
|
|
231
|
-
return (Field(vx,coordinates=self.coordinates,domains=self.domains,type='scalar'),
|
|
232
|
-
Field(vy,coordinates=self.coordinates,domains=self.domains,type='scalar'),
|
|
233
|
-
Field(vz,coordinates=self.coordinates,domains=self.domains,type='scalar'))
|
|
234
|
-
|
|
235
|
-
if self.coordinates == 'spherical':
|
|
236
|
-
|
|
237
|
-
theta,r,phi = np.meshgrid(self.domains.theta,self.domains.r,self.domains.phi,indexing='ij')
|
|
238
|
-
vphi = self.data[0]
|
|
239
|
-
vr = self.data[1]
|
|
240
|
-
vtheta = self.data[2]
|
|
241
|
-
|
|
242
|
-
vx = vr*np.sin(theta)*np.cos(phi) + vtheta*np.cos(theta)*np.cos(phi) - vphi*np.sin(phi)
|
|
243
|
-
vy = vr*np.sin(theta)*np.sin(phi) + vtheta*np.cos(theta)*np.sin(phi) + vphi*np.cos(phi)
|
|
244
|
-
vz = vr*np.cos(theta) - vtheta*np.sin(theta)
|
|
245
|
-
|
|
246
|
-
return (Field(vx,coordinates=self.coordinates,domains=self.domains,type='scalar'),
|
|
247
|
-
Field(vy,coordinates=self.coordinates,domains=self.domains,type='scalar'),
|
|
248
|
-
Field(vz,coordinates=self.coordinates,domains=self.domains,type='scalar'))
|
|
249
|
-
|
|
250
|
-
def get_size(self):
|
|
251
|
-
return self.data.nbytes/1024**2
|
|
252
|
-
|
|
253
|
-
def __str__(self):
|
|
254
|
-
return str(self.data)
|
|
255
|
-
|
|
256
|
-
def __repr__(self):
|
|
257
|
-
return str(self.data)
|
|
258
|
-
|
|
259
|
-
class Simulation(Fargo3d):
|
|
260
|
-
|
|
261
|
-
def __init__(self):
|
|
262
|
-
super().__init__()
|
|
263
|
-
self.output_dir = None
|
|
264
|
-
self.set_units(UL=AU,UM=MSUN)
|
|
265
|
-
|
|
266
|
-
def set_output_dir(self,dir):
|
|
267
|
-
if not os.path.isdir(dir):
|
|
268
|
-
print(f"Directory '{dir}' does not exist.")
|
|
269
|
-
else:
|
|
270
|
-
print(f"Now you are connected with output directory '{dir}'")
|
|
271
|
-
self.output_dir = dir
|
|
272
|
-
|
|
273
|
-
def list_outputs(self,quiet=False):
|
|
274
|
-
if self.output_dir is None:
|
|
275
|
-
print(f"You have to set forst the outputs directory with <sim>.set_outputs('<directory>')")
|
|
276
|
-
else:
|
|
277
|
-
error,output = fargopy.Sys.run(f"ls {self.output_dir}")
|
|
278
|
-
if error == 0:
|
|
279
|
-
files = output[:-1]
|
|
280
|
-
print(f"{len(files)} files in output directory")
|
|
281
|
-
if not quiet:
|
|
282
|
-
file_list = ""
|
|
283
|
-
for i,file in enumerate(files):
|
|
284
|
-
file_list += f"{file}, "
|
|
285
|
-
if ((i+1)%10) == 0:
|
|
286
|
-
file_list += "\n"
|
|
287
|
-
print(file_list)
|
|
288
|
-
return files
|
|
289
|
-
|
|
290
|
-
def load_properties(self,quiet=False,
|
|
291
|
-
varfile='variables.par',
|
|
292
|
-
domain_prefix='domain_',
|
|
293
|
-
dimsfile='dims.dat'
|
|
294
|
-
):
|
|
295
|
-
if self.output_dir is None:
|
|
296
|
-
print(f"You have to set forst the outputs directory with <sim>.set_outputs('<directory>')")
|
|
297
|
-
|
|
298
|
-
# Read variables
|
|
299
|
-
vars = self._load_variables(varfile)
|
|
300
|
-
print(f"Simulation in {vars.DIM} dimensions")
|
|
301
|
-
|
|
302
|
-
# Read domains
|
|
303
|
-
domains = self._load_domains(vars,domain_prefix)
|
|
304
|
-
|
|
305
|
-
# Store the variables in the object
|
|
306
|
-
self.vars = vars
|
|
307
|
-
self.domains = domains
|
|
308
|
-
|
|
309
|
-
# Optionally read dims
|
|
310
|
-
dims = self._load_dims(dimsfile)
|
|
311
|
-
if len(dims):
|
|
312
|
-
self.dims = dims
|
|
313
|
-
|
|
314
|
-
print("Configuration variables and domains load into the object. See e.g. <sim>.vars")
|
|
315
|
-
|
|
316
|
-
def _load_dims(self,dimsfile):
|
|
317
|
-
"""Parse the dim directory
|
|
318
|
-
"""
|
|
319
|
-
dimsfile = f"{self.output_dir}/{dimsfile}".replace('//','/')
|
|
320
|
-
if not os.path.isfile(dimsfile):
|
|
321
|
-
#print(f"No file with dimensions '{dimsfile}' found.")
|
|
322
|
-
return []
|
|
323
|
-
dims = np.loadtxt(dimsfile)
|
|
324
|
-
return dims
|
|
325
|
-
|
|
326
|
-
def _load_variables(self,varfile):
|
|
327
|
-
"""Parse the file with the variables
|
|
328
|
-
"""
|
|
329
|
-
|
|
330
|
-
varfile = f"{self.output_dir}/{varfile}".replace('//','/')
|
|
331
|
-
if not os.path.isfile(varfile):
|
|
332
|
-
print(f"No file with variables named '{varfile}' found.")
|
|
333
|
-
return
|
|
334
|
-
|
|
335
|
-
print(f"Loading variables")
|
|
336
|
-
variables = np.genfromtxt(
|
|
337
|
-
varfile,dtype={'names': ("parameters","values"),
|
|
338
|
-
'formats': ("|S30","|S300")}
|
|
339
|
-
).tolist()
|
|
340
|
-
|
|
341
|
-
vars = dict()
|
|
342
|
-
for posicion in variables:
|
|
343
|
-
str_value = posicion[1].decode("utf-8")
|
|
344
|
-
try:
|
|
345
|
-
value = int(str_value)
|
|
346
|
-
except:
|
|
347
|
-
try:
|
|
348
|
-
value = float(str_value)
|
|
349
|
-
except:
|
|
350
|
-
value = str_value
|
|
351
|
-
vars[posicion[0].decode("utf-8")] = value
|
|
352
|
-
|
|
353
|
-
vars = fargopy.Dictobj(dict=vars)
|
|
354
|
-
print(f"{len(vars.__dict__.keys())} variables loaded")
|
|
355
|
-
|
|
356
|
-
# Create additional variables
|
|
357
|
-
variables = ['x', 'y', 'z']
|
|
358
|
-
if vars.COORDINATES == 'cylindrical':
|
|
359
|
-
variables = ['phi', 'r', 'z']
|
|
360
|
-
elif vars.COORDINATES == 'spherical':
|
|
361
|
-
variables = ['phi', 'r', 'theta']
|
|
362
|
-
vars.VARIABLES = variables
|
|
363
|
-
|
|
364
|
-
vars.__dict__[f'N{variables[0].upper()}'] = vars.NX
|
|
365
|
-
vars.__dict__[f'N{variables[1].upper()}'] = vars.NY
|
|
366
|
-
vars.__dict__[f'N{variables[2].upper()}'] = vars.NZ
|
|
367
|
-
|
|
368
|
-
# Dimension of the domain
|
|
369
|
-
vars.DIM = 2 if vars.NZ == 1 else 3
|
|
370
|
-
|
|
371
|
-
return vars
|
|
372
|
-
|
|
373
|
-
def _load_domains(self,vars,domain_prefix,
|
|
374
|
-
borders=[[],[3,-3],[3,-3]],
|
|
375
|
-
middle=True):
|
|
376
|
-
|
|
377
|
-
# Coordinates
|
|
378
|
-
variable_suffixes = ['x', 'y', 'z']
|
|
379
|
-
print(f"Loading domain in {vars.COORDINATES} coordinates:")
|
|
380
|
-
|
|
381
|
-
# Correct dims in case of 2D
|
|
382
|
-
if vars.DIM == 2:
|
|
383
|
-
borders[-1] = []
|
|
384
|
-
|
|
385
|
-
# Load domains
|
|
386
|
-
domains = dict()
|
|
387
|
-
domains['extrema'] = dict()
|
|
388
|
-
|
|
389
|
-
for i,variable_suffix in enumerate(variable_suffixes):
|
|
390
|
-
domain_file = f"{self.output_dir}/{domain_prefix}{variable_suffix}.dat".replace('//','/')
|
|
391
|
-
if os.path.isfile(domain_file):
|
|
392
|
-
|
|
393
|
-
# Load data from file
|
|
394
|
-
domains[vars.VARIABLES[i]] = np.genfromtxt(domain_file)
|
|
395
|
-
|
|
396
|
-
if len(borders[i]) > 0:
|
|
397
|
-
# Drop the border of the domain
|
|
398
|
-
domains[vars.VARIABLES[i]] = domains[vars.VARIABLES[i]][borders[i][0]:borders[i][1]]
|
|
399
|
-
|
|
400
|
-
if middle:
|
|
401
|
-
# Average between domain cell coordinates
|
|
402
|
-
domains[vars.VARIABLES[i]] = 0.5*(domains[vars.VARIABLES[i]][:-1]+domains[vars.VARIABLES[i]][1:])
|
|
403
|
-
|
|
404
|
-
# Show indices and value map
|
|
405
|
-
domains['extrema'][vars.VARIABLES[i]] = [[0,domains[vars.VARIABLES[i]][0]],[-1,domains[vars.VARIABLES[i]][-1]]]
|
|
406
|
-
|
|
407
|
-
print(f"\tVariable {vars.VARIABLES[i]}: {len(domains[vars.VARIABLES[i]])} {domains['extrema'][vars.VARIABLES[i]]}")
|
|
408
|
-
else:
|
|
409
|
-
print(f"\tDomain file {domain_file} not found.")
|
|
410
|
-
domains = fargopy.Dictobj(dict=domains)
|
|
411
|
-
|
|
412
|
-
return domains
|
|
413
|
-
|
|
414
|
-
def load_field(self,field,snapshot=None,type='scalar'):
|
|
415
|
-
|
|
416
|
-
if not self.has('vars'):
|
|
417
|
-
# If the simulation has not loaded the variables
|
|
418
|
-
dims, vars, domains = self.load_properties()
|
|
419
|
-
|
|
420
|
-
# In case no snapshot has been provided use 0
|
|
421
|
-
snapshot = 0 if snapshot is None else snapshot
|
|
422
|
-
|
|
423
|
-
field_data = []
|
|
424
|
-
if type == 'scalar':
|
|
425
|
-
file_name = f"{field}{str(snapshot)}.dat"
|
|
426
|
-
file_field = f"{self.output_dir}/{file_name}".replace('//','/')
|
|
427
|
-
field_data = self._load_field_scalar(file_field)
|
|
428
|
-
elif type == 'vector':
|
|
429
|
-
field_data = []
|
|
430
|
-
variables = ['x','y']
|
|
431
|
-
if self.vars.DIM == 3:
|
|
432
|
-
variables += ['z']
|
|
433
|
-
for i,variable in enumerate(variables):
|
|
434
|
-
file_name = f"{field}{variable}{str(snapshot)}.dat"
|
|
435
|
-
file_field = f"{self.output_dir}/{file_name}".replace('//','/')
|
|
436
|
-
field_data += [self._load_field_scalar(file_field)]
|
|
437
|
-
else:
|
|
438
|
-
raise ValueError(f"Field type '{type}' not recognized.")
|
|
439
|
-
|
|
440
|
-
field = Field(data=np.array(field_data), coordinates=self.vars.COORDINATES, domains=self.domains, type=type)
|
|
441
|
-
return field
|
|
442
|
-
|
|
443
|
-
def _load_field_scalar(self,file):
|
|
444
|
-
"""Load scalar field from file a file.
|
|
445
|
-
"""
|
|
446
|
-
if os.path.isfile(file):
|
|
447
|
-
field_data = np.fromfile(file).reshape(int(self.vars.NZ),int(self.vars.NY),int(self.vars.NX))
|
|
448
|
-
"""
|
|
449
|
-
if self.vars.NZ > 1:
|
|
450
|
-
# 3D field
|
|
451
|
-
field_data = np.fromfile(file).reshape(int(self.vars.NZ),int(self.vars.NY),int(self.vars.NX))
|
|
452
|
-
else:
|
|
453
|
-
# 2D field
|
|
454
|
-
field_data = np.fromfile(file).reshape(int(self.vars.NY),int(self.vars.NX))
|
|
455
|
-
"""
|
|
456
|
-
return field_data
|
|
457
|
-
else:
|
|
458
|
-
raise AssertionError(f"File with field '{file}' not found")
|
|
459
|
-
|
|
460
|
-
def load_allfields(self,fluid,snapshot=None,type='scalar'):
|
|
461
|
-
"""Load all fields in the output
|
|
462
|
-
"""
|
|
463
|
-
qall = False
|
|
464
|
-
if snapshot is None:
|
|
465
|
-
qall = True
|
|
466
|
-
fields = fargopy.Dictobj()
|
|
467
|
-
else:
|
|
468
|
-
fields = fargopy.Dictobj()
|
|
469
|
-
|
|
470
|
-
# Search for field files
|
|
471
|
-
pattern = f"{self.output_dir}/{fluid}*.dat"
|
|
472
|
-
error,output = fargopy.Sys.run(f"ls {pattern}")
|
|
473
|
-
|
|
474
|
-
if not error:
|
|
475
|
-
size = 0
|
|
476
|
-
for file_field in output[:-1]:
|
|
477
|
-
comps = Simulation._parse_file_field(file_field)
|
|
478
|
-
if comps:
|
|
479
|
-
if qall:
|
|
480
|
-
# Store all snapshots
|
|
481
|
-
field_name = comps[0]
|
|
482
|
-
field_snap = int(comps[1])
|
|
483
|
-
|
|
484
|
-
if type == 'scalar':
|
|
485
|
-
field_data = self._load_field_scalar(file_field)
|
|
486
|
-
elif type == 'vector':
|
|
487
|
-
field_data = []
|
|
488
|
-
variables = ['x','y']
|
|
489
|
-
if self.vars.DIM == 3:
|
|
490
|
-
variables += ['z']
|
|
491
|
-
for i,variable in enumerate(variables):
|
|
492
|
-
file_name = f"{fluid}{variable}{str(field_snap)}.dat"
|
|
493
|
-
file_field = f"{self.output_dir}/{file_name}".replace('//','/')
|
|
494
|
-
field_data += [self._load_field_scalar(file_field)]
|
|
495
|
-
field_data = np.array(field_data)
|
|
496
|
-
field_name = field_name[:-1]
|
|
497
|
-
|
|
498
|
-
if str(field_snap) not in fields.keys():
|
|
499
|
-
fields.__dict__[str(field_snap)] = fargopy.Dictobj()
|
|
500
|
-
size += field_data.nbytes
|
|
501
|
-
(fields.__dict__[str(field_snap)]).__dict__[f"{field_name}"] = Field(data=field_data, coordinates=self.vars.COORDINATES, domains=self.domains, type=type)
|
|
502
|
-
|
|
503
|
-
else:
|
|
504
|
-
# Store a specific snapshot
|
|
505
|
-
if int(comps[1]) == snapshot:
|
|
506
|
-
field_name = comps[0]
|
|
507
|
-
|
|
508
|
-
if type == 'scalar':
|
|
509
|
-
field_data = self._load_field_scalar(file_field)
|
|
510
|
-
elif type == 'vector':
|
|
511
|
-
field_data = []
|
|
512
|
-
variables = ['x','y']
|
|
513
|
-
if self.vars.DIM == 3:
|
|
514
|
-
variables += ['z']
|
|
515
|
-
for i,variable in enumerate(variables):
|
|
516
|
-
file_name = f"{fluid}{variable}{str(field_snap)}.dat"
|
|
517
|
-
file_field = f"{self.output_dir}/{file_name}".replace('//','/')
|
|
518
|
-
field_data += [self._load_field_scalar(file_field)]
|
|
519
|
-
field_data = np.array(field_data)
|
|
520
|
-
field_name = field_name[:-1]
|
|
521
|
-
|
|
522
|
-
size += field_data.nbytes
|
|
523
|
-
fields.__dict__[f"{field_name}"] = Field(data=field_data, coordinates=self.vars.COORDINATES, domains=self.domains, type=type)
|
|
524
|
-
|
|
525
|
-
else:
|
|
526
|
-
raise ValueError(f"No field found with pattern '{pattern}'. Change the fluid")
|
|
527
|
-
|
|
528
|
-
if qall:
|
|
529
|
-
fields.snapshots = sorted([int(s) for s in fields.keys() if s != 'size'])
|
|
530
|
-
fields.size = size/1024**2
|
|
531
|
-
return fields
|
|
532
|
-
|
|
533
|
-
@staticmethod
|
|
534
|
-
def _parse_file_field(file_field):
|
|
535
|
-
basename = os.path.basename(file_field)
|
|
536
|
-
comps = None
|
|
537
|
-
match = re.match('([a-zA-Z]+)(\d+).dat',basename)
|
|
538
|
-
if match is not None:
|
|
539
|
-
comps = [match.group(i) for i in range(1,match.lastindex+1)]
|
|
540
|
-
return comps
|
|
541
|
-
|
|
542
|
-
def set_units(self,UM=MSUN,UL=AU,G=1,mu=2.35):
|
|
543
|
-
"""Set units of simulation
|
|
544
|
-
"""
|
|
545
|
-
# Basic
|
|
546
|
-
self.UM = UM
|
|
547
|
-
self.UL = UL
|
|
548
|
-
self.G = G
|
|
549
|
-
self.UT = (G*self.UL**3/(GCONST*self.UM))**0.5 # In seconds
|
|
550
|
-
|
|
551
|
-
# Thermodynamics
|
|
552
|
-
self.UTEMP = (GCONST*MP*mu/KB)*self.UM/self.UL # In K
|
|
553
|
-
|
|
554
|
-
# Derivative
|
|
555
|
-
self.USIGMA = self.UM/self.UL**2 # In g/cm^2
|
|
556
|
-
self.URHO = self.UM/self.UL**3 # In kg/m^3
|
|
557
|
-
self.UEPS = self.UM/(self.UL*self.UT**2) # In J/m^3
|
|
558
|
-
self.UV = self.UL/self.UT
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|