planit 1.0.2__tar.gz → 1.2.2__tar.gz

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.
Files changed (41) hide show
  1. {planit-1.0.2 → planit-1.2.2}/PKG-INFO +7 -2
  2. {planit-1.0.2 → planit-1.2.2}/README.md +4 -1
  3. {planit-1.0.2 → planit-1.2.2}/planit/eos/aquatable.py +3 -1
  4. {planit-1.0.2 → planit-1.2.2}/planit/eos/eosfuncs.py +24 -4
  5. {planit-1.0.2 → planit-1.2.2}/planit/eos/eostab_extension.py +4 -2
  6. {planit-1.0.2 → planit-1.2.2}/planit/eos/rhoUtable.py +1 -0
  7. planit-1.2.2/planit/impacttools.py +459 -0
  8. {planit-1.0.2 → planit-1.2.2}/planit/main.py +4 -4
  9. {planit-1.0.2 → planit-1.2.2}/planit/makeplanet.py +13 -9
  10. planit-1.2.2/planit/plotting.py +298 -0
  11. planit-1.2.2/planit/snaptools/__init__.py +2 -0
  12. planit-1.2.2/planit/snaptools/io.py +786 -0
  13. planit-1.2.2/planit/snaptools/snaptools.py +555 -0
  14. {planit-1.0.2 → planit-1.2.2}/planit/utils.py +7 -0
  15. {planit-1.0.2 → planit-1.2.2}/planit.egg-info/PKG-INFO +7 -2
  16. {planit-1.0.2 → planit-1.2.2}/planit.egg-info/SOURCES.txt +7 -1
  17. {planit-1.0.2 → planit-1.2.2}/planit.egg-info/requires.txt +1 -0
  18. planit-1.2.2/pyproject.toml +37 -0
  19. {planit-1.0.2 → planit-1.2.2}/tests/test_eos.py +30 -3
  20. planit-1.2.2/tests/test_imp.py +38 -0
  21. planit-1.2.2/tests/test_io.py +102 -0
  22. planit-1.2.2/tests/test_make.py +74 -0
  23. planit-1.2.2/tests/test_plot.py +72 -0
  24. planit-1.2.2/tests/test_snap.py +122 -0
  25. planit-1.2.2/tests/test_utils.py +65 -0
  26. planit-1.0.2/planit/impacttools.py +0 -572
  27. planit-1.0.2/planit/snaptools.py +0 -933
  28. planit-1.0.2/pyproject.toml +0 -13
  29. planit-1.0.2/tests/test_make.py +0 -24
  30. planit-1.0.2/tests/test_snap.py +0 -14
  31. planit-1.0.2/tests/test_utils.py +0 -33
  32. {planit-1.0.2 → planit-1.2.2}/LICENSE +0 -0
  33. {planit-1.0.2 → planit-1.2.2}/planit/__init__.py +0 -0
  34. {planit-1.0.2 → planit-1.2.2}/planit/eos/__init__.py +0 -0
  35. {planit-1.0.2 → planit-1.2.2}/planit/eos/aneostable.py +0 -0
  36. {planit-1.0.2 → planit-1.2.2}/planit/eos/eos_table.py +0 -0
  37. {planit-1.0.2 → planit-1.2.2}/planit/eos/tabinterp.py +0 -0
  38. {planit-1.0.2 → planit-1.2.2}/planit/globaldefs.py +0 -0
  39. {planit-1.0.2 → planit-1.2.2}/planit.egg-info/dependency_links.txt +0 -0
  40. {planit-1.0.2 → planit-1.2.2}/planit.egg-info/top_level.txt +0 -0
  41. {planit-1.0.2 → planit-1.2.2}/setup.cfg +0 -0
@@ -1,10 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: planit
3
- Version: 1.0.2
3
+ Version: 1.2.2
4
4
  Summary: The PLANetary Impact Toolkit provides tools for accessing, manipulating, and analysing smoothed particle hydrodynamcis (SPH) impact simulation data, and creating planets for SPH impact simulations.
5
5
  Author-email: Philip Carter <p.carter@bristol.ac.uk>
6
6
  License-Expression: GPL-3.0-or-later
7
7
  Project-URL: Homepage, https://github.com/PhilJCarter/planit
8
+ Requires-Python: >=3.10
8
9
  Description-Content-Type: text/markdown
9
10
  License-File: LICENSE
10
11
  Requires-Dist: numpy
@@ -14,11 +15,15 @@ Requires-Dist: numba
14
15
  Requires-Dist: h5py
15
16
  Requires-Dist: seagen
16
17
  Requires-Dist: cmasher
18
+ Requires-Dist: IPython
17
19
  Dynamic: license-file
18
20
 
19
21
  # planit
20
22
 
21
23
  [![Tests](https://github.com/PhilJCarter/planit/actions/workflows/python-test.yml/badge.svg)](https://github.com/PhilJCarter/planit/actions/workflows/python-test.yml)
24
+ [![Coverage](https://PhilJCarter.github.io/planit/coverage.svg)](https://PhilJCarter.github.io/planit/cov_html/index.html)
25
+ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://github.com/PhilJCarter/planit/tree/main?tab=GPL-3.0-1-ov-file#GPL-3.0-1-ov-file)
26
+
22
27
 
23
28
  The **Plan**etary **I**mpact **T**oolkit provides tools for accessing, manipulating, and
24
29
  analysing smoothed particle hydrodynamcis (SPH) impact simulation data, and creating
@@ -29,7 +34,7 @@ Sarah T. Stewart (sstewa56@asu.edu)
29
34
 
30
35
  ## Overview
31
36
 
32
- **planit** currently supports the SPH codes [Gadget2-planetary](https://github.com/PlanetSim/gadget2-planetary) and [SWIFT](http://www.swiftsim.com/).
37
+ **planit** currently supports the SPH codes [Gadget2-planetary](https://github.com/PlanetSim/gadget2-planetary), [pkdgrav3](https://bitbucket.org/dpotter/pkdgrav3/src/master/), and [SWIFT](http://www.swiftsim.com/).
33
38
 
34
39
  `makeplanet` provides functions for generating adiabatic 1D planet structures and
35
40
  converting these into (unequilibrated) SPH planets.\
@@ -1,6 +1,9 @@
1
1
  # planit
2
2
 
3
3
  [![Tests](https://github.com/PhilJCarter/planit/actions/workflows/python-test.yml/badge.svg)](https://github.com/PhilJCarter/planit/actions/workflows/python-test.yml)
4
+ [![Coverage](https://PhilJCarter.github.io/planit/coverage.svg)](https://PhilJCarter.github.io/planit/cov_html/index.html)
5
+ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://github.com/PhilJCarter/planit/tree/main?tab=GPL-3.0-1-ov-file#GPL-3.0-1-ov-file)
6
+
4
7
 
5
8
  The **Plan**etary **I**mpact **T**oolkit provides tools for accessing, manipulating, and
6
9
  analysing smoothed particle hydrodynamcis (SPH) impact simulation data, and creating
@@ -11,7 +14,7 @@ Sarah T. Stewart (sstewa56@asu.edu)
11
14
 
12
15
  ## Overview
13
16
 
14
- **planit** currently supports the SPH codes [Gadget2-planetary](https://github.com/PlanetSim/gadget2-planetary) and [SWIFT](http://www.swiftsim.com/).
17
+ **planit** currently supports the SPH codes [Gadget2-planetary](https://github.com/PlanetSim/gadget2-planetary), [pkdgrav3](https://bitbucket.org/dpotter/pkdgrav3/src/master/), and [SWIFT](http://www.swiftsim.com/).
15
18
 
16
19
  `makeplanet` provides functions for generating adiabatic 1D planet structures and
17
20
  converting these into (unequilibrated) SPH planets.\
@@ -17,9 +17,11 @@ def loadAQUAEOS(eos='Water-AQUA-v1.0', eostype='AQUA', debug = False):
17
17
 
18
18
  if eos == 'Water-AQUA-v1.0':
19
19
  eosdir = eospath + 'aqua-water/'
20
-
20
+ womaID = 304
21
+
21
22
  NewEOS = EOStable() # FIRST make new empty EOS object
22
23
  NewEOS.TYPE = eostype
24
+ NewEOS.womaID = womaID
23
25
  NewEOS.VERSION = 1.0
24
26
 
25
27
  NewEOS.loadaquatable(eosdir+'aqua_eos_rhot_v1_0.dat')
@@ -50,9 +50,9 @@ UserEOS4 = None
50
50
 
51
51
 
52
52
  # Name lists for EoS
53
- ironnames = ['Iron-ANEOS-SLVTv0.2G1', 'iron', 'ANEOSIron', 'Fe', 'Iron', 401]
54
- alloynames = ['Fe85Si15-ANEOS-SLVTv0.2G1', 'alloy', 'ANEOSFeSiAlloy', 'FeSi', 'Alloy', 'IronAlloy', 'ironalloy', 402]
55
- forsteritenames = ['Forsterite-ANEOS-SLVTv1.0G1', 'forsterite', 'ANEOSForsterite', 'Forsterite', 'Fo', 400]
53
+ ironnames = ['Iron-ANEOS-SLVTv0.2G1', 'iron', 'ANEOSIron', 'Fe', 'Iron', 401, 63]
54
+ alloynames = ['Fe85Si15-ANEOS-SLVTv0.2G1', 'alloy', 'ANEOSFeSiAlloy', 'FeSi', 'Alloy', 'IronAlloy', 'ironalloy', 402, 64]
55
+ forsteritenames = ['Forsterite-ANEOS-SLVTv1.0G1', 'forsterite', 'ANEOSForsterite', 'Forsterite', 'Fo', 400, 62]
56
56
  pyrolitenames = ['Pyrolite_ANEOS_SLVTv0.2', 'pyrolite', 'Pyrolite', 'ANEOSPyrolite', 403]
57
57
  aquawaternames = ['Water-AQUA-v1.0', 'AQUA', 'AQUAWater', 'aqua', 304]
58
58
  fivephasewaternames = ['5PhaseEOSv8.3', '5PhaseWater', '5phasewater', 'SS08', 'SenftStewartWater', 'SenftStewart08', 303]
@@ -253,6 +253,26 @@ uconversion_U_inv = 1./uconversion_U
253
253
  uconversion_S_inv = 1./uconversion_S
254
254
 
255
255
 
256
+ def pkdgrav3towoma(pkdmats):
257
+ """Translate pkdgrav3/EOSLib material numbers to swift/woma IDs"""
258
+ swiftmats = pkdmats.copy()
259
+ swiftmats[pkdmats==63] = 401 # iron
260
+ swiftmats[pkdmats==62] = 400 # forsterite
261
+ swiftmats[pkdmats==64] = 402 # FeSi alloy
262
+
263
+ return swiftmats
264
+
265
+
266
+ def womatopkdgrav3(swiftmats):
267
+ """Translate swift/woma IDs to pkdgrav3/EOSLib material numbers"""
268
+ pkdmats = swiftmats.copy()
269
+ pkdmats[swiftmats==401] = 63 # iron
270
+ pkdmats[swiftmats==400] = 62 # forsterite
271
+ pkdmats[swiftmats==402] = 64 # FeSi alloy
272
+
273
+ return pkdmats
274
+
275
+
256
276
  def calcprop(Qlab,Xlab,Ylab,X,Y,mats):
257
277
  """Calculate thermodynamic property
258
278
 
@@ -322,7 +342,7 @@ def _calc_prop(Qlab,Xlab,Ylab,X,Y,EOSlist):
322
342
  Q = npy.zeros(len(X))
323
343
  for i in numba.prange(len(X)):
324
344
 
325
- if EOSlist[i].TYPE in ['ANEOS','SESAME','AQUA']:
345
+ if EOSlist[i].TYPE in ['ANEOS', 'SESAME', 'AQUA']:
326
346
  if Ylab == 'S':
327
347
  Q[i] = tabinterp.from_rhoS(Qlab, X[i], Y[i], EOSlist[i])
328
348
  elif Ylab == 'U':
@@ -79,10 +79,12 @@ class EOStable(extEOStable):
79
79
  passer.T = self.T
80
80
  passer.P = self.P
81
81
  passer.U = self.U
82
- passer.A = self.A
82
+ if len(self.A) > 0:
83
+ passer.A = self.A
83
84
  passer.S = self.S
84
85
  passer.cs = self.cs
85
- passer.cv = self.cv
86
+ if len(self.cv) > 0:
87
+ passer.cv = self.cv
86
88
  # passer.KPA = self.KPA
87
89
  # passer.MDQ = self.MDQ
88
90
  passer.TYPE = self.TYPE
@@ -19,6 +19,7 @@ def loadrhoUEOS(eos='HM80-HHe-v2.0', eostype='HM80', debug = False):
19
19
 
20
20
  if eos == 'HM80-HHe-v2.0':
21
21
  eosdir = eospath + 'HM80_HHe/'
22
+ NewEOS.womaID = 200
22
23
  NewEOS.VERSION = 2.0
23
24
  NewEOS.loadrhoUtable(eosdir+'HM80_HHe_extended.txt')
24
25
 
@@ -0,0 +1,459 @@
1
+ """
2
+ planit impact class and analysis tools
3
+ """
4
+
5
+ from .globaldefs import *
6
+ from .snaptools import Snapshot
7
+ from . import plotting
8
+
9
+ import numpy as npy
10
+ import scipy
11
+ import glob
12
+ import os
13
+ import matplotlib
14
+ import matplotlib.pyplot as plt
15
+ import cmasher
16
+
17
+ # for movie:
18
+ from IPython import display
19
+ import matplotlib.animation
20
+
21
+
22
+ class ImpSnapshot(Snapshot):
23
+ pass
24
+
25
+
26
+ class Impact:
27
+ """
28
+ Gadget/Swift impact class
29
+
30
+ A wrapper for holding multiple snapshots
31
+
32
+ load()
33
+ plotseq()
34
+ attrmov()
35
+ """
36
+ def __init__(self):
37
+ #self.targ = None
38
+ #self.proj = None
39
+ #self.v = None
40
+ #self.b = None
41
+ self.nsnaps = 0
42
+ self.snap = self.data = None
43
+
44
+ def load(self,loc,thermo=False,inter=1,compress=True,code='swift',ndigits=4,prefix='snapshot',sep='_',prefix2=None,flist=None):
45
+ Nf2 = Nf = 0
46
+ increment1 = increment2 = 1
47
+ flist2 = []
48
+ loc = str(loc)
49
+ if loc[-1] != '/':
50
+ loc = loc + '/'
51
+ files2 = npy.empty(0)
52
+ if flist:
53
+ files = files1 = flist
54
+ self.nsnaps = len(flist)
55
+ else:
56
+ if code=='swift':
57
+ flist = sorted(glob.glob(loc+prefix+sep+'[0-9]*.hdf5'))
58
+ if prefix2:
59
+ flist2 = sorted(glob.glob(loc+prefix2+sep+'[0-9]*.hdf5'))
60
+ else:
61
+ flist = sorted(glob.glob(loc+prefix+sep+'[0-9]*'))
62
+ if prefix2:
63
+ flist2 = sorted(glob.glob(loc+prefix2+sep+'[0-9]*'))
64
+ Nf1 = [(flist[x].split('/')[-1]).split(sep)[1].split('.')[0] for x in range(len(flist))]
65
+ if prefix2:
66
+ Nf2 = [(flist2[x].split('/')[-1]).split(sep)[1].split('.')[0] for x in range(len(flist2))]
67
+ if len(Nf1)>0:
68
+ Nf1 = sorted(npy.array(Nf1).astype(int))
69
+ increment1 = int(Nf1[1] - Nf1[0])
70
+ Nf = int(Nf1[-1])
71
+ else:
72
+ Nf = 0
73
+ if prefix2 and len(Nf2)>0:
74
+ Nf2 = sorted(npy.array(Nf2).astype(int))
75
+ increment2 = int(Nf2[1]-Nf2[0])
76
+ Nf2 = int(Nf2[-1])
77
+ else:
78
+ Nf2 = 0
79
+ print('Loading', int(Nf/increment1 + Nf2/increment2), 'files...')
80
+ self.nsnaps = len(flist)+len(flist2)
81
+ if self.nsnaps>2:
82
+ if Nf2>0:
83
+ files2 = npy.arange(0,Nf2+increment2,inter*increment2)
84
+ files1 = npy.arange(0,Nf+increment1,inter*increment1)
85
+ files = npy.append(files1,files2)
86
+ elif self.nsnaps>0:
87
+ files = npy.array([0,Nf])
88
+ else:
89
+ files = []
90
+
91
+ self.data = npy.ndarray((len(files),),dtype=object)
92
+
93
+ for i in range(len(self.data)):
94
+ honly = True
95
+ if i==0 or i==len(self.data)-1:
96
+ honly = False
97
+ self.data[i] = ImpSnapshot()
98
+ if code=='swift' or code=='Swift':
99
+ if i<len(files1):
100
+ self.data[i].load(loc+prefix+sep+'{:>0{width}d}.hdf5'.format(int(files[i]),width=ndigits),headonly=honly,thermo=thermo,compress=compress)
101
+ else:
102
+ self.data[i].load(loc+prefix2+sep+'{:>0{width}d}.hdf5'.format(int(files[i]),width=ndigits),headonly=honly,thermo=thermo,compress=compress)
103
+ else:
104
+ if i<len(files1):
105
+ self.data[i].load(loc+prefix+sep+'{:>0{width}d}'.format(int(files[i]),width=ndigits),headonly=honly,thermo=thermo,compress=compress)
106
+ else:
107
+ self.data[i].load(loc+prefix2+sep+'{:>0{width}d}'.format(int(files[i]),width=ndigits),headonly=honly,thermo=thermo,compress=compress)
108
+
109
+ self.snap = self.data
110
+
111
+
112
+ def plotseq(self, n=4, ptype='materials', type=None, seq=None, times=None, scale='Mm', potmin=False, tcut = 3600., zoom=1., focus='potmin', cmap=None):
113
+ """
114
+ tcut -- time cut for pre-contact treatment
115
+ """
116
+ if seq is None: # and times is None:
117
+ if self.nsnaps>n:
118
+ seq = npy.logspace(0,npy.log10(len(self.data)-1),n).astype(int)
119
+ else:
120
+ seq = npy.arange(self.nsnaps)
121
+ elif seq is not None:
122
+ n = len(seq)
123
+
124
+ if type: # for backwards compatibility
125
+ ptype = type
126
+
127
+ scf = plotting.get_scale_fac(scale)
128
+ axlim = 4*int(npy.ceil((self.data[0].x.max()-self.data[0].x.min())/scf/8.))
129
+ zcut = axlim/200.*scf
130
+
131
+ # region to grid/plot
132
+ #zmin=-axlim/10.
133
+ #zmax=axlim/10.
134
+
135
+ axlim /= zoom
136
+
137
+ # number of cells for grid
138
+ Ng = 1601j
139
+ #Ngz = 21j
140
+
141
+ #zi=npy.linspace(zmin,zmax,int(Ngz.imag))
142
+ #X,Y,Z = npy.mgrid[-axlim:axlim:(Ng),-axlim:axlim:(Ng),zmin:zmax:(Ngz)]
143
+ X,Y = npy.mgrid[-axlim:axlim:(Ng),-axlim:axlim:(Ng)]
144
+ Z = npy.full_like(X, 0)
145
+
146
+ if potmin: # for backwards compatibility
147
+ focus='potmin'
148
+
149
+ if not cmap:
150
+ cmap = plotting.get_default_colormap(ptype)
151
+ if ptype in plotting.phase_type:
152
+ cmap = matplotlib.colors.ListedColormap(cmap.colors[[0,1,2,3,4,5],:])
153
+ #cmap = matplotlib.colors.ListedColormap(cmap.colors[0,1,2,3,4,5])
154
+
155
+ fig = plt.figure(figsize=(10,6))
156
+
157
+ for i in range(len(seq)):
158
+ j = seq[i]
159
+ plt.subplot(1,n,i+1,aspect='equal')
160
+
161
+ if ptype in plotting.materials_type:
162
+ im = plotting.plot_snapshot_scatter(self.data[j],cmap=cmap,plotQ=-(self.data[j].id/PROJ_ID_OFFSET).astype(int),ptype=ptype,axlim=axlim,scale=scale,zcut=zcut,tcut=tcut,focus=focus)
163
+ elif ptype in plotting.density_type:
164
+ im = plotting.plot_snapshot_fluid(self.data[j],X,Y,Z,ax=plt.gca(),cmap=cmap,ptype=ptype,axlim=axlim,scale=scale,zcut=zcut,tcut=tcut,vcut=0.5*self.data[0].vel.min(),focus=focus)
165
+ elif ptype in plotting.entropy_type:
166
+ im = plotting.plot_snapshot_fluid(self.data[j],X,Y,Z,plotQ=self.data[j].S/1e7,ax=plt.gca(),cmap=cmap,ptype=ptype,axlim=axlim,scale=scale,zcut=zcut,tcut=tcut,vcut=0.5*self.data[0].vel.min(),focus=focus)
167
+ elif ptype in plotting.temperature_type:
168
+ im = plotting.plot_snapshot_fluid(self.data[j],X,Y,Z,plotQ=self.data[j].T,ax=plt.gca(),cmap=cmap,ptype=ptype,axlim=axlim,scale=scale,zcut=zcut,tcut=tcut,vcut=0.5*self.data[0].vel.min(),focus=focus)
169
+ elif ptype in plotting.pressure_type:
170
+ im = plotting.plot_snapshot_fluid(self.data[j],X,Y,Z,plotQ=self.data[j].P/1e9,ax=plt.gca(),cmap=cmap,ptype=ptype,axlim=axlim,scale=scale,zcut=zcut,tcut=tcut,vcut=0.5*self.data[0].vel.min(),focus=focus)
171
+ elif ptype in plotting.phase_type:
172
+ im = plotting.plot_snapshot_scatter(self.data[j],cmap=cmap,plotQ=self.data[j].phase,ptype=ptype,axlim=axlim,scale=scale,zcut=zcut,tcut=tcut,focus=focus)
173
+
174
+ if i>0:
175
+ plt.gca().set_yticklabels([])
176
+ plt.gca().set_ylabel('')
177
+
178
+ if i == len(seq)-1:
179
+ tlab = plt.gca().texts[0]
180
+ tlab.set_text(tlab.get_text()+' hrs')
181
+
182
+ if ptype not in plotting.materials_type:
183
+ if i == len(seq)-1:
184
+ pbox=plt.gca().get_position()
185
+ xw = 0.25
186
+ cbar_ax = fig.add_axes([pbox.x1-xw, pbox.y1*1.1, xw, 0.015])
187
+ cbar = fig.colorbar(im, cax=cbar_ax, orientation='horizontal')
188
+ plotting.format_colorbar_axis(cbar, ptype)
189
+ plt.subplots_adjust(wspace=0, hspace=0)
190
+ #plt.show(block=False)
191
+ return fig
192
+
193
+
194
+ def attrmov(self, n=40, ptype='materials', seq=None, times=None, scale='Mm', focus='potmin', fps=12, zoom=1., cmap = None, dpi=400, bitrate=5000, tcut = 3600.):
195
+ if seq is None: #and times is None:
196
+ if self.nsnaps>n:
197
+ seq = npy.logspace(0,npy.log10(len(self.data)-1),n).astype(int)
198
+ else:
199
+ seq = npy.arange(self.nsnaps-1)
200
+ elif seq is not None:
201
+ n = len(seq)
202
+
203
+ if ptype not in [*plotting.materials_type,*plotting.density_type,*plotting.entropy_type,*plotting.phase_type,*plotting.pressure_type,*plotting.temperature_type]:
204
+ raise ValueError('Unknown plot type:',ptype)
205
+
206
+ scf = plotting.get_scale_fac(scale)
207
+ axlim = 1.5*int(npy.ceil((self.data[0].x.max()-self.data[0].x.min())/scf/8.))/zoom #4*
208
+ zcut = axlim/200.*scf
209
+
210
+ # number of cells for grid
211
+ Ng = 1201j
212
+ #Ngz = 21j
213
+
214
+ # region to grid/plot
215
+ #zmin=-axlim/10.
216
+ #zmax=axlim/10.
217
+ #zlim = zmax/5.*scf
218
+
219
+ #zi=npy.linspace(zmin,zmax,int(Ngz.imag))
220
+ #X,Y,Z = npy.mgrid[-axlim:axlim:(Ng),-axlim:axlim:(Ng),zmin:zmax:(Ngz)]
221
+ X,Y = npy.mgrid[-axlim:axlim:(Ng),-axlim:axlim:(Ng)]
222
+ Z = npy.full_like(X, 0)
223
+
224
+
225
+ if not cmap:
226
+ cmap = plotting.get_default_colormap(ptype)
227
+ if ptype in plotting.phase_type:
228
+ cmap = matplotlib.colors.ListedColormap(cmap.colors[[0,1,2,3,4,5],:])
229
+
230
+ j = 0
231
+ def attrmovfunc(j):
232
+ plt.clf()
233
+ plt.minorticks_on()
234
+
235
+ if ptype in plotting.materials_type:
236
+ im = plotting.plot_snapshot_scatter(self.data[j],cmap=cmap,plotQ=-(self.data[j].id/PROJ_ID_OFFSET).astype(int),ax=plt.gca(),ptype=ptype,axlim=axlim,scale=scale,zcut=zcut,tcut=tcut,focus=focus)
237
+ elif ptype in plotting.phase_type:
238
+ im = plotting.plot_snapshot_scatter(self.data[j],cmap=cmap,plotQ=self.data[j].phase,ax=plt.gca(),ptype=ptype,axlim=axlim,scale=scale,zcut=zcut,tcut=tcut,focus=focus)
239
+ elif ptype in plotting.density_type:
240
+ im = plotting.plot_snapshot_fluid(self.data[j],X,Y,Z,plotQ=self.data[j].rho,ax=plt.gca(),cmap=cmap,ptype=ptype,axlim=axlim,scale=scale,zcut=zcut,tcut=tcut,vcut=0.5*self.data[0].vel.min(),focus=focus)
241
+ elif ptype in plotting.entropy_type:
242
+ im = plotting.plot_snapshot_fluid(self.data[j],X,Y,Z,plotQ=self.data[j].S/1e7,ax=plt.gca(),cmap=cmap,ptype=ptype,axlim=axlim,scale=scale,zcut=zcut,tcut=tcut,vcut=0.5*self.data[0].vel.min(),focus=focus)
243
+ elif ptype in plotting.temperature_type:
244
+ im = plotting.plot_snapshot_fluid(self.data[j],X,Y,Z,plotQ=self.data[j].T,ax=plt.gca(),cmap=cmap,ptype=ptype,axlim=axlim,scale=scale,zcut=zcut,tcut=tcut,vcut=0.5*self.data[0].vel.min(),focus=focus)
245
+ elif ptype in plotting.pressure_type:
246
+ im = plotting.plot_snapshot_fluid(self.data[j],X,Y,Z,plotQ=self.data[j].P/1e9,ax=plt.gca(),cmap=cmap,ptype=ptype,axlim=axlim,scale=scale,zcut=zcut,tcut=tcut,vcut=0.5*self.data[0].vel.min(),focus=focus)
247
+
248
+ if ptype not in plotting.materials_type:
249
+ pbox = plt.gca().get_position()
250
+ cbar_ax = fig.add_axes([pbox.x1*1.02, pbox.y0, 0.035, 1.0*(pbox.y1-pbox.y0)])
251
+ cbar = fig.colorbar(im, cax=cbar_ax, orientation='vertical')
252
+ plotting.format_colorbar_axis(cbar, ptype, y=True)
253
+
254
+ if n>30 and j!=0 and j!=len(self.data)-1:
255
+ self.data[j].freedata()
256
+
257
+ fig = plt.figure(figsize=(3.5,2.8))
258
+
259
+ if len(seq)==1:
260
+ attrmovfunc(seq[0])
261
+ plt.subplots_adjust(top=0.98,bottom=0.11,left=0.17,right=0.8)
262
+ plt.show(block=False)
263
+ return fig
264
+ else:
265
+ if matplotlib.animation.FFMpegWriter.isAvailable():
266
+ filetype = '.mp4'
267
+ else:
268
+ filetype = '.gif'
269
+ if ptype in plotting.materials_type:
270
+ movfile = os.path.dirname(self.data[0].file)+'/materials'+filetype
271
+ elif ptype in plotting.density_type:
272
+ movfile = os.path.dirname(self.data[0].file)+'/density'+filetype
273
+ elif ptype in plotting.entropy_type:
274
+ movfile = os.path.dirname(self.data[0].file)+'/entropy'+filetype
275
+ elif ptype in plotting.phase_type:
276
+ movfile = os.path.dirname(self.data[0].file)+'/phase'+filetype
277
+ elif ptype in plotting.pressure_type:
278
+ movfile = os.path.dirname(self.data[0].file)+'/pressure'+filetype
279
+ elif ptype in plotting.temperature_type:
280
+ movfile = os.path.dirname(self.data[0].file)+'/temperature'+filetype
281
+ else:
282
+ movfile = os.path.dirname(self.data[0].file)+'/attrmov'+filetype
283
+ anim=matplotlib.animation.FuncAnimation(fig,attrmovfunc,seq)
284
+ plt.subplots_adjust(top=0.975,bottom=0.105,left=0.17,right=0.8)
285
+ ##anim.save(movfile,dpi=200,writer=matplotlib.animation.PillowWriter(fps=fps,bitrate=1000)) #writer='ffmpeg' # 800 # 9000 fps=fps,bitrate=1000
286
+ anim.save(movfile,dpi=dpi,fps=fps,bitrate=bitrate) #writer='ffmpeg' # 800 # 9000 fps=fps,bitrate=1000
287
+ plt.show()
288
+ plt.close()
289
+
290
+ html=display.Video(movfile,embed=True,width=500)
291
+ return html
292
+
293
+
294
+
295
+ def multiplotseq(imps, n=4, types='materials', seqs=None, times=None, scale='Mm', potmin=False, zoom=1., uppercaselab=False, focus='potmin', tcut=3600.):
296
+ if (not isinstance(imps,list)) and (not isinstance(types,list)):
297
+ return imps.plotseq(n=n,ptype=types,seq=seqs,times=times,scale=scale,focus=focus,zoom=zoom)
298
+ elif not isinstance(imps,list):
299
+ imps=[imps,]
300
+ elif not isinstance(types,list):
301
+ types=[types,]
302
+ if seqs is None: # and times is None:
303
+ if imps[0].nsnaps>n:
304
+ seqs = npy.logspace(0,npy.log10(len(imps[0].data)-1),n).astype(int)
305
+ else:
306
+ seqs = npy.arange(imps[0].nsnaps)
307
+ elif not isinstance(seqs,list):
308
+ n = len(seqs)
309
+ seqs = [seqs,]
310
+ elif seqs:
311
+ n = [len(s) for s in seqs]
312
+ if not all(x==n[0] for x in n):
313
+ print('Warning: unequal sequences will produce ugly plots')
314
+
315
+ if not isinstance(zoom,list):
316
+ zoom=[zoom,]
317
+
318
+ scf = plotting.get_scale_fac(scale)
319
+
320
+ # number of cells for grid
321
+ Ng = 1201j
322
+ #Ngz = 15j
323
+
324
+ if potmin:
325
+ focus='potmin'
326
+
327
+ m = 1
328
+ k = 0
329
+ leftcol = None
330
+ toprow = None
331
+
332
+ fig = plt.figure()#figsize=(10,4))
333
+ fig.set_figwidth(8.)
334
+ fig.set_figheight(8./max(n)*(len(imps)*len(types)) + 1.*len(imps)**1.75)#-0.1
335
+ gs = fig.add_gridspec(ncols=max(n), nrows=len(imps)*len(types),wspace=0,hspace=0,right=0.98,top=0.96)
336
+ #print(max(n),len(imps)*len(types))
337
+
338
+ for imp, seq, zoomfac in zip(imps, seqs, zoom):#, types):
339
+ axlim = 2*int(npy.ceil((imp.data[0].x.max()-imp.data[0].x.min())/scf/8.)) #4
340
+ zcut = axlim/200.*scf #200
341
+ # region to grid/plot
342
+ #zmin = -axlim/10.
343
+ #zmax = axlim/10.
344
+ axlim /= zoomfac
345
+
346
+ #zlim = zmax/5.*scf
347
+ #zi = npy.linspace(zmin,zmax,int(Ngz.imag))
348
+ #X,Y,Z = npy.mgrid[-axlim:axlim:(Ng),-axlim:axlim:(Ng),zmin:zmax:(Ngz)]
349
+ X,Y = npy.mgrid[-axlim:axlim:(Ng),-axlim:axlim:(Ng)]
350
+ Z = npy.full_like(X, 0)
351
+
352
+ l = 0
353
+
354
+ for ptype in types:
355
+ n = len(seq)
356
+ # if l==0:
357
+ # cmap = plt.get_cmap('cmr.bubblegum').copy() #'plasma'
358
+ # cmapphase = plt.get_cmap('plasma', 6).copy()
359
+ # elif l==1 and len(types)>2:
360
+ # cmap = plt.get_cmap('cmr.bubblegum').copy()#cmocean.cm.haline #plt.get_cmap('magma')#.reversed()
361
+ # cmapphase = plt.get_cmap('cmr.bubblegum', 6).copy()
362
+ # elif l==2 or l==1:
363
+ # cmap = plt.get_cmap('cmr.eclipse').copy()
364
+ # cmapphase = plt.get_cmap('cmr.eclipse', 6).copy()
365
+ # else:
366
+ # cmap=plt.get_cmap('plasma').copy()
367
+ # cmapphase = plt.get_cmap('plasma', 6).copy()
368
+ cmap = plotting.get_default_colormap(ptype)
369
+ if ptype in plotting.phase_type:
370
+ cmap = matplotlib.colors.ListedColormap(cmap.colors[[0,1,2,3,4,5],:])
371
+ # if ptype in plotting.density_type:
372
+ # cmap.set_under('k')
373
+ # else:
374
+ # cmap.set_under('w')
375
+
376
+ for i in range(len(seq)):
377
+ j = seq[i]
378
+ #plt.subplot(len(imps),n,(m-1)*n + i+1,aspect='equal')
379
+ fig.add_subplot(gs[m-1,i],aspect='equal')
380
+
381
+ if imp.data[j].header.time < tcut:
382
+ vcut = 0.5*imp.data[0].vel.min()
383
+
384
+ if ptype in plotting.materials_type:
385
+ im = plotting.plot_snapshot_scatter(imp.data[j],cmap=cmap,plotQ=-(imp.data[j].id/PROJ_ID_OFFSET).astype(int),ax=plt.gca(),ptype=ptype,axlim=axlim,scale=scale,zcut=zcut,tcut=tcut,focus=focus)
386
+ elif ptype in plotting.density_type:
387
+ im = plotting.plot_snapshot_fluid(imp.data[j],X,Y,Z,ax=plt.gca(),cmap=cmap,ptype=ptype,plotQ=imp.data[j].rho,axlim=axlim,scale=scale,zcut=zcut,tcut=tcut,vcut=vcut,focus=focus)
388
+ elif ptype in plotting.pressure_type:
389
+ im = plotting.plot_snapshot_fluid(imp.data[j],X,Y,Z,ax=plt.gca(),cmap=cmap,ptype=ptype,plotQ=imp.data[j].P/1e9,axlim=axlim,scale=scale,zcut=zcut,tcut=tcut,vcut=vcut,focus=focus)
390
+ elif ptype in plotting.entropy_type:
391
+ im = plotting.plot_snapshot_fluid(imp.data[j],X,Y,Z,ax=plt.gca(),cmap=cmap,ptype=ptype,plotQ=imp.data[j].S/1e7,axlim=axlim,scale=scale,zcut=zcut,focus=focus,tcut=tcut,vcut=vcut)
392
+ elif ptype in plotting.temperature_type:
393
+ im = plotting.plot_snapshot_fluid(imp.data[j],X,Y,Z,ax=plt.gca(),cmap=cmap,ptype=ptype,plotQ=imp.data[j].T,axlim=axlim,scale=scale,zcut=zcut,focus=focus,tcut=tcut,vcut=vcut)
394
+ elif ptype in plotting.phase_type:
395
+ im = plotting.plot_snapshot_scatter(imp.data[j],cmap=cmap,plotQ=imp.data[j].phase,ptype=ptype,ax=plt.gca(),axlim=axlim,scale=scale,zcut=zcut,tcut=tcut,focus=focus)
396
+
397
+ if i>0:
398
+ plt.gca().set_yticklabels([])
399
+ plt.gca().set_ylabel('')
400
+ if m != len(imps)*len(types):
401
+ plt.gca().set_xticklabels([])
402
+ plt.gca().set_xlabel('')
403
+ if i==0:
404
+ if ptype in [*plotting.density_type,*plotting.temperature_type]:
405
+ if uppercaselab:
406
+ plt.text(0.05,0.95,chr(64+m),ha='left',va='top',fontsize=9,fontweight='bold',color='w',transform=plt.gca().transAxes)
407
+ else:
408
+ plt.text(0.05,0.95,chr(96+m),ha='left',va='top',fontsize=9,fontweight='bold',color='w',transform=plt.gca().transAxes)
409
+ else:
410
+ if uppercaselab:
411
+ plt.text(0.05,0.95,chr(64+m),ha='left',va='top',fontsize=9,fontweight='bold',color='k',transform=plt.gca().transAxes)
412
+ else:
413
+ plt.text(0.05,0.95,chr(96+m),ha='left',va='top',fontsize=9,fontweight='bold',color='k',transform=plt.gca().transAxes)
414
+
415
+ ax = plt.gca()
416
+ if i>0:
417
+ colpos = ax.get_position()
418
+ gap = leftcol.x1-colpos.x0
419
+ ax.set_position([colpos.x0+gap,colpos.y0,colpos.width,colpos.height])
420
+ colpos = ax.get_position()
421
+ #else:
422
+ # pos = ax.get_position()
423
+ leftcol = ax.get_position()
424
+ if m>1:
425
+ rowpos = ax.get_position()
426
+ gap = toprow.y0-rowpos.y1
427
+ if k==1:
428
+ gap -= 0.04/max(1,len(imps)-1.1)#0.05
429
+ ax.set_position([rowpos.x0,rowpos.y0+gap,rowpos.width,rowpos.height])
430
+ #else:
431
+ # plt.subplots_adjust(wspace=0)
432
+
433
+ if m==1 and i==0:
434
+ firstplot = plt.gca()
435
+
436
+ if ptype not in plotting.materials_type:
437
+ if i == len(seq)-1 and (m==1 or m==len(imps)*len(types)):
438
+ pbox = ax.get_position()
439
+ xw = 0.33
440
+ if m==1:
441
+ cbar_ax = fig.add_axes([pbox.x1-xw, pbox.y1+0.26/max(1,2*len(imps)-1.9)*xw, xw, 0.02/max(1,2*len(imps)**0.8-1.8)])#0.27
442
+ #cbar_ax = fig.add_axes([pbox.x1-xw, pbox.y1+0.32*xw, xw, 0.015])
443
+ elif m==len(imps)*len(types):
444
+ pbox = firstplot.get_position()
445
+ #cbar_ax = fig.add_axes([pbox.x1-xw, pbox.y0-0.6/max(1,1.5*len(imps)-0.7)*xw, xw, 0.032/max(1,2*len(imps)-1.8)])#0.47
446
+ cbar_ax = fig.add_axes([pbox.x0, pbox.y1+0.26/max(1,2*len(imps)-1.9)*xw, xw, 0.02/max(1,2*len(imps)**0.8-1.8)])#0.47
447
+ cbar = fig.colorbar(im,cax=cbar_ax,orientation='horizontal')
448
+ plotting.format_colorbar_axis(cbar, ptype, y=False)
449
+ k=0
450
+ m+=1
451
+ l+=1
452
+ cbar_ax = None
453
+ toprow = ax.get_position()
454
+ k=1
455
+
456
+ #fig.set_figwidth(10)
457
+ #print(colpos.x0,colpos.y0,colpos.x1,colpos.y1)
458
+ #plt.show()
459
+ return fig
@@ -5,21 +5,21 @@ planit (PLANetary Impact Toolkit)
5
5
  Classes and functions for setting-up, accessing, manipulating,
6
6
  and analysing SPH impact simulation data.
7
7
 
8
- Supported planetary impact codes: gadget-2-planetary, swift
8
+ Supported planetary impact codes: gadget-2-planetary, swift, pkdgrav3
9
9
 
10
10
 
11
11
  Philip J. Carter (p.carter@bristol.ac.uk)
12
12
 
13
13
  Sarah T. Stewart (sstewa56@asu.edu)
14
14
 
15
- v1.0
15
+ v1.2
16
16
 
17
17
  """
18
18
 
19
19
  from .globaldefs import *
20
20
  from . import eos
21
21
  from . import utils
22
- from .snaptools import Snapshot
22
+ from .snaptools import Snapshot, io
23
23
  from .impacttools import Impact
24
24
 
25
25
 
@@ -40,7 +40,7 @@ def loadimpact(loc,thermo=False,inter=1,compress=True,code='swift'):
40
40
 
41
41
  def load_seagen(partplanet, thermo=False, init_h=100e5):
42
42
  s = Snapshot()
43
- s.load_seagen(partplanet, thermo=thermo, init_h=init_h)
43
+ io.load_seagen(s, partplanet, thermo=thermo, init_h=init_h)
44
44
  return s
45
45
 
46
46
  def combine(body1, body2, bidoffset=PROJ_ID_OFFSET, thermo=False, box=0.0):