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/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
-