From bbd5bc12cf446f09243f609ceb36371a50250e93 Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 2 Jul 2021 12:55:56 -0400 Subject: [PATCH] Updated this branch with the restructured Python module taken from the OOPrestructure branch --- examples/symba_chambers2013/aescattermovie.py | 116 ++ examples/symba_clement2018/aescattermovie.py | 116 ++ examples/symba_mars_disk/aescattermovie.py | 26 +- python/.DS_Store | Bin 8196 -> 0 bytes python/swiftest/.idea/.gitignore | 3 + python/swiftest/README.md | 2 + python/swiftest/requirements.txt | 86 + python/{swiftestio => swiftest}/setup.py | 4 +- python/swiftest/swiftest/__init__.py | 2 + python/swiftest/swiftest/constants.py | 15 + python/swiftest/swiftest/init_cond.py | 175 ++ python/swiftest/swiftest/io.py | 1192 ++++++++++++ python/swiftest/swiftest/simulation_class.py | 148 ++ python/swiftest/swiftest/tool.py | 85 + .../tests/bin2xr/swiftest/bin2xr_swiftest.py | 5 + .../tests/bin2xr/swiftest/cb.swiftest.in | 4 + .../tests/bin2xr/swiftest/param.swiftest.in | 31 + .../tests/bin2xr/swiftest/pl.swiftest.in | 29 + .../tests/bin2xr/swiftest/tp.swiftest.in | 4 + .../swift2swifter/param.swift.in | 6 + .../swift2swifter/pl.swift.in | 28 + .../convert_code_type/swift2swifter/swift.in | 3 + .../swift2swifter/swift2swifter.py | 14 + .../swift2swifter/tp.swift.in | 201 +++ .../swift2swiftest/param.swift.in | 6 + .../swift2swiftest/pl.swift.in | 28 + .../convert_code_type/swift2swiftest/swift.in | 3 + .../swift2swiftest/swift2swiftest.py | 14 + .../swift2swiftest/tp.swift.in | 201 +++ .../swifter2swiftest/param.swifter.in | 26 + .../swifter2swiftest/pl.swifter.in | 40 + .../swifter2swiftest/swifter2swiftest.py | 14 + .../swifter2swiftest/tp.swifter.in | 4 + .../tests/param_readers/param.swift.in | 6 + .../tests/param_readers/param.swifter.in | 26 + .../tests/param_readers/param.swiftest.in | 29 + .../tests/param_readers/param_readers.py | 24 + .../mars-scatter-checkpoint.ipynb | 1600 ----------------- .../testreader-checkpoint.ipynb | 6 - python/swiftestio/README.md | 1 - python/swiftestio/__init__.py | 0 python/swiftestio/swiftestio.py | 837 --------- python/swiftestio/testreader.ipynb | 163 -- 43 files changed, 2701 insertions(+), 2622 deletions(-) create mode 100644 examples/symba_chambers2013/aescattermovie.py create mode 100644 examples/symba_clement2018/aescattermovie.py delete mode 100644 python/.DS_Store create mode 100644 python/swiftest/.idea/.gitignore create mode 100644 python/swiftest/README.md create mode 100644 python/swiftest/requirements.txt rename python/{swiftestio => swiftest}/setup.py (70%) create mode 100644 python/swiftest/swiftest/__init__.py create mode 100644 python/swiftest/swiftest/constants.py create mode 100644 python/swiftest/swiftest/init_cond.py create mode 100644 python/swiftest/swiftest/io.py create mode 100644 python/swiftest/swiftest/simulation_class.py create mode 100644 python/swiftest/swiftest/tool.py create mode 100644 python/swiftest/tests/bin2xr/swiftest/bin2xr_swiftest.py create mode 100644 python/swiftest/tests/bin2xr/swiftest/cb.swiftest.in create mode 100644 python/swiftest/tests/bin2xr/swiftest/param.swiftest.in create mode 100644 python/swiftest/tests/bin2xr/swiftest/pl.swiftest.in create mode 100644 python/swiftest/tests/bin2xr/swiftest/tp.swiftest.in create mode 100644 python/swiftest/tests/convert_code_type/swift2swifter/param.swift.in create mode 100644 python/swiftest/tests/convert_code_type/swift2swifter/pl.swift.in create mode 100644 python/swiftest/tests/convert_code_type/swift2swifter/swift.in create mode 100644 python/swiftest/tests/convert_code_type/swift2swifter/swift2swifter.py create mode 100644 python/swiftest/tests/convert_code_type/swift2swifter/tp.swift.in create mode 100644 python/swiftest/tests/convert_code_type/swift2swiftest/param.swift.in create mode 100644 python/swiftest/tests/convert_code_type/swift2swiftest/pl.swift.in create mode 100644 python/swiftest/tests/convert_code_type/swift2swiftest/swift.in create mode 100644 python/swiftest/tests/convert_code_type/swift2swiftest/swift2swiftest.py create mode 100644 python/swiftest/tests/convert_code_type/swift2swiftest/tp.swift.in create mode 100644 python/swiftest/tests/convert_code_type/swifter2swiftest/param.swifter.in create mode 100644 python/swiftest/tests/convert_code_type/swifter2swiftest/pl.swifter.in create mode 100644 python/swiftest/tests/convert_code_type/swifter2swiftest/swifter2swiftest.py create mode 100644 python/swiftest/tests/convert_code_type/swifter2swiftest/tp.swifter.in create mode 100644 python/swiftest/tests/param_readers/param.swift.in create mode 100644 python/swiftest/tests/param_readers/param.swifter.in create mode 100644 python/swiftest/tests/param_readers/param.swiftest.in create mode 100644 python/swiftest/tests/param_readers/param_readers.py delete mode 100644 python/swiftestio/.ipynb_checkpoints/mars-scatter-checkpoint.ipynb delete mode 100644 python/swiftestio/.ipynb_checkpoints/testreader-checkpoint.ipynb delete mode 100644 python/swiftestio/README.md delete mode 100644 python/swiftestio/__init__.py delete mode 100644 python/swiftestio/swiftestio.py delete mode 100644 python/swiftestio/testreader.ipynb diff --git a/examples/symba_chambers2013/aescattermovie.py b/examples/symba_chambers2013/aescattermovie.py new file mode 100644 index 000000000..37e2e1f5a --- /dev/null +++ b/examples/symba_chambers2013/aescattermovie.py @@ -0,0 +1,116 @@ +import swiftest.io as swio +import numpy as np +import matplotlib.pyplot as plt +from matplotlib import animation +import matplotlib.colors as mcolors + +radscale = 20 +xmin = 1.0 +xmax = 10.0 +ymin = 1e-6 +ymax = 1.0 + +class AnimatedScatter(object): + """An animated scatter plot using matplotlib.animations.FuncAnimation.""" + def __init__(self, ds, param): + #outf = 'aescatter.mp4' + + frame = 0 + nframes = ds['time'].size + self.ds = ds + self.param = param + self.ds['Mass'] = self.ds['Mass'] / param['GU'] + self.ds['radmarker'] = self.ds['Radius'].fillna(0) + self.ds['radmarker'] = self.ds['radmarker'] / self.ds['radmarker'].max() * radscale + + self.clist = {'Initial conditions' : 'xkcd:faded blue', + 'Disruption' : 'xkcd:marigold', + 'Supercatastrophic' : 'xkcd:shocking pink', + 'Hit and run fragment' : 'xkcd:baby poop green'} + + self.stream = self.data_stream(frame) + # Setup the figure and axes... + self.fig, self.ax = plt.subplots(figsize=(8,4.5)) + # Then setup FuncAnimation. + self.ani = animation.FuncAnimation(self.fig, self.update, interval=1, frames=nframes, + init_func=self.setup_plot, blit=True) + self.ani.save('aescatter.mp4', fps=60, dpi=300, + extra_args=['-vcodec', 'libx264']) + print('Finished writing aescattter.mp4') + + def scatters(self, pl, radmarker, origin): + scat = [] + for key, value in self.clist.items(): + idx = origin == value + s = self.ax.scatter(pl[idx, 0], pl[idx, 1], marker='o', s=radmarker[idx], c=value, alpha=0.25, label=key) + scat.append(s) + return scat + + def setup_plot(self): + # First frame + """Initial drawing of the scatter plot.""" + t, name, Mass, Radius, npl, pl, radmarker, origin = next(self.data_stream(0)) + + # set up the figure + self.ax = plt.axes(xlim=(xmin, xmax), ylim=(ymin, ymax)) + self.ax.margins(x=10, y=1) + self.ax.set_xlabel('Semi Major Axis (AU)', fontsize='16', labelpad=1) + self.ax.set_ylabel('Eccentricity', fontsize='16', labelpad=1) + self.ax.set_yscale('log') + + self.title = self.ax.text(0.50, 1.05, "", bbox={'facecolor': 'w', 'alpha': 0.5, 'pad': 5}, transform=self.ax.transAxes, + ha="center") + + self.title.set_text(f'Time = ${t / 24 / 3600:4.1f}$ days with ${npl:f}$ particles') + slist = self.scatters(pl, radmarker, origin) + self.s0 = slist[0] + self.s1 = slist[1] + self.s2 = slist[2] + self.s3 = slist[3] + self.ax.legend(loc='upper right') + return self.s0, self.s1, self.s2, self.s3, self.title + + def data_stream(self, frame=0): + while True: + d = self.ds.isel(time=frame) + Radius = d['radmarker'].values + Mass = d['Mass'].values + a = d['a'].values + e = d['e'].values + name = d['id'].values + npl = d['npl'].values + radmarker = d['radmarker'] + origin = d['origin_type'] + + t = self.ds.coords['time'].values[frame] + + frame += 1 + yield t, name, Mass, Radius, npl, np.c_[a, e], radmarker, origin + + def update(self,frame): + """Update the scatter plot.""" + t, name, Mass, Radius, npl, pl, radmarker, origin = next(self.data_stream(frame)) + + self.title.set_text(f'Time = ${t / 24 / 3600:4.1f}$ days with ${npl:4.0f}$ particles') + + # We need to return the updated artist for FuncAnimation to draw.. + # Note that it expects a sequence of artists, thus the trailing comma. + s = [self.s0, self.s1, self.s2, self.s3] + for i, (key, value) in enumerate(self.clist.items()): + idx = origin == key + s[i].set_sizes(radmarker[idx]) + s[i].set_offsets(pl[idx,:]) + s[i].set_facecolor(value) + + self.s0 = s[0] + self.s1 = s[1] + self.s2 = s[2] + self.s3 = s[3] + return self.s0, self.s1, self.s2, self.s3, self.title, + + +param = swio.read_swiftest_param("param.in") +marsdisk = swio.swiftest2xr(param) +print('Making animation') +anim = AnimatedScatter(marsdisk,param) +print('Animation finished') diff --git a/examples/symba_clement2018/aescattermovie.py b/examples/symba_clement2018/aescattermovie.py new file mode 100644 index 000000000..37e2e1f5a --- /dev/null +++ b/examples/symba_clement2018/aescattermovie.py @@ -0,0 +1,116 @@ +import swiftest.io as swio +import numpy as np +import matplotlib.pyplot as plt +from matplotlib import animation +import matplotlib.colors as mcolors + +radscale = 20 +xmin = 1.0 +xmax = 10.0 +ymin = 1e-6 +ymax = 1.0 + +class AnimatedScatter(object): + """An animated scatter plot using matplotlib.animations.FuncAnimation.""" + def __init__(self, ds, param): + #outf = 'aescatter.mp4' + + frame = 0 + nframes = ds['time'].size + self.ds = ds + self.param = param + self.ds['Mass'] = self.ds['Mass'] / param['GU'] + self.ds['radmarker'] = self.ds['Radius'].fillna(0) + self.ds['radmarker'] = self.ds['radmarker'] / self.ds['radmarker'].max() * radscale + + self.clist = {'Initial conditions' : 'xkcd:faded blue', + 'Disruption' : 'xkcd:marigold', + 'Supercatastrophic' : 'xkcd:shocking pink', + 'Hit and run fragment' : 'xkcd:baby poop green'} + + self.stream = self.data_stream(frame) + # Setup the figure and axes... + self.fig, self.ax = plt.subplots(figsize=(8,4.5)) + # Then setup FuncAnimation. + self.ani = animation.FuncAnimation(self.fig, self.update, interval=1, frames=nframes, + init_func=self.setup_plot, blit=True) + self.ani.save('aescatter.mp4', fps=60, dpi=300, + extra_args=['-vcodec', 'libx264']) + print('Finished writing aescattter.mp4') + + def scatters(self, pl, radmarker, origin): + scat = [] + for key, value in self.clist.items(): + idx = origin == value + s = self.ax.scatter(pl[idx, 0], pl[idx, 1], marker='o', s=radmarker[idx], c=value, alpha=0.25, label=key) + scat.append(s) + return scat + + def setup_plot(self): + # First frame + """Initial drawing of the scatter plot.""" + t, name, Mass, Radius, npl, pl, radmarker, origin = next(self.data_stream(0)) + + # set up the figure + self.ax = plt.axes(xlim=(xmin, xmax), ylim=(ymin, ymax)) + self.ax.margins(x=10, y=1) + self.ax.set_xlabel('Semi Major Axis (AU)', fontsize='16', labelpad=1) + self.ax.set_ylabel('Eccentricity', fontsize='16', labelpad=1) + self.ax.set_yscale('log') + + self.title = self.ax.text(0.50, 1.05, "", bbox={'facecolor': 'w', 'alpha': 0.5, 'pad': 5}, transform=self.ax.transAxes, + ha="center") + + self.title.set_text(f'Time = ${t / 24 / 3600:4.1f}$ days with ${npl:f}$ particles') + slist = self.scatters(pl, radmarker, origin) + self.s0 = slist[0] + self.s1 = slist[1] + self.s2 = slist[2] + self.s3 = slist[3] + self.ax.legend(loc='upper right') + return self.s0, self.s1, self.s2, self.s3, self.title + + def data_stream(self, frame=0): + while True: + d = self.ds.isel(time=frame) + Radius = d['radmarker'].values + Mass = d['Mass'].values + a = d['a'].values + e = d['e'].values + name = d['id'].values + npl = d['npl'].values + radmarker = d['radmarker'] + origin = d['origin_type'] + + t = self.ds.coords['time'].values[frame] + + frame += 1 + yield t, name, Mass, Radius, npl, np.c_[a, e], radmarker, origin + + def update(self,frame): + """Update the scatter plot.""" + t, name, Mass, Radius, npl, pl, radmarker, origin = next(self.data_stream(frame)) + + self.title.set_text(f'Time = ${t / 24 / 3600:4.1f}$ days with ${npl:4.0f}$ particles') + + # We need to return the updated artist for FuncAnimation to draw.. + # Note that it expects a sequence of artists, thus the trailing comma. + s = [self.s0, self.s1, self.s2, self.s3] + for i, (key, value) in enumerate(self.clist.items()): + idx = origin == key + s[i].set_sizes(radmarker[idx]) + s[i].set_offsets(pl[idx,:]) + s[i].set_facecolor(value) + + self.s0 = s[0] + self.s1 = s[1] + self.s2 = s[2] + self.s3 = s[3] + return self.s0, self.s1, self.s2, self.s3, self.title, + + +param = swio.read_swiftest_param("param.in") +marsdisk = swio.swiftest2xr(param) +print('Making animation') +anim = AnimatedScatter(marsdisk,param) +print('Animation finished') diff --git a/examples/symba_mars_disk/aescattermovie.py b/examples/symba_mars_disk/aescattermovie.py index b6acb53fb..18d17350e 100644 --- a/examples/symba_mars_disk/aescattermovie.py +++ b/examples/symba_mars_disk/aescattermovie.py @@ -1,4 +1,4 @@ -import swiftestio as swio +import swiftest.io as swio import numpy as np import matplotlib.pyplot as plt from matplotlib import animation @@ -13,15 +13,15 @@ class AnimatedScatter(object): """An animated scatter plot using matplotlib.animations.FuncAnimation.""" - def __init__(self, ds, config): + def __init__(self, ds, param): #outf = 'aescatter.mp4' frame = 0 nframes = ds['time'].size self.ds = ds - self.config = config - self.ds['mass'] = self.ds['mass'] / config['GU'] - self.ds['radmarker'] = self.ds['radius'].fillna(0) + self.param = param + self.ds['Mass'] = self.ds['Mass'] / param['GU'] + self.ds['radmarker'] = self.ds['Radius'].fillna(0) self.ds['radmarker'] = self.ds['radmarker'] / self.ds['radmarker'].max() * radscale self.clist = {'Initial conditions' : 'xkcd:faded blue', @@ -50,7 +50,7 @@ def scatters(self, pl, radmarker, origin): def setup_plot(self): # First frame """Initial drawing of the scatter plot.""" - t, name, mass, radius, npl, pl, radmarker, origin = next(self.data_stream(0)) + t, name, Mass, Radius, npl, pl, radmarker, origin = next(self.data_stream(0)) # set up the figure self.ax = plt.axes(xlim=(xmin, xmax), ylim=(ymin, ymax)) @@ -74,8 +74,8 @@ def setup_plot(self): def data_stream(self, frame=0): while True: d = self.ds.isel(time=frame) - radius = d['radmarker'].values - mass = d['mass'].values + Radius = d['radmarker'].values + Mass = d['Mass'].values a = d['a'].values / RMars e = d['e'].values name = d['id'].values @@ -86,11 +86,11 @@ def data_stream(self, frame=0): t = self.ds.coords['time'].values[frame] frame += 1 - yield t, name, mass, radius, npl, np.c_[a, e], radmarker, origin + yield t, name, Mass, Radius, npl, np.c_[a, e], radmarker, origin def update(self,frame): """Update the scatter plot.""" - t, name, mass, radius, npl, pl, radmarker, origin = next(self.data_stream(frame)) + t, name, Mass, Radius, npl, pl, radmarker, origin = next(self.data_stream(frame)) self.title.set_text(f'Time = ${t / 24 / 3600:4.1f}$ days with ${npl:4.0f}$ particles') @@ -110,8 +110,8 @@ def update(self,frame): return self.s0, self.s1, self.s2, self.s3, self.title, -config = swio.read_swiftest_config("param.in") -marsdisk = swio.swiftest2xr(config) +param = swio.read_swiftest_param("param.in") +marsdisk = swio.swiftest2xr(param) print('Making animation') -anim = AnimatedScatter(marsdisk,config) +anim = AnimatedScatter(marsdisk,param) print('Animation finished') diff --git a/python/.DS_Store b/python/.DS_Store deleted file mode 100644 index 003a7918e1f539f333acc9f83d8cb191664f5032..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMU2GLa6h3GB!|nnyaDnpI_CjgITA+Wnm=?YL1FJv_E%XO!*?V`PtJ~drckjKF zQqu=RjH1y8G%6;(5CbGUm|%P`#s_13ASM$0eK0ZL&y(@ZXf%3eW_tz7eN~h0Br|8u zoO5RPocYdd&n*C8N5-rNSOWkmbxzr08t&4#ocDQ630F#pBH053V1ZAg4cQ3Rq0EXWA(`yo!9(?m#TB^6f(4Wa}fT1?BL z(VXf4VG|E&BBZmD3RBusRu34OVpw9JG$(nSs}oIxbXHPn4k*n5!zW`{p`ds=*~NuA zU_#Ppj3N+4V15L6?XFYJo}-%m*sb+@kK?71j+Z1kPpMYwTmBM_W(91LIe#*=xtg4G zY(J>0`x2F+;*!!uszz<8HrhY#<@y67$oL&b`Y`AEj9@$&&Idft$k z8yL20rG>F=TBLGh&~{BP*WqPc(--^nOM!UM7+XI*z4d|SmfCoIV?*6cZG5`EVMkqU zd`Erb%#5a%RoCzAIXW?Qa{AQF)8~XofZ^2w%Osy4-z?;><7YdizeS~U{(hDBS6>`E zG^h^`*(uNMw@+GQY?)8)_7K~bwzA~fV9Ikc6RtnTmZuCSm2r%~YIhv2><ykyn7%Bn3}8(P}h zyZ7$DzVx1DOkWXOIheJ5JLy;lbG8|b4;y~Ua!uPkK0+~c1N)e5r8V}pI^Y@;mN1Hy z#n!5S4a#nYL(@%X)R}UX2;* zfKQ&uEo$^yjrrQZlXRZabh}=!GE+O~7)i^KOHF#S${y1Ov(iDi_@LgZF2`DJDCJE| z&};j0`Jq@sWuK^z^Jnid{GfNza{qa&E>#`ol6KRiMYe1ABR!ACVt2-2EvUfEV!+ zUcnFWBm5MF%($vSKxST+e*wqpl&;vRx#pMd6J9K|s_N&tNV9fGGz@SGxe zp28VCjnCq9_&lD$v-m2$hOgrrcn;6wMG3e(0DEo+AYLj2z-)iobv*Yt$>+d(yXgYt zilonLc>Uj9`1k(>7@5fBC;|&70$AMD-_=3>7P=XEtsSR+lsa!*Z&p%aLW3yBiHdTZ mX#O9DG>?-iw@HL_R#IA__OJgCP~b1+==&di{{ 0: + for key in param: + if (key == fields[0].upper()): param[key] = fields[1] + # Special case of CHK_QMIN_RANGE requires a second input + if fields[0].upper() == 'CHK_QMIN_RANGE': + alo = real2float(fields[1]) + ahi = real2float(fields[2]) + param['CHK_QMIN_RANGE'] = f"{alo} {ahi}" + + param['ISTEP_OUT'] = int(param['ISTEP_OUT']) + param['ISTEP_DUMP'] = int(param['ISTEP_DUMP']) + param['T0'] = real2float(param['T0']) + param['TSTOP'] = real2float(param['TSTOP']) + param['DT'] = real2float(param['DT']) + param['J2'] = real2float(param['J2']) + param['J4'] = real2float(param['J4']) + param['CHK_RMIN'] = real2float(param['CHK_RMIN']) + param['CHK_RMAX'] = real2float(param['CHK_RMAX']) + param['CHK_EJECT'] = real2float(param['CHK_EJECT']) + param['CHK_QMIN'] = real2float(param['CHK_QMIN']) + param['MTINY'] = real2float(param['MTINY']) + param['DU2M'] = real2float(param['DU2M']) + param['MU2KG'] = real2float(param['MU2KG']) + param['TU2S'] = real2float(param['TU2S']) + param['EXTRA_FORCE'] = param['EXTRA_FORCE'].upper() + param['BIG_DISCARD'] = param['BIG_DISCARD'].upper() + param['CHK_CLOSE'] = param['CHK_CLOSE'].upper() + param['FRAGMENTATION'] = param['FRAGMENTATION'].upper() + param['ROTATION'] = param['ROTATION'].upper() + param['TIDES'] = param['TIDES'].upper() + param['ENERGY'] = param['ENERGY'].upper() + param['GR'] = param['GR'].upper() + param['YORP'] = param['YORP'].upper() + param['GU'] = swiftest.GC / (param['DU2M'] ** 3 / (param['MU2KG'] * param['TU2S'] ** 2)) + except IOError: + print(f"{param_file_name} not found.") + return param + +def read_swifter_param(param_file_name): + """ + Reads in a Swifter param.in file and saves it as a dictionary + + Parameters + ---------- + param_file_name : string + File name of the input parameter file + + Returns + ------- + param + A dictionary containing the entries in the user parameter file + """ + param = { + '! VERSION': f"Swifter parameter input from file {param_file_name}", + 'T0': "0.0", + 'TSTOP': "0.0", + 'DT': "0.0", + 'PL_IN': "", + 'TP_IN': "", + 'IN_TYPE': "ASCII", + 'ISTEP_OUT': "-1", + 'ISTEP_DUMP': "-1", + 'BIN_OUT': "bin.dat", + 'OUT_TYPE': "REAL8", + 'OUT_FORM': "XV", + 'OUT_STAT': "NEW", + 'J2': "0.0", + 'J4': "0.0", + 'CHK_CLOSE': 'NO', + 'CHK_RMIN': "-1.0", + 'CHK_RMAX': "-1.0", + 'CHK_EJECT': "-1.0", + 'CHK_QMIN': "-1.0", + 'CHK_QMIN_COORD': "HELIO", + 'CHK_QMIN_RANGE': "", + 'ENC_OUT': "", + 'EXTRA_FORCE': 'NO', + 'BIG_DISCARD': 'NO', + 'RHILL_PRESENT': 'NO', + 'C': "-1.0", + } + + # Read param.in file + print(f'Reading Swifter file {param_file_name}') + try: + with open(param_file_name, 'r') as f: + for line in f.readlines(): + fields = line.split() + if len(fields) > 0: + for key in param: + if (key == fields[0].upper()): param[key] = fields[1] + # Special case of CHK_QMIN_RANGE requires a second input + if fields[0].upper() == 'CHK_QMIN_RANGE': + alo = real2float(fields[1]) + ahi = real2float(fields[2]) + param['CHK_QMIN_RANGE'] = f"{alo} {ahi}" + + param['ISTEP_OUT'] = int(param['ISTEP_OUT']) + param['ISTEP_DUMP'] = int(param['ISTEP_DUMP']) + param['T0'] = real2float(param['T0']) + param['TSTOP'] = real2float(param['TSTOP']) + param['DT'] = real2float(param['DT']) + param['J2'] = real2float(param['J2']) + param['J4'] = real2float(param['J4']) + param['CHK_RMIN'] = real2float(param['CHK_RMIN']) + param['CHK_RMAX'] = real2float(param['CHK_RMAX']) + param['CHK_EJECT'] = real2float(param['CHK_EJECT']) + param['CHK_QMIN'] = real2float(param['CHK_QMIN']) + param['EXTRA_FORCE'] = param['EXTRA_FORCE'].upper() + param['BIG_DISCARD'] = param['BIG_DISCARD'].upper() + param['CHK_CLOSE'] = param['CHK_CLOSE'].upper() + param['RHILL_PRESENT'] = param['RHILL_PRESENT'].upper() + if param['C'] != '-1.0': + param['C'] = real2float(param['C']) + else: + param.pop('C', None) + except IOError: + print(f"{param_file_name} not found.") + + return param + +def read_swift_param(param_file_name, startfile="swift.in"): + """ + Reads in a Swift param.in file and saves it as a dictionary + + Parameters + ---------- + param_file_name : string + File name of the input parameter file + + Returns + ------- + param : dict + A dictionary containing the entries in the user parameter file + """ + param = { + '! VERSION': f"Swift parameter input from file {param_file_name}", + 'T0': 0.0, + 'TSTOP': 0.0, + 'DT': 0.0, + 'DTOUT': 0.0, + 'DTDUMP': 0.0, + 'L1': "F", + 'L1': "F", + 'L2': "F", + 'L3': "F", + 'L4': "F", + 'L5': "F", + 'L6': "F", + 'RMIN': -1, + 'RMAX': -1, + 'RMAXU': -1, + 'QMIN': -1, + 'LCLOSE': "F", + 'BINARY_OUTPUTFILE': "bin.dat", + 'STATUS_FLAG_FOR_OPEN_STATEMENTS': "NEW", + } + + try: + with open(startfile, 'r') as f: + line = f.readline() + plname = f.readline().split()[0] + tpname = f.readline().split()[0] + except: + plname = "pl.in" + tpname = "tp.in" + param['PL_IN'] = plname + param['TP_IN'] = tpname + + # Read param.in file + print(f'Reading Swift file {param_file_name}') + try: + with open(param_file_name, 'r') as f: + line = f.readline().split() + for i, l in enumerate(line): + line[i] = l + param['T0'] = real2float(line[0]) + param['TSTOP'] = real2float(line[1]) + param['DT'] = real2float(line[2]) + line = f.readline().split() + for i, l in enumerate(line): + line[i] = l + param['DTOUT'] = real2float(line[0]) + param['DTDUMP'] = real2float(line[1]) + line = f.readline().split() + param['L1'] = line[0].upper() + param['L2'] = line[1].upper() + param['L3'] = line[2].upper() + param['L4'] = line[3].upper() + param['L5'] = line[4].upper() + param['L6'] = line[5].upper() + if param['L2'] == "T": + line = f.readline().split() + for i, l in enumerate(line): + line[i] = l + param['RMIN'] = real2float(line[0]) + param['RMAX'] = real2float(line[1]) + param['RMAXU'] = real2float(line[2]) + param['QMIN'] = real2float(line[3]) + param['LCLOSE'] = line[4].upper() + param['BINARY_OUTPUTFILE'] = f.readline().strip() + param['STATUS_FLAG_FOR_OPEN_STATEMENTS'] = f.readline().strip().upper() + except IOError: + print(f"{param_file_name} not found.") + + return param + +def write_swift_param(param, param_file_name): + outfile = open(param_file_name, 'w') + print(param['T0'], param['TSTOP'], param['DT'], file=outfile) + print(param['DTOUT'], param['DTDUMP'], file=outfile) + print(param['L1'], param['L2'], param['L3'], param['L4'], param['L5'], param['L6'], file=outfile) + print(param['RMIN'], param['RMAX'], param['RMAXU'], param['QMIN'], param['LCLOSE'], file=outfile) + print(param['BINARY_OUTPUTFILE'], file=outfile) + print(param['STATUS_FLAG_FOR_OPEN_STATEMENTS'], file=outfile) + outfile.close() + return + +def write_labeled_param(param, param_file_name): + outfile = open(param_file_name, 'w') + for key, val in sorted(param.items()): + print(f"{key:<16} {val}", file=outfile) + outfile.close() + return + +def swifter_stream(f, param): + """ + Reads in a Swifter bin.dat file and returns a single frame of data as a datastream + + Parameters + ---------- + f : file object + param : dict + + Yields + ------- + t : float + Time of this frame + npl : int + Number of massive bodies + plid : int array + IDs of massive bodies + pvec : float array + (npl,N) - vector of N quantities or each particle (6 of XV/EL + Mass, Radius, etc) + plab : string list + Labels for the pvec data + ntp : int + Number of test particles + tpid : int array + Ids of test particles + tvec : float array + (ntp,N) - vector of N quantities for each particle (6 of XV/EL, etc.) + tlab : string list + Labels for the tvec data + """ + while True: # Loop until you read the end of file + try: + # Read single-line header + record = f.read_record(' 0: + Mpl = np.empty(npl) + Rpl = np.empty(npl) + for i in range(npl): + # Read single-line pl frame for + record = f.read_record(' 0: + for i in range(ntp): + record = f.read_record(' 0: + plid = f.read_ints() + p1 = f.read_reals(np.float64) + p2 = f.read_reals(np.float64) + p3 = f.read_reals(np.float64) + p4 = f.read_reals(np.float64) + p5 = f.read_reals(np.float64) + p6 = f.read_reals(np.float64) + Mpl = f.read_reals(np.float64) + Rpl = f.read_reals(np.float64) + if param['ROTATION'] == 'YES': + rot_x = f.read_reals(np.float64) + rot_y = f.read_reals(np.float64) + rot_z = f.read_reals(np.float64) + Ip_1 = f.read_reals(np.float64) + Ip_2 = f.read_reals(np.float64) + Ip_3 = f.read_reals(np.float64) + if ntp[0] > 0: + tpid = f.read_ints() + t1 = f.read_reals(np.float64) + t2 = f.read_reals(np.float64) + t3 = f.read_reals(np.float64) + t4 = f.read_reals(np.float64) + t5 = f.read_reals(np.float64) + t6 = f.read_reals(np.float64) + + plab, tlab = make_swiftest_labels(param) + + if param['OUT_FORM'] == 'XV': + mu = np.empty_like(p1) + mu[0] = Mpl[0] + mu[1:] = Mpl[0] + Mpl[1:] + p7 = [] + p8 = [] + p9 = [] + p10 = [] + p11 = [] + p12 = [] + for i in range(mu.size): + elem = orbel.xv2el(mu[i], p1[i], p2[i], p3[i], p4[i], p5[i], p6[i]) + p7.append(elem[0]) + p8.append(elem[1]) + p9.append(elem[2]) + p10.append(elem[3]) + p11.append(elem[4]) + p12.append(elem[5]) + p7 = np.array(p7) + p8 = np.array(p8) + p9 = np.array(p9) + p10 = np.array(p10) + p11 = np.array(p11) + p12 = np.array(p12) + if ntp[0] > 0: + mu = np.full_like(t1,Mpl[0]) + t7 = [] + t8 = [] + t9 = [] + t10 = [] + t11 = [] + t12 = [] + for i in range(mu.size): + elem = orbel.xv2el(mu[i], t1[i], t2[i], t3[i], t4[i], t5[i], t6[i]) + t7.append(elem[0]) + t8.append(elem[1]) + t9.append(elem[2]) + t10.append(elem[3]) + t11.append(elem[4]) + t12.append(elem[5]) + t7 = np.array(t7) + t8 = np.array(t8) + t9 = np.array(t9) + t10 = np.array(t10) + t11 = np.array(t11) + t12 = np.array(t12) + + if npl > 0: + if param['ROTATION'] == 'YES': + if param['OUT_FORM'] == 'EL': + pvec = np.vstack([p1,p2,p3,p4,p5,p6,Mpl,Rpl,rot_x,rot_y,rot_z,Ip_1,Ip_2,Ip_3]) + else: + pvec = np.vstack([p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, Mpl, Rpl, rot_x, rot_y, rot_z, Ip_1, Ip_2, Ip_3]) + else: + if param['OUT_FORM'] == 'EL': + pvec = np.vstack([p1,p2,p3,p4,p5,p6,Mpl,Rpl]) + else: + pvec = np.vstack([p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, Mpl, Rpl]) + else: + pvec = np.empty((8,0)) + plid = np.empty(0) + if ntp > 0: + if param['OUT_FORM'] == 'EL': + tvec = np.vstack([t1,t2,t3,t4,t5,t6]) + else: + tvec = np.vstack([t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12]) + else: + tvec = np.empty((6,0)) + tpid = np.empty(0) + yield t, npl, plid, pvec.T, plab, \ + ntp, tpid, tvec.T, tlab + + +def swifter2xr(param): + """ + Converts a Swifter binary data file into an xarray DataSet. + + Parameters + ---------- + param : dict + Swifter parameters + + Returns + ------- + xarray dataset + """ + dims = ['time', 'id', 'vec'] + pl = [] + tp = [] + with FortranFile(param['BIN_OUT'], 'r') as f: + for t, npl, plid, pvec, plab, \ + ntp, tpid, tvec, tlab in swifter_stream(f, param): + plframe = np.expand_dims(pvec, axis=0) + tpframe = np.expand_dims(tvec, axis=0) + + # Create xarray DataArrays out of each body type + plxr = xr.DataArray(plframe, dims=dims, coords={'time': t, 'id': plid, 'vec': plab}) + tpxr = xr.DataArray(tpframe, dims=dims, coords={'time': t, 'id': tpid, 'vec': tlab}) + + pl.append(plxr) + tp.append(tpxr) + sys.stdout.write('\r' + f"Reading in time {t[0]:.3e}") + sys.stdout.flush() + + plda = xr.concat(pl, dim='time') + tpda = xr.concat(tp, dim='time') + + plds = plda.to_dataset(dim='vec') + tpds = tpda.to_dataset(dim='vec') + print('\nCreating Dataset') + ds = xr.combine_by_coords([plds, tpds]) + print(f"Successfully converted {ds.sizes['time']} output frames.") + return ds + + +def swiftest2xr(param): + """Reads in the Swiftest BIN_OUT file and converts it to an xarray Dataset""" + dims = ['time','id', 'vec'] + dsframes = [] + + with FortranFile(param['BIN_OUT'], 'r') as f: + for t, npl, plid, pvec, plab, \ + ntp, tpid, tvec, tlab in swiftest_stream(f, param): + plframe = np.expand_dims(pvec, axis=0) + tpframe = np.expand_dims(tvec, axis=0) + bd = [] + + # Create xarray DataArrays out of each body type + if npl[0] > 0 : + plxr = xr.DataArray(plframe, dims=dims, coords={'time': t, 'id': plid, 'vec': plab}) + bd.append(plxr) + if ntp[0] > 0 : + tpxr = xr.DataArray(tpframe, dims=dims, coords={'time': t, 'id': tpid, 'vec': tlab}) + bd.append(tpxr) + bdxr = xr.concat(bd, dim='time') + bdxr = bdxr.to_dataset(dim='vec') + bdxr = bdxr.assign(npl=npl[0]) + bdxr = bdxr.assign(ntp=ntp[0]) + dsframes.append(bdxr) + sys.stdout.write('\r'+f"Reading in time {t[0]:.3e}") + sys.stdout.flush() + print('\nCreating Dataset') + ds = xr.concat(dsframes, dim='time') + if not param['PARTICLE_FILE'] == '': + ds = swiftest_particle_2xr(ds, param) + print(f"Successfully converted {ds.sizes['time']} output frames.") + return ds + +def swiftest_particle_stream(f): + """ + Reads in a Swiftest particle.dat file and returns a single frame of particle data as a datastream + + Parameters + ---------- + f : file object + param : dict + + Yields + ------- + plid : int + ID of massive bodie + origin_type : string + The origin type for the body (Initial conditions, disruption, supercatastrophic, hit and run, etc) + origin_xh : float array + The origin heliocentric position vector + origin_vh : float array + The origin heliocentric velocity vector + """ + while True: # Loop until you read the end of file + try: + # Read multi-line header + plid = f.read_ints() # Try first part of the header + except: + break + origin_rec = f.read_record(np.dtype('a32'), np.dtype((' ") + if intxt.upper() == 'Y': + isSyMBA = True + swifter_param['RHILL_PRESENT'] = 'YES' + else: + isSyMBA = False + swifter_param['RHILL_PRESENT'] = 'NO' + + isDouble = conversion_questions.get('DOUBLE', None) + if not isDouble: + print("Use single precision or double precision for real outputs?") + print(" 1) Single (real*4)") + print("*2) Double (real*8)") + intxt = input("> ") + if intxt == '1': + isDouble = False + else: + isDouble = True + + # Convert the parameter file values + swifter_param['T0'] = swift_param['T0'] + swifter_param['TSTOP'] = swift_param['TSTOP'] + swifter_param['DT'] = swift_param['DT'] + swifter_param['ISTEP_OUT'] = int(swift_param['DTOUT'] / swift_param['DT']) + swifter_param['ISTEP_DUMP'] = int(swift_param['DTDUMP'] / swift_param['DT']) + swifter_param['BIN_OUT'] = swift_param['BINARY_OUTPUTFILE'] + swifter_param['OUT_STAT'] = swift_param['STATUS_FLAG_FOR_OPEN_STATEMENTS'] + + if swift_param['L5'] == "T": + swifter_param['OUT_FORM'] = 'EL' + else: + swifter_param['OUT_FORM'] = 'XV' + + if swift_param['LCLOSE'] == "T": + swifter_param['CHK_CLOSE'] = "YES" + else: + swifter_param['CHK_CLOSE'] = "NO" + + swifter_param['CHK_RMIN'] = swift_param['RMIN'] + swifter_param['CHK_RMAX'] = swift_param['RMAX'] + swifter_param['CHK_QMIN'] = swift_param['QMIN'] + if swift_param['QMIN'] != '-1': + + swifter_param['CHK_QMIN_COORD'] = conversion_questions.get('CHK_QMIN_COORD', None) + if not swifter_param['CHK_QMIN_COORD']: + print("CHK_QMIN_COORD value:") + print("*1) HELIO") + print(" 2) BARY") + intxt = input("> ") + if intxt == '2': + swifter_param['CHK_QMIN_COORD'] = "BARY" + else: + swifter_param['CHK_QMIN_COORD'] = "HELIO" + + swifter_param['CHK_QMIN_RANGE'] = conversion_questions.get('CHK_QMIN_RANGE', None) + if not swifter_param['CHK_QMIN_RANGE']: + alo = input(f"Lower bound on CHK_QMIN_RANGE [{swift_param['RMIN']}]: ") + if alo == '': + alo = swift_param['RMIN'] + ahi = input(f"Upper bound on CHK_QMIN_RANGE: [{swift_param['RMAXU']}]: ") + if ahi == '': + ahi = swift_param['RMAXU'] + swifter_param['CHK_QMIN_RANGE'] = f"{alo} {ahi}" + + + swifter_param['ENC_OUT'] = conversion_questions.get('ENC_OUT', None) + if not swifter_param['ENC_OUT']: + swifter_param['ENC_OUT'] = input("ENC_OUT: Encounter file name: [enc.dat]> ") + if swifter_param['ENC_OUT'] == '': + swifter_param['ENC_OUT'] = "enc.dat" + + intxt = conversion_questions.get('EXTRA_FORCE', None) + if not intxt: + intxt = input("EXTRA_FORCE: Use additional user-specified force routines? (y/N)> ") + if intxt.upper() == 'Y': + swifter_param['EXTRA_FORCE'] = 'YES' + else: + swifter_param['EXTRA_FORCE'] = 'NO' + + intxt = conversion_questions.get('BIG_DISCARD', None) + if not intxt: + intxt = input("BIG_DISCARD: include data for all bodies > MTINY for each discard record? (y/N)> ") + if intxt.upper() == 'Y': + swifter_param['BIG_DISCARD'] = 'YES' + else: + swifter_param['BIG_DISCARD'] = 'NO' + + # Convert the PL file + if plname == '': + plname = input("PL_IN: Name of new planet input file: [pl.swifter.in]> ") + if plname == '': + plname = "pl.swifter.in" + swifter_param['PL_IN'] = plname + try: + plnew = open(swifter_param['PL_IN'], 'w') + except IOError: + print(f"Cannot write to file {swifter_param['PL_IN']}") + return swift_param + + print(f"Converting PL file: {swift_param['PL_IN']} -> {swifter_param['PL_IN']}") + try: + with open(swift_param['PL_IN'], 'r') as plold: + line = plold.readline() + i_list = [i for i in line.split(" ") if i.strip()] + npl = int(i_list[0]) + print(npl, file=plnew) + line = plold.readline() + i_list = [i for i in line.split(" ") if i.strip()] + GMcb = real2float(i_list[0]) + if swift_param['L1'] == "T": + swifter_param['J2'] = real2float(i_list[1]) + swifter_param['J4'] = real2float(i_list[2]) + else: + swifter_param['J2'] = 0.0 + swifter_param['J4'] = 0.0 + print(1, GMcb, file=plnew) + print(0.0, 0.0, 0.0, file=plnew) + print(0.0, 0.0, 0.0, file=plnew) + line = plold.readline() # Ignore the two zero vector lines + line = plold.readline() + for n in range(1, npl): # Loop over planets + line = plold.readline() + i_list = [i for i in line.split(" ") if i.strip()] + GMpl = real2float(i_list[0]) + if isSyMBA: + Rhill = real2float(i_list[1]) + if swift_param['LCLOSE'] == "T": + plrad = real2float(i_list[2]) + else: + if swift_param['LCLOSE'] == "T": + plrad = real2float(i_list[1]) + if swifter_param['RHILL_PRESENT'] == 'YES': + print(n + 1, GMpl, Rhill, file=plnew) + else: + print(n + 1, GMpl, file=plnew) + if swifter_param['CHK_CLOSE'] == 'YES': + print(plrad, file=plnew) + line = plold.readline() + i_list = [i for i in line.split(" ") if i.strip()] + xh = real2float(i_list[0]) + yh = real2float(i_list[1]) + zh = real2float(i_list[2]) + print(xh, yh, zh, file=plnew) + line = plold.readline() + i_list = [i for i in line.split(" ") if i.strip()] + vx = real2float(i_list[0]) + vy = real2float(i_list[1]) + vz = real2float(i_list[2]) + print(vx, vy, vz, file=plnew) + plnew.close() + plold.close() + except IOError: + print(f"Error converting PL file") + + # Convert the TP file + if tpname == '': + tpname = input("TP_IN: Name of new test particle input file: [tp.swifter.in]> ") + if tpname == '': + tpname = "tp.swifter.in" + swifter_param['TP_IN'] = tpname + + try: + tpnew = open(swifter_param['TP_IN'], 'w') + except IOError: + print(f"Cannot write to file {swifter_param['TP_IN']}") + + print(f"Converting TP file: {swift_param['TP_IN']} -> {swifter_param['TP_IN']}") + try: + print(f'Writing out new TP file: {swifter_param["TP_IN"]}') + with open(swift_param['TP_IN'], 'r') as tpold: + line = tpold.readline() + i_list = [i for i in line.split(" ") if i.strip()] + ntp = int(i_list[0]) + print(ntp, file=tpnew) + for n in range(0, ntp): # Loop over test particles + print(npl + n + 1, file=tpnew) + line = tpold.readline() + i_list = [i for i in line.split(" ") if i.strip()] + xh = real2float(i_list[0]) + yh = real2float(i_list[1]) + zh = real2float(i_list[2]) + print(xh, yh, zh, file=tpnew) + line = tpold.readline() + i_list = [i for i in line.split(" ") if i.strip()] + vx = real2float(i_list[0]) + vy = real2float(i_list[1]) + vz = real2float(i_list[2]) + print(vx, vy, vz, file=tpnew) + # Ignore STAT lines + line = tpold.readline() + line = tpold.readline() + except IOError: + print(f"Error converting TP file") + swifter_param['! VERSION'] = "Swifter parameter file converted from Swift" + + return swifter_param + +def swifter2swiftest(swifter_param, plname="", tpname="", cbname="", conversion_questions={}): + swiftest_param = swifter_param.copy() + # Pull additional feature status from the conversion_questions dictionary + featurelist = ("FRAGMENTATION", "ROTATION", "TIDES", "ENERGY", "GR", "YARKOVSKY", "YORP" ) + for key in featurelist: + swiftest_param[key] = conversion_questions.get(key, "NO") + # Convert the PL file + if plname == '': + plname = input("PL_IN: Name of new planet input file: [pl.swiftest.in]> ") + if plname == '': + plname = "pl.swiftest.in" + swiftest_param['PL_IN'] = plname + + try: + plnew = open(swiftest_param['PL_IN'], 'w') + except IOError: + print(f"Cannot write to file {swiftest_param['PL_IN']}") + return swifter_param + + print(f"Converting PL file: {swifter_param['PL_IN']} -> {swiftest_param['PL_IN']}") + try: + with open(swifter_param['PL_IN'], 'r') as plold: + line = plold.readline() + line = line.split("!")[0] # Ignore comments + i_list = [i for i in line.split(" ") if i.strip()] + npl = int(i_list[0]) + print(npl, file=plnew) + for n in range(3): + line = plold.readline() + print(line, file=plnew) + # Needs to be implemented as a question + #print("0.4 0.4 0.4 ! Ip", file=plnew) + #print("0.0 0.0 0.0 ! rot", file=plnew) + for n in range(npl): # Loop over planets + line = plold.readline() + i_list = [i for i in line.split(" ") if i.strip()] + name = int(i_list[0]) + GMpl = real2float(i_list[1]) + print(name, GMpl, file=plnew) + if swifter_param['CHK_CLOSE'] == 'YES': + line = plold.readline() + i_list = [i for i in line.split(" ") if i.strip()] + plrad = real2float(i_list[0]) + print(plrad, file=plnew) + line = plold.readline() + i_list = [i for i in line.split(" ") if i.strip()] + xh = real2float(i_list[0]) + yh = real2float(i_list[1]) + zh = real2float(i_list[2]) + print(xh, yh, zh, file=plnew) + line = plold.readline() + i_list = [i for i in line.split(" ") if i.strip()] + vx = real2float(i_list[0]) + vy = real2float(i_list[1]) + vz = real2float(i_list[2]) + print(vx, vy, vz, file=plnew) + plnew.close() + plold.close() + except IOError: + print(f"Error converting PL file") + + # Convert the TP file + if tpname == '': + tpname = input("TP_IN: Name of new planet input file: [tp.swiftest.in]> ") + if tpname == '': + tpname = "tp.swiftest.in" + swiftest_param['TP_IN'] = tpname + + try: + tpnew = open(swiftest_param['TP_IN'], 'w') + except IOError: + print(f"Cannot write to file {swiftest_param['TP_IN']}") + + print(f"Converting TP file: {swifter_param['TP_IN']} -> {swiftest_param['TP_IN']}") + try: + print(f'Writing out new TP file: {swiftest_param["TP_IN"]}') + with open(swifter_param['TP_IN'], 'r') as tpold: + line = tpold.readline() + line = line.split("!")[0] # Ignore comments + i_list = [i for i in line.split(" ") if i.strip()] + ntp = int(i_list[0]) + print(ntp, file=tpnew) + for n in range(0, ntp): # Loop over test particles + line = tpold.readline() + i_list = [i for i in line.split(" ") if i.strip()] + name = int(i_list[0]) + print(name, file=tpnew) + line = tpold.readline() + i_list = [i for i in line.split(" ") if i.strip()] + xh = real2float(i_list[0]) + yh = real2float(i_list[1]) + zh = real2float(i_list[2]) + print(xh, yh, zh, file=tpnew) + line = tpold.readline() + i_list = [i for i in line.split(" ") if i.strip()] + vx = real2float(i_list[0]) + vy = real2float(i_list[1]) + vz = real2float(i_list[2]) + print(vx, vy, vz, file=tpnew) + + tpold.close() + tpnew.close() + except IOError: + print(f"Error converting TP file") + + unit_system = conversion_questions.get('UNITS', None) + unit_type = 5 + if not unit_system: + print(f"\nCentral body G*M = {GMcb}\n") + print("Select the unit system to use:") + print("1) MSun-AU-year") + print("2) MSun-AU-day") + print("3) SI: kg-m-s") + print("4) CGS: g-cm-s") + print("5) Set units manually") + inval = input("> ") + try: + unit_type = int(inval) + except ValueError: + goodval = False + else: + goodval = (unit_type > 0 and unit_type < 6) + if not goodval: + print(f"{inval} is not a valid menu option") + sys.exit(-1) + if unit_type == 1 or unit_system.upper() == 'MSUN-AU-YEAR': + print("Unit system is MSun-AU-year") + swiftest_param['MU2KG'] = swiftest.MSun + swiftest_param['DU2M'] = swiftest.AU2M + swiftest_param['TU2S'] = swiftest.YR2S + elif unit_type == 2 or unit_system.upper() == 'MSUN-AU-DAY': + print("Unit system is MSun-AU-day") + swiftest_param['MU2KG'] = swiftest.MSun + swiftest_param['DU2M'] = swiftest.AU2M + swiftest_param['TU2S'] = swiftest.JD2S + elif unit_type == 3 or unit_system.upper() == 'SI': + print("Unit system is SI: kg-m-s") + swiftest_param['MU2KG'] = 1.0 + swiftest_param['DU2M'] = 1.0 + swiftest_param['TU2S'] = 1.0 + elif unit_type == 4 or unit_system.upper() == 'CGS': + print("Unit system is CGS: g-cm-s") + swiftest_param['MU2KG'] = 1e-3 + swiftest_param['DU2M'] = 1.0e-2 + swiftest_param['TU2S'] = 1.0 + elif unit_type == 5: + print("User-defined units.") + print("Define each unit (mass, distance, and time) by its corresponding SI value.") + swiftest_param['MU2KG'] = input("Mass value in kilograms: ") + swiftest_param['DU2M'] = input("Distance value in meters: ") + swiftest_param['TU2S'] = input("Time unit in seconds: ") + GU = swiftest.GC / (swiftest_param['DU2M'] ** 3 / (swiftest_param['MU2KG'] * swiftest_param['TU2S'] ** 2)) + print(f"Central body mass: {GMcb / GU} MU ({(GMcb / GU) * swiftest_param['MU2KG']} kg)") + + MTINY = conversion_questions.get('MTINY', None) + if not MTINY: + MTINY = input(f"Value of MTINY if this is a SyMBA simulation (enter nothing if this is not a SyMBA parameter file)> ") + if MTINY != '' and real2float(MTINY.strip()) > 0: + swiftest_param['MTINY'] = real2float(MTINY.strip()) + + # Remove the unneeded parameters + if 'C' in swiftest_param: + swiftest_param['GR'] = 'YES' + swiftest_param.pop('C', None) + swiftest_param.pop('J2', None) + swiftest_param.pop('J4', None) + swiftest_param.pop('RHILL_PRESENT', None) + swiftest_param['! VERSION'] = "Swiftest parameter file converted from Swifter" + return swiftest_param + +def swift2swiftest(swift_param, plname="", tpname="", cbname="", conversion_questions={}): + if plname == '': + plname = input("PL_IN: Name of new planet input file: [pl.swiftest.in]> ") + if plname == '': + plname = "pl.swiftest.in" + pltmp = tempfile.NamedTemporaryFile() + pltmpname = pltmp.name + + if tpname == '': + tpname = input("TP_IN: Name of new planet input file: [tp.swiftest.in]> ") + if tpname == '': + tpname = "tp.swiftest.in" + tptmp = tempfile.NamedTemporaryFile() + tptmpname = tptmp.name + + # Create the CB file + if cbname == '': + cbname = input("CB_IN: Name of new planet input file: [cb.swiftest.in]> ") + if cbname == '': + cbname = "cb.swiftest.in" + swifter_param = swift2swifter(swift_param, pltmpname, tptmpname, conversion_questions) + swiftest_param = swifter2swiftest(swifter_param, plname, tpname, cbname, conversion_questions) + swiftest_param['! VERSION'] = "Swiftest parameter file converted from Swift" + return swiftest_param + \ No newline at end of file diff --git a/python/swiftest/swiftest/simulation_class.py b/python/swiftest/swiftest/simulation_class.py new file mode 100644 index 000000000..94f922dfe --- /dev/null +++ b/python/swiftest/swiftest/simulation_class.py @@ -0,0 +1,148 @@ +from swiftest import io +from swiftest import tool + +class Simulation: + """ + This is a class that define the basic Swift/Swifter/Swiftest simulation object + """ + def __init__(self, codename="Swiftest", param_file=""): + self.ds = None + self.param = { + '! VERSION': f"Swiftest parameter input", + 'T0': "0.0", + 'TSTOP': "0.0", + 'DT': "0.0", + 'PL_IN': "", + 'TP_IN': "", + 'CB_IN': "", + 'IN_TYPE': "REAL8", + 'ISTEP_OUT': "1", + 'ISTEP_DUMP': "1", + 'BIN_OUT': "bin.dat", + 'OUT_TYPE': 'REAL8', + 'OUT_FORM': "XV", + 'OUT_STAT': "REPLACE", + 'J2': "0.0", + 'J4': "0.0", + 'CHK_RMIN': "-1.0", + 'CHK_RMAX': "-1.0", + 'CHK_EJECT': "-1.0", + 'CHK_QMIN': "-1.0", + 'CHK_QMIN_COORD': "HELIO", + 'CHK_QMIN_RANGE': "", + 'ENC_OUT': "", + 'MTINY': "-1.0", + 'MU2KG': "-1.0", + 'TU2S': "-1.0", + 'DU2M': "-1.0", + 'GU': "-1.0", + 'EXTRA_FORCE': "NO", + 'BIG_DISCARD': "NO", + 'CHK_CLOSE': "NO", + 'FRAGMENTATION': "NO", + 'MTINY_SET': "NO", + 'ROTATION': "NO", + 'TIDES': "NO", + 'ENERGY': "NO", + 'GR': "NO", + 'YARKOVSKY': "NO", + 'YORP': "NO", + } + if param_file != "" : + self.read_param(param_file, codename) + return + + def read_param(self, param_file, codename="Swiftest"): + if codename == "Swiftest": + self.param = io.read_swiftest_param(param_file) + self.codename = "Swiftest" + elif codename == "Swifter": + self.param = io.read_swifter_param(param_file) + self.codename = "Swifter" + elif codename == "Swift": + self.param = io.read_swift_param(param_file) + self.codename = "Swift" + else: + print(f'{codename} is not a recognized code name. Valid options are "Swiftest", "Swifter", or "Swift".') + self.codename = "Unknown" + return + + def write_param(self, param_file): + # Check to see if the parameter type matches the output type. If not, we need to convert + codename = self.param['! VERSION'].split()[0] + if codename == "Swifter" or codename == "Swiftest": + io.write_labeled_param(self.param, param_file) + elif codename == "Swift": + io.write_swift_param(self.param, param_file) + else: + print('Cannot process unknown code type. Call the read_param method with a valid code name. Valid options are "Swiftest", "Swifter", or "Swift".') + return + + def convert(self, param_file, newcodename="Swiftest", plname="pl.swiftest.in", tpname="tp.swiftest.in", cbname="cb.swiftest.in", conversion_questions={}): + """ + Converts simulation input files from one code type to another (Swift, Swifter, or Swiftest). Returns the old parameter configuration. + """ + oldparam = self.param + if self.codename == newcodename: + print(f"This parameter configuration is already in {newcodename} format") + return oldparam + if newcodename != "Swift" and newcodename != "Swifter" and newcodename != "Swiftest": + print(f'{newcodename} is an invalid code type. Valid options are "Swiftest", "Swifter", or "Swift".') + return oldparam + goodconversion = True + if self.codename == "Swifter": + if newcodename == "Swiftest": + self.param = io.swifter2swiftest(self.param, plname, tpname, cbname, conversion_questions) + else: + goodconversion = False + elif self.codename == "Swift": + if newcodename == "Swifter": + self.param = io.swift2swifter(self.param, plname, tpname, conversion_questions) + elif newcodename == "Swiftest": + self.param = io.swift2swiftest(self.param, plname, tpname, cbname, conversion_questions) + else: + goodconversion = False + + if goodconversion: + self.write_param(param_file) + else: + print(f"Conversion from {self.codename} to {newcodename} is not supported.") + return oldparam + + def bin2xr(self): + if self.codename == "Swiftest": + self.ds = io.swiftest2xr(self.param) + print('Swiftest simulation data stored as xarray DataSet .ds') + elif self.codename == "Swifter": + self.ds = io.swifter2xr(self.param) + print('Swifter simulation data stored as xarray DataSet .ds') + elif self.codename == "Swift": + print("Reading Swift simulation data is not implemented yet") + else: + print('Cannot process unknown code type. Call the read_param method with a valid code name. Valid options are "Swiftest", "Swifter", or "Swift".') + return + + + def follow(self, codestyle="Swifter"): + if self.ds is None: + self.bin2xr() + if codestyle == "Swift": + try: + with open('follow.in', 'r') as f: + line = f.readline() # Parameter file (ignored because bin2xr already takes care of it + line = f.readline() # PL file (ignored) + line = f.readline() # TP file (ignored) + line = f.readline() # ifol + i_list = [i for i in line.split(" ") if i.strip()] + ifol = int(i_list[0]) + line = f.readline() # nskp + i_list = [i for i in line.split(" ") if i.strip()] + nskp = int(i_list[0]) + except IOError: + print('No follow.in file found') + ifol = None + nskp = None + fol = tool.follow_swift(self.ds, ifol=ifol, nskp=nskp) + + print('follow.out written') + return fol \ No newline at end of file diff --git a/python/swiftest/swiftest/tool.py b/python/swiftest/swiftest/tool.py new file mode 100644 index 000000000..fba725f4e --- /dev/null +++ b/python/swiftest/swiftest/tool.py @@ -0,0 +1,85 @@ +import swiftest +import numpy as np +import os +import glob +from pyslalib import slalib +import xarray as xr +""" +Functions that recreate the Swift/Swifter tool programs +""" + +def sla_dranrm(angle): + func = np.vectorize(slalib.sla_dranrm) + return xr.apply_ufunc(func, angle) + +def follow_swift(ds, ifol=None, nskp=None): + """ + Emulates the Swift version of tool_follow.f + + + Parameters + ---------- + ds : Dataset containing orbital elements + + Returns + ------- + fol : Dataset containing only the followed body with angles converted to degrees + + Generates a file called follow.out containing 10 columns (angles are all in degrees): + 1 2 3 4 5 6 7 8 9 10 + t,a,e,inc,capom,omega,capm,peri,apo,obar + + """ + fol = None + if ifol is None: + intxt = input(' Input the particle number to follow \n') + ifol = int(intxt) + print(f"Following particle {ifol}") + if ifol < 0: # Negative numbers are planets + fol = ds.where(np.invert(np.isnan(ds['Mass'])), drop=True) + fol = fol.where(np.invert(np.isnan(fol['a'])), drop=True) # Remove times where this body doesn't exist (but this also gets rid of the central body) + fol = fol.isel(id = -ifol - 2) # Take 1 off for 0-indexed arrays in Python, and take 1 more off because the central body is gone + elif ifol > 0: # Positive numbers are test particles + fol = ds.where(np.isnan(ds['Mass']), drop=True).drop_vars(['Mass', 'Radius']) + fol = fol.where(np.invert(np.isnan(fol['a'])), drop=True) + fol = fol.isel(id = ifol - 1) # Take 1 off for 0-indexed arrays in Python + + if nskp is None: + intxt = input('Input the print frequency\n') + nskp = int(intxt) + + + dr = 180.0 / np.pi + fol['obar'] = fol['capom'] + fol['omega'] + fol['obar'] = fol['obar'].fillna(0) + fol['obar'] = sla_dranrm(fol['obar']) + fol['obar'] = fol['obar'] * dr + fol['inc'] = fol['inc'] * dr + fol['capom'] = fol['capom'] * dr + fol['omega'] = fol['omega'] * dr + fol['capm'] = fol['capm'] * dr + fol['peri'] = fol['a'] * (1.0 - fol['e']) + fol['apo'] = fol['a'] * (1.0 + fol['e']) + + print('1 2 3 4 5 6 7 8 9 10') + print('t,a,e,inc,capom,omega,capm,peri,apo,obar') + + tslice = slice(None, None, nskp) + try: + with open('follow.out', 'w') as f: + for t in fol.isel(time=tslice).time: + a = fol['a'].sel(time=t).values + e = fol['e'].sel(time=t).values + inc = fol['inc'].sel(time=t).values + capom = fol['capom'].sel(time=t).values + omega = fol['omega'].sel(time=t).values + capm = fol['capm'].sel(time=t).values + peri = fol['peri'].sel(time=t).values + apo = fol['apo'].sel(time=t).values + obar = fol['obar'].sel(time=t).values + print(f"{t.values:15.7e} {a:10.4f} {e:7.5f} {inc:9.4f} {capom:9.4f} {omega:9.4f} {capm:9.4f} {peri:10.4f} {apo:10.4f} {obar:9.4f}", file=f) + + except IOError: + print(f"Error writing to follow.out") + + return fol \ No newline at end of file diff --git a/python/swiftest/tests/bin2xr/swiftest/bin2xr_swiftest.py b/python/swiftest/tests/bin2xr/swiftest/bin2xr_swiftest.py new file mode 100644 index 000000000..4437247be --- /dev/null +++ b/python/swiftest/tests/bin2xr/swiftest/bin2xr_swiftest.py @@ -0,0 +1,5 @@ +import swiftest +import swiftest.io as swio +param_file = "param.swiftest.in" +sim = swiftest.Simulation(source="param.swiftest.in") +ds = swio.swiftest2xr(sim.param) \ No newline at end of file diff --git a/python/swiftest/tests/bin2xr/swiftest/cb.swiftest.in b/python/swiftest/tests/bin2xr/swiftest/cb.swiftest.in new file mode 100644 index 000000000..e50255f4a --- /dev/null +++ b/python/swiftest/tests/bin2xr/swiftest/cb.swiftest.in @@ -0,0 +1,4 @@ +0.000295923385935 +0.00468 +0.0 +0.0 diff --git a/python/swiftest/tests/bin2xr/swiftest/param.swiftest.in b/python/swiftest/tests/bin2xr/swiftest/param.swiftest.in new file mode 100644 index 000000000..6a9e599f9 --- /dev/null +++ b/python/swiftest/tests/bin2xr/swiftest/param.swiftest.in @@ -0,0 +1,31 @@ +! VERSION Swiftest parameter file converted from Swift +BIG_DISCARD NO +BIN_OUT bin.dat +CB_IN cb.swiftest.in +CHK_CLOSE YES +CHK_QMIN 0.00468 +CHK_QMIN_COORD HELIO +CHK_QMIN_RANGE 4.68e-03 100.0 +CHK_RMAX 100.0 +CHK_RMIN 0.00468 +DT 5.0 +DU2M 149597870700.0 +ENC_OUT enc.dat +ENERGY NO +EXTRA_FORCE NO +FRAGMENTATION NO +GR NO +ISTEP_DUMP 7305000 +ISTEP_OUT 7305000 +MU2KG 1.988409870698051e+30 +OUT_FORM EL +OUT_STAT UNKNOWN +PL_IN pl.swiftest.in +ROTATION NO +T0 0.0 +TIDES NO +TP_IN tp.swiftest.in +TSTOP 365250000000.0 +TU2S 86400 +YARKOVSKY NO +YORP NO diff --git a/python/swiftest/tests/bin2xr/swiftest/pl.swiftest.in b/python/swiftest/tests/bin2xr/swiftest/pl.swiftest.in new file mode 100644 index 000000000..b7814ac98 --- /dev/null +++ b/python/swiftest/tests/bin2xr/swiftest/pl.swiftest.in @@ -0,0 +1,29 @@ +7 +2 4.91254745e-11 +1.63083872e-05 +-0.1407280799640445 -0.4439009577663329 -0.02334555971312333 +0.021170988258808896 -0.007097975438870806 -0.002522830951443755 +3 7.24345249e-10 +4.04544528e-05 +-0.7186302169039649 -0.02250380105571625 0.04117184137682461 +0.0005135327579269579 -0.02030614162239802 -0.0003071745100210849 +4 8.99701139e-10 +4.26352325e-05 +-0.1685504489908262 0.9687636586748941 -1.151849464023427e-06 +-0.01723001047964496 -0.003013273823615044 2.412522755326018e-08 +5 9.54953511e-11 +2.27075425e-05 +1.390361066044069 -0.02100972149003466 -0.03461801461346188 +0.0007479271121979245 0.01518629868805657 0.0002997532108600616 +6 2.8238813e-07 +0.000477894503 +4.003460074251473 2.93535365924021 -0.1018232730751003 +-0.004563473375353001 0.006446757832442719 7.545633314092875e-05 +7 8.4549815e-08 +0.000402866697 +6.408554725090048 6.568044145835263 -0.3691278858265656 +-0.004291119710689724 0.003891580681674363 0.0001028767891901977 +8 1.291492e-08 +0.000170851362 +14.43051751807564 -13.73565829091644 -0.238128468762112 +0.002678379897839438 0.002672442537311352 -2.477647055276606e-05 diff --git a/python/swiftest/tests/bin2xr/swiftest/tp.swiftest.in b/python/swiftest/tests/bin2xr/swiftest/tp.swiftest.in new file mode 100644 index 000000000..b3b8f423c --- /dev/null +++ b/python/swiftest/tests/bin2xr/swiftest/tp.swiftest.in @@ -0,0 +1,4 @@ +1 +9 +1.407578089380049 0.5926170247361682 -0.7567948854164774 +-0.004970782813745737 0.01294038841446245 3.261913169537027e-05 diff --git a/python/swiftest/tests/convert_code_type/swift2swifter/param.swift.in b/python/swiftest/tests/convert_code_type/swift2swifter/param.swift.in new file mode 100644 index 000000000..3f9822a58 --- /dev/null +++ b/python/swiftest/tests/convert_code_type/swift2swifter/param.swift.in @@ -0,0 +1,6 @@ +.0d0 365.25d9 5.0d0 +365.25d5 365.25d5 +F T F F T F +4.68d-03 100.0 -1.0 4.68d-03 T +bin.dat +unknown diff --git a/python/swiftest/tests/convert_code_type/swift2swifter/pl.swift.in b/python/swiftest/tests/convert_code_type/swift2swifter/pl.swift.in new file mode 100644 index 000000000..4d479d3cf --- /dev/null +++ b/python/swiftest/tests/convert_code_type/swift2swifter/pl.swift.in @@ -0,0 +1,28 @@ + 8 + 2.9592338592955439E-004 + 0.0000000000000000 0.0000000000000000 0.0000000000000000 + 0.0000000000000000 0.0000000000000000 0.0000000000000000 + 4.9127330156310911E-011 1.6308387199999999E-005 + -0.15273942296363005 -0.44077188683118762 -2.1987973899201478E-002 + 2.0924205227543746E-002 -7.6522013575130771E-003 -2.5455577585009612E-003 + 7.2437260968171072E-010 4.0454452799999999E-005 + -0.68052645343902751 -0.21255610959625498 3.6375571604128076E-002 + 5.7676478402592110E-003 -1.9654618148759011E-002 -6.0150804827979417E-004 + 8.9973512337453730E-010 4.2635232500000000E-005 + 0.21153912017632401 0.96910814953928759 -1.5976841060778844E-006 + -1.6944135164995145E-002 3.6911953785631699E-003 1.4525071481945407E-008 + 9.5498958252779674E-011 2.2707542499999999E-005 + 1.4232971230754801 0.21815483859431103 -3.0416153305576600E-002 + -1.9274688569975952E-003 1.4590108763912674E-002 3.5304139123317309E-004 + 2.8254526327676804E-007 4.7789450300000003E-004 + 4.0036874054921974 2.9350393270474617 -0.10182563723380476 + -4.5629876169643530E-003 6.4471059617920590E-003 7.5448856044019538E-005 + 8.4600347388504292E-008 4.0286669700000002E-004 + 6.4083018390909805 6.5682871940009111 -0.36911425745370574 + -4.2912688970106801E-003 3.8914184987695602E-003 1.0289743699759401E-004 + 1.2920737211033427E-008 1.7085136200000001E-004 + 14.430329793174279 -13.735823636348456 -0.23812543891764848 + 2.6784223946886604E-003 2.6724061291222238E-003 -2.4777620883141212E-005 + 1.5244164811971947E-008 1.6553711599999999E-004 + 16.808300160620913 -24.994308693440338 0.12729909149223279 + 2.5795430409598025E-003 1.7765162604947151E-003 -9.5908529499802122E-005 diff --git a/python/swiftest/tests/convert_code_type/swift2swifter/swift.in b/python/swiftest/tests/convert_code_type/swift2swifter/swift.in new file mode 100644 index 000000000..fd99232cf --- /dev/null +++ b/python/swiftest/tests/convert_code_type/swift2swifter/swift.in @@ -0,0 +1,3 @@ +param.swift.in +pl.swift.in +tp.swift.in diff --git a/python/swiftest/tests/convert_code_type/swift2swifter/swift2swifter.py b/python/swiftest/tests/convert_code_type/swift2swifter/swift2swifter.py new file mode 100644 index 000000000..bd765d90f --- /dev/null +++ b/python/swiftest/tests/convert_code_type/swift2swifter/swift2swifter.py @@ -0,0 +1,14 @@ +import swiftest +""" + Reads in an example parameter file for each of the codes (Swift, Swifter, and Swiftest) and outputs an equivalent + parameter file in another code type. + + Input files are param.swift[er|est].in and output files are param.[src]2[dest].new, where [src] is the original file type + and [dest] is the new one. The user may be prompted to answer questions regarding how to convert between the different + simulation types. + """ +inparam = "param.swift.in" +outparam = "param.swift2swifter.new" +print(f"Reading Swift parameter {inparam} and saving it to {outparam}") +sim = swiftest.Simulation(source=inparam, codename="Swift") +oldparam = sim.convert(outparam, newcodename="Swifter", plname="pl.swift2swifter.in", tpname="tp.swift2swifter.in") \ No newline at end of file diff --git a/python/swiftest/tests/convert_code_type/swift2swifter/tp.swift.in b/python/swiftest/tests/convert_code_type/swift2swifter/tp.swift.in new file mode 100644 index 000000000..c63ce7f13 --- /dev/null +++ b/python/swiftest/tests/convert_code_type/swift2swifter/tp.swift.in @@ -0,0 +1,201 @@ + 50 + 1.75536839836414 -0.397301559901775 -2.886320950191011E-002 + 2.828957660824792E-003 1.250539366801959E-002 -8.833159624221525E-005 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.75462547108338 -0.397439253344038 -5.771762699017597E-002 + 2.826684041441025E-003 1.250497227754510E-002 -1.766362858232247E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.75338751027446 -0.397668695834012 -8.655446554537932E-002 + 2.822895444946565E-003 1.250427010264027E-002 -2.648871776719500E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.75165489340570 -0.397989817412071 -0.115364933939178 + 2.817593026527604E-003 1.250328735740620E-002 -3.530573675304868E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.74942814808290 -0.398402520292259 -0.144140261060723 + 2.810778400843813E-003 1.250202434110241E-002 -4.411200127075503E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.74670795159950 -0.398906678945642 -0.172871691292285 + 2.802453640651961E-003 1.250048143789167E-002 -5.290483179262686E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.74349513437761 -0.399502139462572 -0.201550453497502 + 2.792621287336390E-003 1.249865911879178E-002 -6.168154404172742E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.73979067424302 -0.400188720613739 -0.230167821489439 + 2.781284333388745E-003 1.249655793842830E-002 -7.043946749723006E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.73559569961003 -0.400966213259897 -0.258715078141622 + 2.768446232154610E-003 1.249417853684106E-002 -7.917593441112837E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.73091148830840 -0.401834380569283 -0.287183527684168 + 2.754110894243519E-003 1.249152163881874E-002 -8.788828357128555E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.72026103118157 -0.389355528881347 -2.828594532477477E-002 + 2.886114093303328E-003 1.275805340156797E-002 -9.011625318008804E-005 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.71953296244609 -0.389490468454826 -5.656327447617424E-002 + 2.883794537575375E-003 1.275762349729473E-002 -1.802050560751523E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.71831976085279 -0.389715322095103 -8.482337627316461E-002 + 2.879929396047131E-003 1.275690713560546E-002 -2.702389743052803E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.71662179632064 -0.390030021241745 -0.113057635311967 + 2.874519847244236E-003 1.275590453492696E-002 -3.601905600373064E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.71443958590329 -0.390434470064514 -0.141257455903944 + 2.867567538449044E-003 1.275461600056502E-002 -4.500324282485798E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.71177379334835 -0.390928545545054 -0.169414257543719 + 2.859074584296430E-003 1.275304192444406E-002 -5.397372422888266E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.70862523246946 -0.391512096851912 -0.197519444517652 + 2.849043577517016E-003 1.275118278709834E-002 -6.292776170557357E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.70499486153590 -0.392184946380362 -0.225564465162543 + 2.837477571062932E-003 1.274903915435912E-002 -7.186263077873903E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.70088378639370 -0.392946889173945 -0.253540776694444 + 2.824380088051367E-003 1.274661167919763E-002 -8.077560980102980E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.69629325931601 -0.393797693137531 -0.281439857258866 + 2.809755118102047E-003 1.274390110104623E-002 -8.966398379301735E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.68515366399900 -0.381409497860919 -2.770868114763943E-002 + 2.944472485597326E-003 1.301602639267184E-002 -9.193844020566386E-005 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.68444045380880 -0.381541683565614 -5.540892196217252E-002 + 2.942106027515987E-003 1.301558779556061E-002 -1.838488750704571E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.68325201143113 -0.381761948356195 -8.309228700094988E-002 + 2.938162731265411E-003 1.301485694874873E-002 -2.757033154802284E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.68158869923558 -0.382070225071419 -0.110750336684755 + 2.932643799201507E-003 1.301383407507970E-002 -3.674737585955427E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.67945102372369 -0.382466419836768 -0.138374650747165 + 2.925550911915339E-003 1.301251948603269E-002 -4.591322656575339E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.67683963509720 -0.382950412144466 -0.165956823795153 + 2.916886226800555E-003 1.301091358145700E-002 -5.506509472578220E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.67375533056131 -0.383522054241252 -0.193488435537802 + 2.906652389013839E-003 1.300901685160348E-002 -6.420018645562698E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.67019904882879 -0.384181172146986 -0.220961108835647 + 2.894852513239243E-003 1.300682987374474E-002 -7.331572218908740E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.66617187317737 -0.384927565087993 -0.248366475247266 + 2.881490193832806E-003 1.300435331405534E-002 -8.240892524600587E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.66167503032362 -0.385761005705779 -0.275696186833564 + 2.866569501085982E-003 1.300158792691927E-002 -9.147702574897361E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.65004629681643 -0.373463466840492 -2.713141697050409E-002 + 3.004107385165185E-003 1.327964217801076E-002 -9.380048499464011E-005 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.64934794517152 -0.373592898676403 -5.425456944817078E-002 + 3.001692998807830E-003 1.327919469791802E-002 -1.875723974515014E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.64818426200946 -0.373808574617286 -8.136119772873515E-002 + 2.997669838310936E-003 1.327844904914197E-002 -2.812871813881668E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.64655560215051 -0.374110428901093 -0.108443038057544 + 2.992039130381927E-003 1.327740545903941E-002 -3.749162668189549E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.64446246154409 -0.374498369609023 -0.135491845590387 + 2.984802589649166E-003 1.327606424539795E-002 -4.684311491365882E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.64190547684605 -0.374972278743879 -0.162499390046587 + 2.975962417200357E-003 1.327442581616511E-002 -5.618033740837786E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.63888542865316 -0.375532011630592 -0.189457426557952 + 2.965521311764990E-003 1.327249067152087E-002 -6.550044369703316E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.63540323612168 -0.376177397913609 -0.216357752508752 + 2.953482451109342E-003 1.327025940042943E-002 -7.480059791839970E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.63145995996104 -0.376908241002040 -0.243192173800089 + 2.939849502386553E-003 1.326773268255752E-002 -8.407796715574675E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.62705680133123 -0.377724318274027 -0.269952516408261 + 2.924626618324377E-003 1.326491128756776E-002 -9.332972543286958E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.61493892963385 -0.365517435820064 -2.655415279336874E-002 + 3.065098326561108E-003 1.354925233969722E-002 -9.570487094018532E-005 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.61425543653423 -0.365644113787191 -5.310021693416905E-002 + 3.062634922083575E-003 1.354879577463227E-002 -1.913805892481565E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.61311651258780 -0.365855200878378 -7.963010845652042E-002 + 3.058530081302113E-003 1.354803498730923E-002 -2.869980191831766E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.61152250506545 -0.366150632730767 -0.106135739430332 + 3.052785055829394E-003 1.354697020970083E-002 -3.825280107169432E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.60947389936449 -0.366530319381278 -0.132609040433608 + 3.045401595105050E-003 1.354560176604655E-002 -4.779414805269034E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.60697131859490 -0.366994145343291 -0.159041956298021 + 3.036381944904408E-003 1.354393007257628E-002 -5.732093966627254E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.60401552674501 -0.367541969019932 -0.185426417578102 + 3.025728858747958E-003 1.354195563962491E-002 -6.683026757172563E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.60060742341456 -0.368173623680233 -0.211754396181856 + 3.013445578918633E-003 1.353967906811411E-002 -7.631923833270372E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.59674804674471 -0.368888916916088 -0.238017872352911 + 2.999535847022010E-003 1.353710105150953E-002 -8.578496151713587E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.59243857233884 -0.369687630842276 -0.264208845982959 + 2.984003900096668E-003 1.353422237509990E-002 -9.522455377438729E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 diff --git a/python/swiftest/tests/convert_code_type/swift2swiftest/param.swift.in b/python/swiftest/tests/convert_code_type/swift2swiftest/param.swift.in new file mode 100644 index 000000000..3f9822a58 --- /dev/null +++ b/python/swiftest/tests/convert_code_type/swift2swiftest/param.swift.in @@ -0,0 +1,6 @@ +.0d0 365.25d9 5.0d0 +365.25d5 365.25d5 +F T F F T F +4.68d-03 100.0 -1.0 4.68d-03 T +bin.dat +unknown diff --git a/python/swiftest/tests/convert_code_type/swift2swiftest/pl.swift.in b/python/swiftest/tests/convert_code_type/swift2swiftest/pl.swift.in new file mode 100644 index 000000000..4d479d3cf --- /dev/null +++ b/python/swiftest/tests/convert_code_type/swift2swiftest/pl.swift.in @@ -0,0 +1,28 @@ + 8 + 2.9592338592955439E-004 + 0.0000000000000000 0.0000000000000000 0.0000000000000000 + 0.0000000000000000 0.0000000000000000 0.0000000000000000 + 4.9127330156310911E-011 1.6308387199999999E-005 + -0.15273942296363005 -0.44077188683118762 -2.1987973899201478E-002 + 2.0924205227543746E-002 -7.6522013575130771E-003 -2.5455577585009612E-003 + 7.2437260968171072E-010 4.0454452799999999E-005 + -0.68052645343902751 -0.21255610959625498 3.6375571604128076E-002 + 5.7676478402592110E-003 -1.9654618148759011E-002 -6.0150804827979417E-004 + 8.9973512337453730E-010 4.2635232500000000E-005 + 0.21153912017632401 0.96910814953928759 -1.5976841060778844E-006 + -1.6944135164995145E-002 3.6911953785631699E-003 1.4525071481945407E-008 + 9.5498958252779674E-011 2.2707542499999999E-005 + 1.4232971230754801 0.21815483859431103 -3.0416153305576600E-002 + -1.9274688569975952E-003 1.4590108763912674E-002 3.5304139123317309E-004 + 2.8254526327676804E-007 4.7789450300000003E-004 + 4.0036874054921974 2.9350393270474617 -0.10182563723380476 + -4.5629876169643530E-003 6.4471059617920590E-003 7.5448856044019538E-005 + 8.4600347388504292E-008 4.0286669700000002E-004 + 6.4083018390909805 6.5682871940009111 -0.36911425745370574 + -4.2912688970106801E-003 3.8914184987695602E-003 1.0289743699759401E-004 + 1.2920737211033427E-008 1.7085136200000001E-004 + 14.430329793174279 -13.735823636348456 -0.23812543891764848 + 2.6784223946886604E-003 2.6724061291222238E-003 -2.4777620883141212E-005 + 1.5244164811971947E-008 1.6553711599999999E-004 + 16.808300160620913 -24.994308693440338 0.12729909149223279 + 2.5795430409598025E-003 1.7765162604947151E-003 -9.5908529499802122E-005 diff --git a/python/swiftest/tests/convert_code_type/swift2swiftest/swift.in b/python/swiftest/tests/convert_code_type/swift2swiftest/swift.in new file mode 100644 index 000000000..fd99232cf --- /dev/null +++ b/python/swiftest/tests/convert_code_type/swift2swiftest/swift.in @@ -0,0 +1,3 @@ +param.swift.in +pl.swift.in +tp.swift.in diff --git a/python/swiftest/tests/convert_code_type/swift2swiftest/swift2swiftest.py b/python/swiftest/tests/convert_code_type/swift2swiftest/swift2swiftest.py new file mode 100644 index 000000000..6234dc61a --- /dev/null +++ b/python/swiftest/tests/convert_code_type/swift2swiftest/swift2swiftest.py @@ -0,0 +1,14 @@ +import swiftest +""" + Reads in an example parameter file for each of the codes (Swift, Swifter, and Swiftest) and outputs an equivalent + parameter file in another code type. + + Input files are param.swift[er|est].in and output files are param.[src]2[dest].new, where [src] is the original file type + and [dest] is the new one. The user may be prompted to answer questions regarding how to convert between the different + simulation types. + """ +inparam = "param.swift.in" +outparam = "param.swift2swiftest.new" +print(f"Reading Swift parameter {inparam} and saving it to {outparam}") +sim = swiftest.Simulation(source=inparam, codename="Swift") +oldparam = sim.convert(outparam, newcodename="Swiftest", plname="pl.swift2swiftest.in", tpname="tp.swift2swiftest.in", cbname="cb.swift2swiftest.in") \ No newline at end of file diff --git a/python/swiftest/tests/convert_code_type/swift2swiftest/tp.swift.in b/python/swiftest/tests/convert_code_type/swift2swiftest/tp.swift.in new file mode 100644 index 000000000..c63ce7f13 --- /dev/null +++ b/python/swiftest/tests/convert_code_type/swift2swiftest/tp.swift.in @@ -0,0 +1,201 @@ + 50 + 1.75536839836414 -0.397301559901775 -2.886320950191011E-002 + 2.828957660824792E-003 1.250539366801959E-002 -8.833159624221525E-005 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.75462547108338 -0.397439253344038 -5.771762699017597E-002 + 2.826684041441025E-003 1.250497227754510E-002 -1.766362858232247E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.75338751027446 -0.397668695834012 -8.655446554537932E-002 + 2.822895444946565E-003 1.250427010264027E-002 -2.648871776719500E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.75165489340570 -0.397989817412071 -0.115364933939178 + 2.817593026527604E-003 1.250328735740620E-002 -3.530573675304868E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.74942814808290 -0.398402520292259 -0.144140261060723 + 2.810778400843813E-003 1.250202434110241E-002 -4.411200127075503E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.74670795159950 -0.398906678945642 -0.172871691292285 + 2.802453640651961E-003 1.250048143789167E-002 -5.290483179262686E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.74349513437761 -0.399502139462572 -0.201550453497502 + 2.792621287336390E-003 1.249865911879178E-002 -6.168154404172742E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.73979067424302 -0.400188720613739 -0.230167821489439 + 2.781284333388745E-003 1.249655793842830E-002 -7.043946749723006E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.73559569961003 -0.400966213259897 -0.258715078141622 + 2.768446232154610E-003 1.249417853684106E-002 -7.917593441112837E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.73091148830840 -0.401834380569283 -0.287183527684168 + 2.754110894243519E-003 1.249152163881874E-002 -8.788828357128555E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.72026103118157 -0.389355528881347 -2.828594532477477E-002 + 2.886114093303328E-003 1.275805340156797E-002 -9.011625318008804E-005 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.71953296244609 -0.389490468454826 -5.656327447617424E-002 + 2.883794537575375E-003 1.275762349729473E-002 -1.802050560751523E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.71831976085279 -0.389715322095103 -8.482337627316461E-002 + 2.879929396047131E-003 1.275690713560546E-002 -2.702389743052803E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.71662179632064 -0.390030021241745 -0.113057635311967 + 2.874519847244236E-003 1.275590453492696E-002 -3.601905600373064E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.71443958590329 -0.390434470064514 -0.141257455903944 + 2.867567538449044E-003 1.275461600056502E-002 -4.500324282485798E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.71177379334835 -0.390928545545054 -0.169414257543719 + 2.859074584296430E-003 1.275304192444406E-002 -5.397372422888266E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.70862523246946 -0.391512096851912 -0.197519444517652 + 2.849043577517016E-003 1.275118278709834E-002 -6.292776170557357E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.70499486153590 -0.392184946380362 -0.225564465162543 + 2.837477571062932E-003 1.274903915435912E-002 -7.186263077873903E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.70088378639370 -0.392946889173945 -0.253540776694444 + 2.824380088051367E-003 1.274661167919763E-002 -8.077560980102980E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.69629325931601 -0.393797693137531 -0.281439857258866 + 2.809755118102047E-003 1.274390110104623E-002 -8.966398379301735E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.68515366399900 -0.381409497860919 -2.770868114763943E-002 + 2.944472485597326E-003 1.301602639267184E-002 -9.193844020566386E-005 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.68444045380880 -0.381541683565614 -5.540892196217252E-002 + 2.942106027515987E-003 1.301558779556061E-002 -1.838488750704571E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.68325201143113 -0.381761948356195 -8.309228700094988E-002 + 2.938162731265411E-003 1.301485694874873E-002 -2.757033154802284E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.68158869923558 -0.382070225071419 -0.110750336684755 + 2.932643799201507E-003 1.301383407507970E-002 -3.674737585955427E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.67945102372369 -0.382466419836768 -0.138374650747165 + 2.925550911915339E-003 1.301251948603269E-002 -4.591322656575339E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.67683963509720 -0.382950412144466 -0.165956823795153 + 2.916886226800555E-003 1.301091358145700E-002 -5.506509472578220E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.67375533056131 -0.383522054241252 -0.193488435537802 + 2.906652389013839E-003 1.300901685160348E-002 -6.420018645562698E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.67019904882879 -0.384181172146986 -0.220961108835647 + 2.894852513239243E-003 1.300682987374474E-002 -7.331572218908740E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.66617187317737 -0.384927565087993 -0.248366475247266 + 2.881490193832806E-003 1.300435331405534E-002 -8.240892524600587E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.66167503032362 -0.385761005705779 -0.275696186833564 + 2.866569501085982E-003 1.300158792691927E-002 -9.147702574897361E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.65004629681643 -0.373463466840492 -2.713141697050409E-002 + 3.004107385165185E-003 1.327964217801076E-002 -9.380048499464011E-005 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.64934794517152 -0.373592898676403 -5.425456944817078E-002 + 3.001692998807830E-003 1.327919469791802E-002 -1.875723974515014E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.64818426200946 -0.373808574617286 -8.136119772873515E-002 + 2.997669838310936E-003 1.327844904914197E-002 -2.812871813881668E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.64655560215051 -0.374110428901093 -0.108443038057544 + 2.992039130381927E-003 1.327740545903941E-002 -3.749162668189549E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.64446246154409 -0.374498369609023 -0.135491845590387 + 2.984802589649166E-003 1.327606424539795E-002 -4.684311491365882E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.64190547684605 -0.374972278743879 -0.162499390046587 + 2.975962417200357E-003 1.327442581616511E-002 -5.618033740837786E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.63888542865316 -0.375532011630592 -0.189457426557952 + 2.965521311764990E-003 1.327249067152087E-002 -6.550044369703316E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.63540323612168 -0.376177397913609 -0.216357752508752 + 2.953482451109342E-003 1.327025940042943E-002 -7.480059791839970E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.63145995996104 -0.376908241002040 -0.243192173800089 + 2.939849502386553E-003 1.326773268255752E-002 -8.407796715574675E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.62705680133123 -0.377724318274027 -0.269952516408261 + 2.924626618324377E-003 1.326491128756776E-002 -9.332972543286958E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.61493892963385 -0.365517435820064 -2.655415279336874E-002 + 3.065098326561108E-003 1.354925233969722E-002 -9.570487094018532E-005 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.61425543653423 -0.365644113787191 -5.310021693416905E-002 + 3.062634922083575E-003 1.354879577463227E-002 -1.913805892481565E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.61311651258780 -0.365855200878378 -7.963010845652042E-002 + 3.058530081302113E-003 1.354803498730923E-002 -2.869980191831766E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.61152250506545 -0.366150632730767 -0.106135739430332 + 3.052785055829394E-003 1.354697020970083E-002 -3.825280107169432E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.60947389936449 -0.366530319381278 -0.132609040433608 + 3.045401595105050E-003 1.354560176604655E-002 -4.779414805269034E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.60697131859490 -0.366994145343291 -0.159041956298021 + 3.036381944904408E-003 1.354393007257628E-002 -5.732093966627254E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.60401552674501 -0.367541969019932 -0.185426417578102 + 3.025728858747958E-003 1.354195563962491E-002 -6.683026757172563E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.60060742341456 -0.368173623680233 -0.211754396181856 + 3.013445578918633E-003 1.353967906811411E-002 -7.631923833270372E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.59674804674471 -0.368888916916088 -0.238017872352911 + 2.999535847022010E-003 1.353710105150953E-002 -8.578496151713587E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.59243857233884 -0.369687630842276 -0.264208845982959 + 2.984003900096668E-003 1.353422237509990E-002 -9.522455377438729E-004 + 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 diff --git a/python/swiftest/tests/convert_code_type/swifter2swiftest/param.swifter.in b/python/swiftest/tests/convert_code_type/swifter2swiftest/param.swifter.in new file mode 100644 index 000000000..5d250c0b1 --- /dev/null +++ b/python/swiftest/tests/convert_code_type/swifter2swiftest/param.swifter.in @@ -0,0 +1,26 @@ +! Swifter input file generated using init_cond.py +T0 0 +TSTOP 80.0 +DT 1.0 +PL_IN pl.swifter.in +TP_IN tp.swifter.in +IN_TYPE ASCII +ISTEP_OUT 1 +ISTEP_DUMP 1 +BIN_OUT bin.dat +OUT_TYPE REAL8 +OUT_FORM XV +OUT_STAT NEW +J2 4.7535806948127355e-12 +J4 -2.2473967953572827e-18 +CHK_CLOSE yes +CHK_RMIN 0.004650467260962157 +CHK_RMAX 1000.0 +CHK_EJECT 1000.0 +CHK_QMIN 0.004650467260962157 +CHK_QMIN_COORD HELIO +CHK_QMIN_RANGE 0.004650467260962157 1000.0 +ENC_OUT enc.dat +EXTRA_FORCE no +BIG_DISCARD no +RHILL_PRESENT yes diff --git a/python/swiftest/tests/convert_code_type/swifter2swiftest/pl.swifter.in b/python/swiftest/tests/convert_code_type/swifter2swiftest/pl.swifter.in new file mode 100644 index 000000000..b98db89c9 --- /dev/null +++ b/python/swiftest/tests/convert_code_type/swifter2swiftest/pl.swifter.in @@ -0,0 +1,40 @@ +10 +1 0.00029591220819207775568 +0.0 0.0 0.0 +0.0 0.0 0.0 +2 4.9125474498983625e-11 0.0014751258227142052 ! mercury +1.6306381826061646e-05 +0.008059842448018334 -0.4616051037329109 -0.03846017738329229 +0.02248719132054853 0.001934639213990692 -0.001904656977422976 +3 7.243452483873647e-10 0.006759134232034942 ! venus +4.0453784346544176e-05 +-0.5115875215389065 0.5030818749037324 0.03642547299277956 +-0.01425515725454357 -0.01452868630179309 0.0006232072038298823 +4 8.997011382166019e-10 0.010044625087011913 ! earthmoon +4.25875607065041e-05 +-0.1090020607540907 -1.009893805009766 4.823302918632528e-05 +0.01682491922568941 -0.001910549762056979 3.992660742687128e-08 +5 9.549535102761465e-11 0.007246789790242477 ! mars +2.2657408050928896e-05 +-1.342897929331636 0.9778655112682739 0.05343398538723887 +-0.007712315645393206 -0.01011917844182223 -2.287744801261131e-05 +6 2.8253459086313547e-07 0.3552720805286442 ! jupiter +0.0004673261703049093 +3.923184193414315 -3.168419770483168 -0.0746147877972047 +0.004655552638985802 0.006232623300954468 -0.0001300429201057457 +7 8.459715183006416e-08 0.4376460836930155 ! saturn +0.00038925687730393614 +6.185794462795267 -7.804174837804826 -0.110498432926239 +0.004066833203985018 0.003458637040736611 -0.0002219310939327014 +8 1.2920249163736674e-08 0.46946272948265794 ! uranus +0.00016953449859497232 +14.9290976575471 12.92949673572929 -0.1454099139559955 +-0.002599557960646664 0.002795888198858545 4.391864857782088e-05 +9 1.5243589003230834e-08 0.7811947848333599 ! neptune +0.00016458790412449367 +29.54416169025338 -4.716921603714237 -0.5838030174427992 +0.0004792636209523189 0.00312573757291745 -7.53264045199501e-05 +10 2.1919422829042796e-12 0.05379680851617536 ! plutocharon +7.943294877391593e-06 +14.54448346259197 -31.05223519593471 -0.8828000265625595 +0.002923077617691739 0.0006625916902153526 -0.0009142553677224461 diff --git a/python/swiftest/tests/convert_code_type/swifter2swiftest/swifter2swiftest.py b/python/swiftest/tests/convert_code_type/swifter2swiftest/swifter2swiftest.py new file mode 100644 index 000000000..4cc62bf8f --- /dev/null +++ b/python/swiftest/tests/convert_code_type/swifter2swiftest/swifter2swiftest.py @@ -0,0 +1,14 @@ +import swiftest +""" + Reads in an example parameter file for each of the codes (Swift, Swifter, and Swiftest) and outputs an equivalent + parameter file in another code type. + + Input files are param.swift[er|est].in and output files are param.[src]2[dest].new, where [src] is the original file type + and [dest] is the new one. The user may be prompted to answer questions regarding how to convert between the different + simulation types. + """ +inparam = "param.swifter.in" +outparam = "param.swifter2swiftest.new" +print(f"Reading Swift parameter {inparam} and saving it to {outparam}") +sim = swiftest.Simulation(source=inparam, codename="Swifter") +oldparam = sim.convert(outparam, newcodename="Swiftest", plname="pl.swifter2swiftest.in", tpname="tp.swifter2swiftest.in", cbname="cb.swifter2swiftest.in") \ No newline at end of file diff --git a/python/swiftest/tests/convert_code_type/swifter2swiftest/tp.swifter.in b/python/swiftest/tests/convert_code_type/swifter2swiftest/tp.swifter.in new file mode 100644 index 000000000..9c026369e --- /dev/null +++ b/python/swiftest/tests/convert_code_type/swifter2swiftest/tp.swifter.in @@ -0,0 +1,4 @@ +1 +100 +1.01 0.0 0.0 +0.0 6.252003053624663 0.0 diff --git a/python/swiftest/tests/param_readers/param.swift.in b/python/swiftest/tests/param_readers/param.swift.in new file mode 100644 index 000000000..3f9822a58 --- /dev/null +++ b/python/swiftest/tests/param_readers/param.swift.in @@ -0,0 +1,6 @@ +.0d0 365.25d9 5.0d0 +365.25d5 365.25d5 +F T F F T F +4.68d-03 100.0 -1.0 4.68d-03 T +bin.dat +unknown diff --git a/python/swiftest/tests/param_readers/param.swifter.in b/python/swiftest/tests/param_readers/param.swifter.in new file mode 100644 index 000000000..5834d2dcc --- /dev/null +++ b/python/swiftest/tests/param_readers/param.swifter.in @@ -0,0 +1,26 @@ +! Swifter input file generated using init_cond.py +T0 0 +TSTOP 1.0 +DT 0.0006844626967830253 +PL_IN pl.swifter.in +TP_IN tp.swifter.in +IN_TYPE ASCII +ISTEP_OUT 1 +ISTEP_DUMP 1 +BIN_OUT bin.swifter.dat +OUT_TYPE REAL8 +OUT_FORM EL +OUT_STAT NEW +J2 4.7535806948127355e-12 +J4 -2.2473967953572827e-18 +CHK_CLOSE yes +CHK_RMIN 0.004650467260962157 +CHK_RMAX 1000.0 +CHK_EJECT 1000.0 +CHK_QMIN 0.004650467260962157 +CHK_QMIN_COORD HELIO +CHK_QMIN_RANGE 0.004650467260962157 1000.0 +ENC_OUT enc.swifter.dat +EXTRA_FORCE no +BIG_DISCARD no +RHILL_PRESENT yes diff --git a/python/swiftest/tests/param_readers/param.swiftest.in b/python/swiftest/tests/param_readers/param.swiftest.in new file mode 100644 index 000000000..6e623a5dd --- /dev/null +++ b/python/swiftest/tests/param_readers/param.swiftest.in @@ -0,0 +1,29 @@ +! Swiftest input file generated using init_cond.py +T0 0 +TSTOP 1.0 +DT 0.0006844626967830253 +CB_IN cb.swiftest.in +PL_IN pl.swiftest.in +TP_IN tp.swiftest.in +IN_TYPE REAL8 +ISTEP_OUT 1 +ISTEP_DUMP 1 +BIN_OUT bin.swiftest.dat +OUT_TYPE REAL8 +OUT_FORM EL +OUT_STAT REPLACE +CHK_CLOSE yes +CHK_RMIN 0.004650467260962157 +CHK_RMAX 1000.0 +CHK_EJECT 1000.0 +CHK_QMIN 0.004650467260962157 +CHK_QMIN_COORD HELIO +CHK_QMIN_RANGE 0.004650467260962157 1000.0 +ENC_OUT enc.swiftest.dat +EXTRA_FORCE no +BIG_DISCARD no +ROTATION no +GR no +MU2KG 1.988409870698051e+30 +DU2M 149597870700.0 +TU2S 31557600.0 diff --git a/python/swiftest/tests/param_readers/param_readers.py b/python/swiftest/tests/param_readers/param_readers.py new file mode 100644 index 000000000..d940eecc3 --- /dev/null +++ b/python/swiftest/tests/param_readers/param_readers.py @@ -0,0 +1,24 @@ +import swiftest +""" + Reads in an example parameter file for each of the codes (Swift, Swifter, and Swiftest) and outputs a copy using the + internal parsing system. Input files are param.swift[er|est].in and output files are param.swift[er|est].new. + The contents of the parameter files should be the same, though the new version may be formatted differently and also + contain explicit values for default parameters. + """ +inparam = "param.swift.in" +outparam = "param.swift.new" +print(f"Reading Swift parameter {inparam} and saving it to {outparam}") +sim = swiftest.Simulation(source=inparam, codename="Swift") +sim.write_param(outparam) + +inparam = "param.swifter.in" +outparam = "param.swifter.new" +print(f"Reading Swifter parameter {inparam} and saving it to {outparam}") +sim = swiftest.Simulation(source=inparam, codename="Swifter") +sim.write_param(outparam) + +inparam = "param.swiftest.in" +outparam = "param.swiftest.new" +print(f"Reading Swifter parameter {inparam} and saving it to {outparam}") +sim = swiftest.Simulation(source=inparam) # The default value of codename is "Swiftest" +sim.write_param(outparam) \ No newline at end of file diff --git a/python/swiftestio/.ipynb_checkpoints/mars-scatter-checkpoint.ipynb b/python/swiftestio/.ipynb_checkpoints/mars-scatter-checkpoint.ipynb deleted file mode 100644 index 421bdbc35..000000000 --- a/python/swiftestio/.ipynb_checkpoints/mars-scatter-checkpoint.ipynb +++ /dev/null @@ -1,1600 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 155, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import swiftestio as swio\n", - "import matplotlib.pyplot as plt\n", - "import timeit" - ] - }, - { - "cell_type": "code", - "execution_count": 352, - "metadata": {}, - "outputs": [], - "source": [ - "workingdir = '/Users/daminton/work/Projects/Swiftest/Pouplin-Mars-Disk/high_high_1500_1/'" - ] - }, - { - "cell_type": "code", - "execution_count": 353, - "metadata": {}, - "outputs": [], - "source": [ - "def readswifter(inparfile):\n", - " inparfile = workingdir + inparfile\n", - " param = {}\n", - " param = swio.read_swifter_param(inparfile)\n", - " param['BIN_OUT'] = workingdir + param['BIN_OUT']\n", - " ds = swio.swifter2xr(param)\n", - " return ds" - ] - }, - { - "cell_type": "code", - "execution_count": 354, - "metadata": {}, - "outputs": [], - "source": [ - "def readswiftest(config_file_name):\n", - " config_file_name = workingdir + config_file_name\n", - " config = {}\n", - " config = swio.read_swiftest_config(config_file_name)\n", - " config['BIN_OUT'] = workingdir + config['BIN_OUT']\n", - " ds = swio.swiftest2xr(config)\n", - " ds['Mass'] = ds['Mass'] * config['GU']\n", - " return ds" - ] - }, - { - "cell_type": "code", - "execution_count": 355, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Reading Swiftest file /Users/daminton/work/Projects/Swiftest/Pouplin-Mars-Disk/high_high_1500_1/param.in\n" - ] - }, - { - "ename": "ValueError", - "evalue": "Size obtained (4) is not a multiple of the dtypes given (8).", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdisk\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mreadswiftest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'param.in'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36mreadswiftest\u001b[0;34m(config_file_name)\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mconfig\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mswio\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread_swiftest_config\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mconfig_file_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mconfig\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'BIN_OUT'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mworkingdir\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mconfig\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'BIN_OUT'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0mds\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mswio\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mswiftest2xr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mconfig\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 7\u001b[0m \u001b[0mds\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'Mass'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mds\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'Mass'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mconfig\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'GU'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mds\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/git/swiftest/python/swiftestio/swiftestio.py\u001b[0m in \u001b[0;36mswiftest2xr\u001b[0;34m(config)\u001b[0m\n", - "\u001b[0;32m~/git/swiftest/python/swiftestio/swiftestio.py\u001b[0m in \u001b[0;36mswiftest_stream\u001b[0;34m(f, config)\u001b[0m\n\u001b[1;32m 356\u001b[0m \u001b[0mtlab\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'omega'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 357\u001b[0m \u001b[0mtlab\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'capm'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 358\u001b[0;31m \u001b[0mplab\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtlab\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 359\u001b[0m \u001b[0mplab\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Mass'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 360\u001b[0m \u001b[0mplab\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Radius'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/Library/Python/3.7/lib/python/site-packages/scipy/io/_fortran.py\u001b[0m in \u001b[0;36mread_reals\u001b[0;34m(self, dtype)\u001b[0m\n\u001b[1;32m 300\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 301\u001b[0m \"\"\"\n\u001b[0;32m--> 302\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread_record\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 303\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 304\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mclose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/Library/Python/3.7/lib/python/site-packages/scipy/io/_fortran.py\u001b[0m in \u001b[0;36mread_record\u001b[0;34m(self, *dtypes, **kwargs)\u001b[0m\n\u001b[1;32m 225\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mremainder\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 226\u001b[0m raise ValueError('Size obtained ({0}) is not a multiple of the '\n\u001b[0;32m--> 227\u001b[0;31m 'dtypes given ({1}).'.format(first_size, block_size))\n\u001b[0m\u001b[1;32m 228\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 229\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdtypes\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0;36m1\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mfirst_size\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mblock_size\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mValueError\u001b[0m: Size obtained (4) is not a multiple of the dtypes given (8)." - ] - } - ], - "source": [ - "disk = readswiftest('param.in')" - ] - }, - { - "cell_type": "code", - "execution_count": 349, - "metadata": {}, - "outputs": [], - "source": [ - "diffxv = np.abs(swifterxv - swiftestxv)" - ] - }, - { - "cell_type": "code", - "execution_count": 350, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Text(0, 0.5, 'Swifter - Swiftest: $\\\\Delta$')" - ] - }, - "execution_count": 350, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "fig = plt.figure(1, figsize=(10,6))\n", - "ax = fig.add_subplot(111)\n", - "pnum = 103\n", - "diffxv['px'].sel(id=[pnum]).plot.line(x='time',add_legend=False,label='$x$')\n", - "diffxv['py'].sel(id=[pnum]).plot.line(x='time',add_legend=False,label='$y$')\n", - "diffxv['pz'].sel(id=[pnum]).plot.line(x='time',add_legend=False,label='$z$')\n", - "diffxv['vx'].sel(id=[pnum]).plot.line(x='time',add_legend=False,label='$v_x$')\n", - "diffxv['vy'].sel(id=[pnum]).plot.line(x='time',add_legend=False,label='$v_y$')\n", - "diffxv['vz'].sel(id=[pnum]).plot.line(x='time',add_legend=False,label='$v_z$')\n", - "ax.legend()\n", - "plt.rcParams.update({'font.size': 18})\n", - "#ax.set_yscale('log')\n", - "#plt.ylim((-1e-6,1e-6))\n", - "ax.set_ylabel(\"Swifter - Swiftest: $\\Delta$\")" - ] - }, - { - "cell_type": "code", - "execution_count": 351, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "Show/Hide data repr\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "Show/Hide attributes\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
xarray.DataArray
'vx'
  • time: 101
  • id: 1
  • 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
    array([[0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.],\n",
    -       "       [0.]])
    • id
      (id)
      int64
      103
      array([103])
    • time
      (time)
      float64
      0.0 1.0 2.0 3.0 ... 98.0 99.0 100.0
      array([  0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.,\n",
      -       "        12.,  13.,  14.,  15.,  16.,  17.,  18.,  19.,  20.,  21.,  22.,  23.,\n",
      -       "        24.,  25.,  26.,  27.,  28.,  29.,  30.,  31.,  32.,  33.,  34.,  35.,\n",
      -       "        36.,  37.,  38.,  39.,  40.,  41.,  42.,  43.,  44.,  45.,  46.,  47.,\n",
      -       "        48.,  49.,  50.,  51.,  52.,  53.,  54.,  55.,  56.,  57.,  58.,  59.,\n",
      -       "        60.,  61.,  62.,  63.,  64.,  65.,  66.,  67.,  68.,  69.,  70.,  71.,\n",
      -       "        72.,  73.,  74.,  75.,  76.,  77.,  78.,  79.,  80.,  81.,  82.,  83.,\n",
      -       "        84.,  85.,  86.,  87.,  88.,  89.,  90.,  91.,  92.,  93.,  94.,  95.,\n",
      -       "        96.,  97.,  98.,  99., 100.])
" - ], - "text/plain": [ - "\n", - "array([[0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.],\n", - " [0.]])\n", - "Coordinates:\n", - " * id (id) int64 103\n", - " * time (time) float64 0.0 1.0 2.0 3.0 4.0 ... 96.0 97.0 98.0 99.0 100.0" - ] - }, - "execution_count": 351, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "diffxv['vx'].sel(id=[pnum])" - ] - }, - { - "cell_type": "code", - "execution_count": 276, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Reading Swifter file /Users/daminton/work/Projects/Swiftest/swiftest_whm_test/solar_system_plus_3tp/param.el.in\n" - ] - } - ], - "source": [ - "swifterel = readswifter('param.el.in')" - ] - }, - { - "cell_type": "code", - "execution_count": 282, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Reading Swiftest file /Users/daminton/work/Projects/Swiftest/swiftest_whm_test/solar_system_plus_3tp/config.el.in\n" - ] - } - ], - "source": [ - "swiftestel = readswiftest('config.el.in')" - ] - }, - { - "cell_type": "code", - "execution_count": 283, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "Show/Hide data repr\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "Show/Hide attributes\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
xarray.DataArray
'e'
  • time: 5
  • id: 1
  • 0.2056 0.2056 0.2057 0.2056 0.2056
    array([[0.20563512],\n",
    -       "       [0.2056476 ],\n",
    -       "       [0.20565571],\n",
    -       "       [0.20564613],\n",
    -       "       [0.20563473]])
    • id
      (id)
      int64
      2
      array([2])
    • time
      (time)
      float64
      0.0 100.0 200.0 300.0 400.0
      array([  0., 100., 200., 300., 400.])
" - ], - "text/plain": [ - "\n", - "array([[0.20563512],\n", - " [0.2056476 ],\n", - " [0.20565571],\n", - " [0.20564613],\n", - " [0.20563473]])\n", - "Coordinates:\n", - " * id (id) int64 2\n", - " * time (time) float64 0.0 100.0 200.0 300.0 400.0" - ] - }, - "execution_count": 283, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "swiftestel['e'].sel(id=[2])" - ] - }, - { - "cell_type": "code", - "execution_count": 284, - "metadata": {}, - "outputs": [], - "source": [ - "diffel = swifterel - swiftestel" - ] - }, - { - "cell_type": "code", - "execution_count": 285, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "Show/Hide data repr\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "Show/Hide attributes\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
xarray.DataArray
'e'
  • time: 5
  • id: 1
  • 0.0 3.434e-08 -4.801e-07 -1.546e-07 -2.212e-07
    array([[ 0.00000000e+00],\n",
    -       "       [ 3.43417110e-08],\n",
    -       "       [-4.80051157e-07],\n",
    -       "       [-1.54617024e-07],\n",
    -       "       [-2.21233928e-07]])
    • id
      (id)
      int64
      2
      array([2])
    • time
      (time)
      float64
      0.0 100.0 200.0 300.0 400.0
      array([  0., 100., 200., 300., 400.])
" - ], - "text/plain": [ - "\n", - "array([[ 0.00000000e+00],\n", - " [ 3.43417110e-08],\n", - " [-4.80051157e-07],\n", - " [-1.54617024e-07],\n", - " [-2.21233928e-07]])\n", - "Coordinates:\n", - " * id (id) int64 2\n", - " * time (time) float64 0.0 100.0 200.0 300.0 400.0" - ] - }, - "execution_count": 285, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "diffel['e'].sel(id=[2])" - ] - }, - { - "cell_type": "code", - "execution_count": 286, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Text(0, 0.5, 'Swifter - Swiftest: $\\\\Delta$')" - ] - }, - "execution_count": 286, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "fig = plt.figure(1, figsize=(10,6))\n", - "ax = fig.add_subplot(111)\n", - "pnum = 102\n", - "diffel['a'].sel(id=[pnum]).plot.line(x='time',add_legend=False,label='$a$')\n", - "diffel['e'].sel(id=[pnum]).plot.line(x='time',add_legend=False,label='$e$')\n", - "diffel['inc'].sel(id=[pnum]).plot.line(x='time',add_legend=False,label='$i$')\n", - "diffel['capom'].sel(id=[pnum]).plot.line(x='time',add_legend=False,label='$\\Omega$')\n", - "diffel['omega'].sel(id=[pnum]).plot.line(x='time',add_legend=False,label='$\\omega$')\n", - "diffel['capm'].sel(id=[pnum]).plot.line(x='time',add_legend=False,label='$M$')\n", - "ax.legend()\n", - "plt.rcParams.update({'font.size': 18})\n", - "#plt.ylim((-1e-15,1e-15))\n", - "ax.set_ylabel(\"Swifter - Swiftest: $\\Delta$\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/python/swiftestio/.ipynb_checkpoints/testreader-checkpoint.ipynb b/python/swiftestio/.ipynb_checkpoints/testreader-checkpoint.ipynb deleted file mode 100644 index 2fd64429b..000000000 --- a/python/swiftestio/.ipynb_checkpoints/testreader-checkpoint.ipynb +++ /dev/null @@ -1,6 +0,0 @@ -{ - "cells": [], - "metadata": {}, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/python/swiftestio/README.md b/python/swiftestio/README.md deleted file mode 100644 index e3c0a1ae3..000000000 --- a/python/swiftestio/README.md +++ /dev/null @@ -1 +0,0 @@ -swiftestio diff --git a/python/swiftestio/__init__.py b/python/swiftestio/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/python/swiftestio/swiftestio.py b/python/swiftestio/swiftestio.py deleted file mode 100644 index f56c41546..000000000 --- a/python/swiftestio/swiftestio.py +++ /dev/null @@ -1,837 +0,0 @@ -import numpy as np -import pandas as pd -from scipy.io import FortranFile -import xarray as xr -from astroquery.jplhorizons import Horizons -import astropy.constants as const -import datetime -import sys -from swiftestpy import orbel - -# Constants in SI units -AU2M = np.longdouble(const.au.value) -GMSunSI = np.longdouble(const.GM_sun.value) -RSun = np.longdouble(const.R_sun.value) -GC = np.longdouble(const.G.value) -JD2S = 86400 -year = np.longdouble(365.25 * JD2S) -einsteinC = np.longdouble(299792458.0) -# Solar oblatenes values: From Mecheri et al. (2004), using Corbard (b) 2002 values (Table II) -J2Sun = np.longdouble(2.198e-7) -J4Sun = np.longdouble(-4.805e-9) - -def read_swifter_param(inparfile): - """ - Reads in a Swifter param.in file and saves it as a dictionary - - Parameters - ---------- - inparfile : string - File name of the input parameter file - - Returns - ------- - param - A dictionary containing the entries in the user parameter file - """ - param = { - 'INPARFILE' : inparfile, - 'NPLMAX' : -1, - 'NTPMAX' : -1, - 'T0' : 0.0, - 'TSTOP' : 0.0, - 'DT' : 0.0, - 'PL_IN' : "", - 'TP_IN' : "", - 'IN_TYPE' : "ASCII", - 'ISTEP_OUT' : -1, - 'BIN_OUT' : "", - 'OUT_TYPE' : 'REAL8', - 'OUT_FORM' : "XV", - 'OUT_STAT' : "NEW", - 'ISTEP_DUMP' : -1, - 'J2' : 0.0, - 'J4' : 0.0, - 'CHK_CLOSE' : 'NO', - 'CHK_RMIN' : -1.0, - 'CHK_RMAX' : -1.0, - 'CHK_EJECT' : -1.0, - 'CHK_QMIN' : -1.0, - 'CHK_QMIN_COORD' : "HELIO", - 'CHK_QMIN_RANGE' : "", - 'QMIN_ALO' : -1.0, - 'QMIN_AHI' : -1.0, - 'ENC_OUT' : "", - 'EXTRA_FORCE' : 'NO', - 'BIG_DISCARD' : 'NO', - 'RHILL_PRESENT' : 'NO', - 'GR' : 'NO', - 'C2' : -1.0, - } - - # Read param.in file - print(f'Reading Swifter file {inparfile}') - f = open(inparfile, 'r') - swifterlines = f.readlines() - f.close() - for line in swifterlines: - fields = line.split() - if len(fields) > 0: - for key in param: - if (key == fields[0].upper()): param[key] = fields[1] - #Special case of CHK_QMIN_RANGE requires a second input - if (param['CHK_QMIN_RANGE'] == fields[0].upper()): - param['QMIN_ALO'] = fields[1] - param['QMIN_AHI'] = fields[2] - - param['NPLMAX'] = int(param['NPLMAX']) - param['NTPMAX'] = int(param['NTPMAX']) - param['ISTEP_OUT'] = int(param['ISTEP_OUT']) - param['ISTEP_DUMP'] = int(param['ISTEP_DUMP']) - param['T0'] = float(param['T0']) - param['TSTOP'] = float(param['TSTOP']) - param['DT'] = float(param['DT']) - param['J2'] = float(param['J2']) - param['J4'] = float(param['J4']) - param['CHK_RMIN'] = float(param['CHK_RMIN']) - param['CHK_RMAX'] = float(param['CHK_RMAX']) - param['CHK_EJECT'] = float(param['CHK_EJECT']) - param['CHK_QMIN'] = float(param['CHK_QMIN']) - param['QMIN_ALO'] = float(param['QMIN_ALO']) - param['QMIN_AHI'] = float(param['QMIN_AHI']) - param['EXTRA_FORCE'] = param['EXTRA_FORCE'].upper() - param['BIG_DISCARD'] = param['BIG_DISCARD'].upper() - param['CHK_CLOSE'] = param['CHK_CLOSE'].upper() - param['RHILL_PRESENT'] = param['RHILL_PRESENT'].upper() - - return param - -def read_swiftest_config(config_file_name): - """ - Reads in a Swiftest config.in file and saves it as a dictionary - - Parameters - ---------- - config_file_name : string - File name of the input parameter file - - Returns - ------- - config : dict - A dictionary containing the entries in the user parameter file - """ - config = { - 'CONFIG_FILE_NAME' : config_file_name, - 'NPLMAX' : -1, - 'NTPMAX' : -1, - 'T0' : 0.0, - 'TSTOP' : 0.0, - 'DT' : 0.0, - 'PL_IN' : "", - 'TP_IN' : "", - 'IN_TYPE' : "ASCII", - 'ISTEP_OUT' : -1, - 'BIN_OUT' : "", - 'PARTICLE_FILE' : "", - 'OUT_TYPE' : 'REAL8', - 'OUT_FORM' : "XV", - 'OUT_STAT' : "NEW", - 'ISTEP_DUMP' : -1, - 'J2' : 0.0, - 'J4' : 0.0, - 'CHK_RMIN' : -1.0, - 'CHK_RMAX' : -1.0, - 'CHK_EJECT' : -1.0, - 'CHK_QMIN' : -1.0, - 'CHK_QMIN_COORD' : "HELIO", - 'CHK_QMIN_RANGE' : "", - 'QMIN_ALO' : -1.0, - 'QMIN_AHI' : -1.0, - 'ENC_OUT' : "", - 'MTINY' : -1.0, - 'MU2KG' : -1.0, - 'TU2S' : -1.0, - 'DU2M' : -1.0, - 'GU' : -1.0, - 'INV_C2' : -1.0, - 'EXTRA_FORCE' : 'NO', - 'BIG_DISCARD' : 'NO', - 'CHK_CLOSE' : 'NO', - 'FRAGMENTATION' : 'NO', - 'MTINY_SET' : 'NO', - 'ROTATION' : 'NO', - 'TIDES' : 'NO', - 'ENERGY' : 'NO', - 'GR' : 'NO', - 'YARKOVSKY' : 'NO', - 'YORP' : 'NO', - 'EUCL_THRESHOLD' : 1000000, - 'SKIP' : 0, - } - - # Read config.in file - print(f'Reading Swiftest file {config_file_name}' ) - f = open(config_file_name, 'r') - swiftestlines = f.readlines() - f.close() - for line in swiftestlines: - fields = line.split() - if len(fields) > 0: - for key in config: - if (key == fields[0].upper()): config[key] = fields[1] - #Special case of CHK_QMIN_RANGE requires a second input - if (config['CHK_QMIN_RANGE'] == fields[0].upper()): - config['QMIN_ALO'] = fields[1] - config['QMIN_AHI'] = fields[2] - - config['NPLMAX'] = int(config['NPLMAX']) - config['NTPMAX'] = int(config['NTPMAX']) - config['ISTEP_OUT'] = int(config['ISTEP_OUT']) - config['ISTEP_DUMP'] = int(config['ISTEP_DUMP']) - config['EUCL_THRESHOLD'] = int(config['EUCL_THRESHOLD']) - config['T0'] = float(config['T0']) - config['TSTOP'] = float(config['TSTOP']) - config['DT'] = float(config['DT']) - config['J2'] = float(config['J2']) - config['J4'] = float(config['J4']) - config['CHK_RMIN'] = float(config['CHK_RMIN']) - config['CHK_RMAX'] = float(config['CHK_RMAX']) - config['CHK_EJECT'] = float(config['CHK_EJECT']) - config['CHK_QMIN'] = float(config['CHK_QMIN']) - config['QMIN_ALO'] = float(config['QMIN_ALO']) - config['QMIN_AHI'] = float(config['QMIN_AHI']) - config['MTINY'] = float(config['MTINY']) - config['DU2M'] = float(config['DU2M']) - config['MU2KG'] = float(config['MU2KG']) - config['TU2S'] = float(config['TU2S']) - config['EXTRA_FORCE'] = config['EXTRA_FORCE'].upper() - config['BIG_DISCARD'] = config['BIG_DISCARD'].upper() - config['CHK_CLOSE'] = config['CHK_CLOSE'].upper() - config['FRAGMENTATION'] = config['FRAGMENTATION'].upper() - config['ROTATION'] = config['ROTATION'].upper() - - config['GU'] = GC / (config['DU2M']**3 / (config['MU2KG'] * config['TU2S']**2)) - return config - -def swifter_stream(f, param): - """ - Reads in a Swifter bin.dat file and returns a single frame of data as a datastream - - Parameters - ---------- - f : file object - param : dict - - Yields - ------- - t : float - Time of this frame - npl : int - Number of massive bodies - plid : int array - IDs of massive bodies - pvec : float array - (npl,N) - vector of N quantities or each particle (6 of XV/EL + mass, radius, etc) - plab : string list - Labels for the pvec data - ntp : int - Number of test particles - tpid : int array - Ids of test particles - tvec : float array - (ntp,N) - vector of N quantities for each particle (6 of XV/EL, etc.) - tlab : string list - Labels for the tvec data - """ - while True: # Loop until you read the end of file - try: - # Read single-line header - record = f.read_record(' 0: - Mpl = np.empty(npl) - Rpl = np.empty(npl) - for i in range(npl): - #Read single-line pl frame for - record = f.read_record(' 0: - for i in range(ntp): - record = f.read_record(' 0: - plid = f.read_ints() - p1 = f.read_reals(np.float64) - p2 = f.read_reals(np.float64) - p3 = f.read_reals(np.float64) - p4 = f.read_reals(np.float64) - p5 = f.read_reals(np.float64) - p6 = f.read_reals(np.float64) - Mpl = f.read_reals(np.float64) - Rpl = f.read_reals(np.float64) - if config['ROTATION'] == 'YES': - rot_x = f.read_reals(np.float64) - rot_y = f.read_reals(np.float64) - rot_z = f.read_reals(np.float64) - Ip_1 = f.read_reals(np.float64) - Ip_2 = f.read_reals(np.float64) - Ip_3 = f.read_reals(np.float64) - if ntp[0] > 0: - tpid = f.read_ints() - t1 = f.read_reals(np.float64) - t2 = f.read_reals(np.float64) - t3 = f.read_reals(np.float64) - t4 = f.read_reals(np.float64) - t5 = f.read_reals(np.float64) - t6 = f.read_reals(np.float64) - - plab, tlab = make_swiftest_labels(config) - - if config['OUT_FORM'] == 'XV': - mu = np.empty_like(p1) - mu[0] = Mpl[0] - mu[1:] = Mpl[0] + Mpl[1:] - p7 = [] - p8 = [] - p9 = [] - p10 = [] - p11 = [] - p12 = [] - for i in range(mu.size): - elem = orbel.xv2el(mu[i], p1[i], p2[i], p3[i], p4[i], p5[i], p6[i]) - p7.append(elem[0]) - p8.append(elem[1]) - p9.append(elem[2]) - p10.append(elem[3]) - p11.append(elem[4]) - p12.append(elem[5]) - p7 = np.array(p7) - p8 = np.array(p8) - p9 = np.array(p9) - p10 = np.array(p10) - p11 = np.array(p11) - p12 = np.array(p12) - if ntp[0] > 0: - mu = np.full_like(t1,Mpl[0]) - t7 = [] - t8 = [] - t9 = [] - t10 = [] - t11 = [] - t12 = [] - for i in range(mu.size): - elem = orbel.xv2el(mu[i], t1[i], t2[i], t3[i], t4[i], t5[i], t6[i]) - t7.append(elem[0]) - t8.append(elem[1]) - t9.append(elem[2]) - t10.append(elem[3]) - t11.append(elem[4]) - t12.append(elem[5]) - t7 = np.array(t7) - t8 = np.array(t8) - t9 = np.array(t9) - t10 = np.array(t10) - t11 = np.array(t11) - t12 = np.array(t12) - - if npl > 0: - if config['ROTATION'] == 'YES': - if config['OUT_FORM'] == 'EL': - pvec = np.vstack([p1,p2,p3,p4,p5,p6,Mpl,Rpl,rot_x,rot_y,rot_z,Ip_1,Ip_2,Ip_3]) - else: - pvec = np.vstack([p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, Mpl, Rpl, rot_x, rot_y, rot_z, Ip_1, Ip_2, Ip_3]) - else: - if config['OUT_FORM'] == 'EL': - pvec = np.vstack([p1,p2,p3,p4,p5,p6,Mpl,Rpl]) - else: - pvec = np.vstack([p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, Mpl, Rpl]) - else: - pvec = np.empty((8,0)) - plid = np.empty(0) - if ntp > 0: - if config['OUT_FORM'] == 'EL': - tvec = np.vstack([t1,t2,t3,t4,t5,t6]) - else: - tvec = np.vstack([t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12]) - else: - tvec = np.empty((6,0)) - tpid = np.empty(0) - yield t, npl, plid, pvec.T, plab, \ - ntp, tpid, tvec.T, tlab - -def swifter2xr(param): - dims = ['time','id', 'vec'] - pl = [] - tp = [] - nplarr = [] - ntparr = [] - with FortranFile(param['BIN_OUT'], 'r') as f: - for t, npl, plid, pvec, plab, \ - ntp, tpid, tvec, tlab in swifter_stream(f, param): - - #Prepare frames by adding an extra axis for the time coordinate - plframe = np.expand_dims(pvec, axis=0) - tpframe = np.expand_dims(tvec, axis=0) - - #Create xarray DataArrays out of each body type - plxr = xr.DataArray(plframe, dims = dims, coords = {'time' : t, 'id' : plid, 'vec' : plab}) - tpxr = xr.DataArray(tpframe, dims = dims, coords = {'time' : t, 'id' : tpid, 'vec' : tlab}) - plda = xr.concat(pl, dim='time') - tpda = xr.concat(tp, dim='time') - plds = plda.to_dataset(dim='vec') - tpds = tpda.to_dataset(dim='vec') - dsi = xr.combine_by_coords([plds, tpds]) - #nplarr.append(npl) - #ntparr.append(ntp) - - pl.append(plxr) - tp.append(tpxr) - - ds = xr.combine_by_coords([plds, tpds]) - - return ds - -def swiftest2xr(config): - """Reads in the Swiftest BIN_OUT file and converts it to an xarray Dataset""" - dims = ['time','id', 'vec'] - dsframes = [] - - with FortranFile(config['BIN_OUT'], 'r') as f: - for t, npl, plid, pvec, plab, \ - ntp, tpid, tvec, tlab in swiftest_stream(f, config): - plframe = np.expand_dims(pvec, axis=0) - tpframe = np.expand_dims(tvec, axis=0) - bd = [] - - # Create xarray DataArrays out of each body type - if npl[0] > 0 : - plxr = xr.DataArray(plframe, dims=dims, coords={'time': t, 'id': plid, 'vec': plab}) - bd.append(plxr) - if ntp[0] > 0 : - tpxr = xr.DataArray(tpframe, dims=dims, coords={'time': t, 'id': tpid, 'vec': tlab}) - bd.append(tpxr) - bdxr = xr.concat(bd, dim='time') - bdxr = bdxr.to_dataset(dim='vec') - bdxr = bdxr.assign(npl=npl[0]) - bdxr = bdxr.assign(ntp=ntp[0]) - dsframes.append(bdxr) - sys.stdout.write('\r'+f"Reading in time {t[0]:.3e}") - sys.stdout.flush() - print('\nCreating Dataset') - ds = xr.concat(dsframes, dim='time') - if not config['PARTICLE_FILE'] == '': - ds = swiftest_particle_2xr(ds, config) - print(f"Successfully converted {ds.sizes['time']} output frames.") - return ds - -def swiftest_particle_stream(f): - """ - Reads in a Swiftest particle.dat file and returns a single frame of particle data as a datastream - - Parameters - ---------- - f : file object - config : dict - - Yields - ------- - plid : int - ID of massive bodie - origin_type : string - The origin type for the body (Initial conditions, disruption, supercatastrophic, hit and run, etc) - origin_xh : float array - The origin heliocentric position vector - origin_vh : float array - The origin heliocentric velocity vector - """ - while True: # Loop until you read the end of file - try: - # Read multi-line header - plid = f.read_ints() # Try first part of the header - except: - break - origin_rec = f.read_record(np.dtype('a32'), np.dtype((' 0:\n", - " plxr = xr.DataArray(plframe, dims = dims, coords = {'time' : t, 'id' : plid, 'vec' : plab})\n", - " bd.append(plxr)\n", - " if ntp[0] > 0:\n", - " tpxr = xr.DataArray(tpframe, dims = dims, coords = {'time' : t, 'id' : tpid, 'vec' : tlab})\n", - " bd.append(tpxr)\n", - " bdxr = xr.concat(bd, dim='time')\n", - " #bdxr = bdxr.assign_coords({'npl' : npl[0], 'ntp' : ntp[0]})\n", - " bdxr = bdxr.to_dataset(dim = 'vec')\n", - " bdxr = bdxr.assign(npl=npl[0])\n", - " bdxr = bdxr.assign(ntp=ntp[0])\n", - " bdxr = bdxr.chunk()\n", - " dsframes.append(bdxr)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "ds = xr.concat(dsframes, dim='time')" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "workingdir = \"/Volumes/Minton Data Archive/work archive/Projects/Swiftest/Pouplin-Mars-Disk/high_high_1500_1/savestate2/\"\n", - "filehead = workingdir + 'bin'\n", - "ds = xr.open_mfdataset(f'{filehead}*.nc', combine='by_coords',concat_dim='time',parallel=False)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAZ4AAAEWCAYAAABWn/G6AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjAsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+17YcXAAAgAElEQVR4nO3de3xdVZ338c8vJ9cmbZKm96YlLS1QWmihpVQEBsHhNiiI6OCgFGXgQdFBnRkHhmcGLyMvGWceHbxhFRQcEREGQQShIIKjtlBoKS2ld3qjN5omaZPmcs75PX/sFTwtSXrS7HPSlO/79Tqv7LP22mutDaf5Zq+zzj7m7oiIiORLQX8PQERE3lkUPCIiklcKHhERySsFj4iI5JWCR0RE8krBIyIieaXgETlEZrbczM7qZt9ZZrY5z0MSGRAUPCKHyN2nuvvv8tmnmc0zs5Vmljazq7rY/zkz22ZmTWZ2l5mVZOyrM7NnzKzFzF4zs/f24tivmNkrZpY0sy/m8hzlyKfgERlYXgY+Bbx04A4zOw+4ETgHOAqYCHwpo8rPgMVADXAz8ICZDc/y2DXAF4Bfx3s68k6k4BE5RGb2eudVg5mVmdmPzWy3mb0KnJKLPt39O+7+NNDaxe65wJ3uvtzddwNfAa4K4zsGOBm4xd33ufuDwCvABw92bOj3bnd/HNiTi/OSdxYFj0g8bgGODo/ziH6Rd8vMlppZQzeP7x7iGKYSXRF1ehkYaWY1Yd86d99zwP6pWRwrEqvC/h6AyBHiw8Cn3L0eqDez24F/7a6yu5+YgzFUAI0Zzzu3B3exr3P/2CyO3RXvMOWdTlc8IvEYA2zKeL6hH8awFxiS8bxze08X+zr3d14B9XSsSKwUPCLx2AqMy3g+vqfKYSn23m4edxziGJYD0zOeTwe2u/uusG+imQ0+YP/yLI4ViZWCRyQe9wM3mVm1mdUCn+mpcliKXdHN47rujjOzYjMrBQwoMrNSM+v8d3wPcLWZHW9mVcD/BX4c+lsFLAFuCcd8ADgRePBgx4Z+i0K/BUBhaCPRu/9EIhEFj0g8vkQ0vbYeeBL4SY76eRLYB5wGzAvbZwK4+2+AfweeATaG8dyScezlwCxgN/A14DJ335nlsT8IfX2EaCn2PuBjuThBOfKZvghORETySVc8IiKSVwoeERHJKwWPiIjklYJHRETySncuOIhhw4Z5XV1dfw9DRGRAefHFF9909+Fd7VPwHERdXR2LFi3q72GIiAwoZtbt3Ts01SYiInml4BERkbxS8IiISF4peEREJK8UPCIiklcKHhERySsFj4iI5JWCR0RE3uau/13Pr5duzUnbCh4REXmbH//xdea/ui0nbSt4RETkbfa0djC4tCgnbSt4RERkP+7OntYkg0tzc1c1BY+IiOxnX0eKZNp1xSMiIvnR0NIBQGWZgkdERPJga+M+AEZXleakfQWPiIjsZ1N9FDy1VWU5aV/BIyIi+1m2pZGSwgImDCvPSfsKHhER2c/SzY0cP2YIhYncREROg8fMbjCzZWa23Mw+G8q+YmZLzWyJmT1pZmNCuZnZ7Wa2Juw/OaOduWa2OjzmZpTPNLNXwjG3m5mF8qFmNj/Un29m1QfrQ0REYHdzOy9u3M2ciTU56yNnwWNm04BrgNnAdOAiM5sEfN3dT3T3GcCjwL+GQy4AJofHtcD3QjtDgVuAU0Nbt3QGSahzTcZx54fyG4Gn3X0y8HR43m0fIiISefClzaTSzl+dMDpnfeTyimcKsNDdW9w9CTwLXOruTRl1ygEP2xcD93hkAVBlZqOB84D57l7v7ruB+cD5Yd8Qd1/g7g7cA1yS0dbdYfvuA8q76kNE5B1vd3M7dzy7llMnDGXa2Mqc9ZObj6VGlgFfNbMaYB9wIbAIwMy+ClwJNALvCfXHApsyjt8cynoq39xFOcBId++8u902YORB+tjvTnhmdi3RFRHjx4/P9nxFRA5ZWzLFw0veYMa4Ko4ZOTjr49qTadbs2MvqHXvY3dxOU2uSN/e2Ud/czkUnjuH8aaOyaqelPcnf3beYhpYObnnf1EM9jazkLHjcfYWZ3QY8CTQDS4BU2HczcLOZ3QR8mmgqLVfjcDPzg9fc75h5wDyAWbNm9epYEZFD8Z9PrmLec+tIFBh/M3s8cybWMKg4QWHCSBQYzW0pdre009DSTn1zB2807HsrcDpS+/+aGlxaSGlRgkeXbuW8qSP55wuncFTN21eouTtrd+7lmdd28qM/rGdrUyu3ffBEjh8zJKfnmssrHtz9TuBOADO7lf2vUAB+CjxGFDxbgHEZ+2pD2RbgrAPKfxfKa7uoD7DdzEa7+9YwlbYjlHfXh4hIv9nR1Mrdf3yd9xw7nFGVZfzs+Y38ZMGGbusXJYzRlWXUDSvnzGOGc/yYIRw3ajDDKkoYXFpIUaKAZCrND36/nm8+tYonlm9n2tghDKsoob65nZ172tjblqQtmaY9mQZgdt1Qvnn5ScyeMDTn55vT4DGzEe6+w8zGA5cCc8xssruvDlUuBl4L248Anzaz+4gWEjSG4HgCuDVjQcG5wE3uXm9mTWY2B1hINHX3rYy25gJfCz8f7qmPHJ2+iEhWvvfsWpJp55b3TaVuWDk3XXgcWxtaaWlPkkw7yZRTXpKgelAx1eXFlBcnCIt4u1WYKOCTZx3NJSeN4X9e2sIf177Jrr3tVJcXc8zIwVSUFFJSWMDRwyuYPWEodTn6zE6XY8tx+w+G93g6gOvdvcHM7jSzY4E0sAG4LtR9jOh9oDVAC/BxgBAwXwFeCPW+7O71YftTwI+BMuDx8IAocO43s6tDHx/uqQ8Rkf6yo6mVexdu5IMnj33rl/+Q0iKGjIrnPmmjK8u4/j2TuP49k2JpLw4WLQiT7syaNcsXLVrU38MQkSPU39//Mg8v2cJv//4sxtcM6u/hxMbMXnT3WV3t050LRET6yXOrdvLgS5v5P38x8YgKnYNR8IiI9INN9S189udLOGZkBZ85e3J/Dyevcv0ej4iIZGhpT/Lcqp185dEVdKTSfO+jMyktSvT3sPJKwSMi0gs79rSybEsjy7Y08ebeNlo7UrR2pNnXkaItmabAIJV2WtpTtCVTJFNOKu2k3GnaF324E6CuZhA/u2YORw+v6Oczyj8Fj4gMKO7O9qY22pIpIFo2XFRgFCUKKExEP4sSBSQKjPZkmt0t7eza2059czt72zoAoz2VZkdTK7ua2ylKFOAewiHtJMPPkqICZtRWkSgwXt3axLItjbyypZHtTVFwmEXf0FlamKCsOEFJYQElRQncHTOjvDhBZVkRhQXRB0ATBcag4gTjqgcxfVwVcybWUFz4zny3Q8EjIoe9zrBZsG4Xt/3mNbY2th70GDM42KLdwgIjmXYKjLfCobAgCq197SnaU+m32jp6eAWnHT2MaWMrOWFsJcePGUJFiX6FHgr9VxORw86+9hTPrd7JK5ujq4xXtjRS39wOwJTRQ/jUWUczqDj69ZVMp+lIOclU9LMjnaYj6STTaQoLChhaUUxNefSoKI2OKU4UMHxwCZVl0WdluvowZlsyxatvNGFmTB5RQblCJjb6LykiObWvPcX8FdtZsbWJNTv2kkylmTxyMDPGVTFjXBWjK0sxM9yd5W808dDiLfxi0SaaWpMkCqJf+uccN4JpYyuZPKKCUyfWkCjo+VP7cSgpTHDS+OqDV5ReU/CISE5sa2zlnj+9zr3Pb6ShpYOihFFXU06iwPjDml1vTWONGFzCqMpSdjS1sa2plcIC47xpo7ji1PGcPL76Hbfi651AwSMifbajqZXWjjSDShKsf7OZn/xpA4+9spW0O+ceP4qr3l3HzKOqKQpfpdyeTLNiaxOLN+5m6eZG3mxup66mnDkTa7hg2iiqy4v7+YwklxQ8InJIUmnn5y9s4u4/vs7K7Xv22ze4pJCrTqtj7ml1jBv69k/kFxcWMH1cFdPHVeVruHIYUfCISK91pNJce88inlm5k+m1lfzzhccxtLyE5rYkNRXFnHXsCK34km7plSEiWWtq7aCxpYN5z63jmZU7+fLFU/nYnKMOeot+kUwKHhHJSjrtvOvWp2lujz64edVpdVz5rrr+HZQMSAoeEcnKL5dsobk9xfTaSq449Sg+cPLY/h6SDFAKHhHJSnNbEoDvfnQmY6vK+nk0MpC9M28UJCK9F97HKU7o14b0jV5BIpIdfVuxxETBIyK9ogVs0lcKHhHJiq53JC4KHhHpFV3wSF8peEREJK8UPCKSFa0tkLgoeESkV3R7HOkrBY+IiOSVgkdEsuKaa5OYKHhEpFc00SZ9peARkazoekfiouARkV7R2gLpKwWPiIjklYJHRLKitQUSFwWPiPSKaXmB9JGCR0SyogseiYuCR0R6Rxc80kcKHhERySsFj4hkRXcukLgoeESkV/Q5HumrnAaPmd1gZsvMbLmZfTaUfd3MXjOzpWb2kJlVhfI6M9tnZkvC446Mdmaa2StmtsbMbrdwe1wzG2pm881sdfhZHcot1FsT+jk5o625of5qM5uby/MXEZG3y1nwmNk04BpgNjAduMjMJgHzgWnufiKwCrgp47C17j4jPK7LKP9eaGtyeJwfym8Ennb3ycDT4TnABRl1rw3HY2ZDgVuAU8O4bukMKxERyY9cXvFMARa6e4u7J4FngUvd/cnwHGABUNtTI2Y2Ghji7gs8mmS+B7gk7L4YuDts331A+T0eWQBUhXbOA+a7e7277yYKwc4QE5EsaKZN+iqXwbMMOMPMasxsEHAhMO6AOp8AHs94PsHMFpvZs2Z2RigbC2zOqLM5lAGMdPetYXsbMDLjmE1dHNNd+X7M7FozW2Rmi3bu3JnFqYoc+bS2QOJSmKuG3X2Fmd0GPAk0A0uAVOd+M7sZSAI/DUVbgfHuvsvMZgK/NLOpvejPzSyWfxruPg+YBzBr1iz9cxPJoG8glb7K6eICd7/T3We6+5nAbqL3dDCzq4CLgCvC9Bnu3ubuu8L2i8Ba4BhgC/tPx9WGMoDtYQqtc0puRyjfwv5XV53HdFcuIiJ5kutVbSPCz/HApcC9ZnY+8AXg/e7eklF3uJklwvZEooUB68JUWpOZzQmr2a4EHg6HPQJ0rkybe0D5lWF12xygMbTzBHCumVWHRQXnhjIROQjXTXMkJjmbagseNLMaoAO43t0bzOzbQAkwP1yyLwgr2M4EvmxmHUAauM7d60M7nwJ+DJQRvSfU+b7Q14D7zexqYAPw4VD+GNF7SmuAFuDjAO5eb2ZfAV4I9b6c0YeIZEETbdJXOQ0edz+ji7JJ3dR9EHiwm32LgGldlO8Czumi3IHru2nrLuCuHgcuIm+jxQUSF925QER6RWsLpK8UPCIiklcKHhHJimbaJC4KHhHpFX0DqfSVgkdERPJKwSMiWdGqNomLgkdEekWr2qSvFDwikhXduUDiouAREZG8UvCIiEheKXhEJCtaXCBxUfCISK9ocYH0lYJHRETySsEjIiJ5peARkV7RLXOkrxQ8IpIV1+oCiYmCR0R6RYsLpK8UPCIiklcKHhHJimbaJC4KHhHpFc20SV8peEQkK7rgkbgoeESkV0yrC6SPFDwiIpJXCh4RyYoWF0hcFDwi0iuaaJO+UvCIiEheKXhEJCv66muJi4JHRHpFi9qkrxQ8IpIVLS6QuCh4RKRX9Dke6SsFj4iI5JWCR0Syopk2iYuCR0RE8krBIyLZ0eoCiUlhthXNrBqYDJR2lrn7c7kYlIgcnrSuQOKQVfCY2d8CNwC1wBJgDvAn4OzcDU1ERI5E2U613QCcAmxw9/cAJwENBzvIzG4ws2VmttzMPhvKvm5mr5nZUjN7yMyqMurfZGZrzGylmZ2XUX5+KFtjZjdmlE8ws4Wh/OdmVhzKS8LzNWF/3cH6EJGeaaJN4pJt8LS6eytEv9Td/TXg2J4OMLNpwDXAbGA6cJGZTQLmA9Pc/URgFXBTqH88cDkwFTgf+K6ZJcwsAXwHuAA4HvhIqAtwG/ANd58E7AauDuVXA7tD+TdCvW77yPK/gcg7nmbaJA7ZBs/mcGXyS2C+mT0MbDjIMVOAhe7e4u5J4FngUnd/MjwHWEA0fQdwMXCfu7e5+3pgDVFozQbWuPs6d28H7gMutuhTbGcDD4Tj7wYuyWjr7rD9AHBOqN9dHyIikidZBY+7f8DdG9z9i8C/AHfy51/y3VkGnGFmNWY2CLgQGHdAnU8Aj4ftscCmjH2bQ1l35TVAQ0aIdZbv11bY3xjqd9fWfszsWjNbZGaLdu7ceZDTFHln0KI2iUvWq9o6ufuzWdZbYWa3AU8CzUSLElKd+83sZiAJ/LS3Y8g1d58HzAOYNWuW/rmJBLpdjsQhp5/jcfc73X2mu59J9B7MKgAzuwq4CLjC/a2/o7aw/xVRbSjrrnwXUGVmhQeU79dW2F8Z6nfXlogchL4WQeKS0+AxsxHh53jgUuBeMzsf+ALwfndvyaj+CHB5WJE2gegzQ88DLwCTwwq2YqLFAY+EwHoGuCwcPxd4OKOtuWH7MuC3oX53fYhIFnS9I3Ho9VRbLz1oZjVAB3C9uzeY2beBEqJFCgAL3P06d19uZvcDrxJNwV3v7ikAM/s08ASQAO5y9+Wh/X8C7jOzfwMWE733RPj5EzNbA9QThRU99SEiIvmR0+Bx9zO6KJvUQ/2vAl/tovwx4LEuytfRxaq0sPT7Q73pQ0R6psUFEhfdq01Esqa1BRIHBY+IiOSVgkdEsqKZNomLgkdEsmZa1yYxUPCISFa0uEDiouARkezpgkdioOAREZG8UvCISFZ0yxyJi4JHRLKmmTaJg4JHRLKjCx6JiYJHRLKmOxdIHBQ8IiKSVwoeEcmKZtokLgoeEcma7lwgcVDwiIhIXil4RCQrrnvmSEwUPCKSNa1qkzgoeEQkK7rgkbgoeEQka7rgkTgoeEREJK8UPCKSFc20SVwUPCKSNdPqAomBgkdEsqLFBRIXBY+IZE3XOxIHBY+IiOSVgkdEsqJvIJW4KHhEJHuaa5MYKHhERCSvFDwikhWtapO4KHhEJGuaaZM4KHhERCSvFDwikjXduUDioOAREZG8UvCISFb0DaQSFwWPiGRNM20SBwWPiIjklYJHRLKiiTaJS06Dx8xuMLNlZrbczD4byj4UnqfNbFZG3Toz22dmS8Ljjox9M83sFTNbY2a3W1haY2ZDzWy+ma0OP6tDuYV6a8xsqZmdnNHW3FB/tZnNzeX5ixxpNNMmcchZ8JjZNOAaYDYwHbjIzCYBy4BLgee6OGytu88Ij+syyr8X2pocHueH8huBp919MvB0eA5wQUbda8PxmNlQ4Bbg1DCuWzrDSkR6prUFEpdcXvFMARa6e4u7J4FngUvdfYW7r8y2ETMbDQxx9wUeLau5B7gk7L4YuDts331A+T0eWQBUhXbOA+a7e7277wbm8+cQE5GD0Od4JA65DJ5lwBlmVmNmg4ALgXEHOWaCmS02s2fN7IxQNhbYnFFncygDGOnuW8P2NmBkxjGbujimu/L9mNm1ZrbIzBbt3LnzIEMWEZHeKMxVw+6+wsxuA54EmoElQKqHQ7YC4919l5nNBH5pZlN70Z+bWSyTAe4+D5gHMGvWLE0wiKDv45H45HRxgbvf6e4z3f1MYDewqoe6be6+K2y/CKwFjgG2ALUZVWtDGcD2MIXWOSW3I5RvYf+rq85juisXkSxook3ikOtVbSPCz/FECwru7aHucDNLhO2JRAsD1oWptCYzmxNWs10JPBwOewToXJk294DyK8PqtjlAY2jnCeBcM6sOiwrODWUichBaXCBxydlUW/CgmdUAHcD17t5gZh8AvgUMB35tZkvc/TzgTODLZtYBpIHr3L0+tPMp4MdAGfB4eAB8DbjfzK4GNgAfDuWPEb2ntAZoAT4O4O71ZvYV4IVQ78sZfYjIQWhtgcQhp8Hj7md0UfYQ8FAX5Q8CD3bTziJgWhflu4Bzuih34Ppu2roLuOtgYxcRkdzQnQtEJCuaaZO4KHhEpBc01yZ9p+AREZG8UvCISFa0qk3iouARkaxpVZvEQcEjIlnSJY/EQ8EjIlnTBY/EQcEjIiJ5peARkaxocYHERcEjIlnT4gKJg4JHRLKiKx6Ji4JHRLJmWl4gMVDwiIhIXil4RCQr+gZSiYuCR0SypsUFEgcFj4iI5JWCR0SyolVtEhcFj4hkTTNtEgcFj4hkRRc8EhcFj4hkzbS6QGKg4BERkbxS8IhIVrS4QOKi4MmxZVsaWbalsb+HISJy2Cjs7wEcyVZt38PF3/kDqbRzwthKqgYVkSjYf468KFHAoOIEZUUJSosSlIXtsqIEpWH7wP0lhQU07usgnXZKihIMryihtrqMgoLezb+7Ox0pp7hQf3+ISP4oeHLovuc3kUo7nzzraBZv3M2e1iSeMV/hQHsyTWtHin0dKfa1p2jtSNOeSve6r4qSQqaOGcKMcVXUDStnxOASChMFpNNOKu20p9LsbU1SUGC8b/pofrNsG7c+toLtTW0Mqyjm/dPH8i8XTdGbx9It3TJH4qLgyZGOVJqHl2zh/Kmj+Kfzj+vVsclUOgqijhSt7X/ejoIpegwpK6KwwNjXkWJbYyuvbm3i5c2N/OgPrx80uP7ll8vY15FixrgqLj9lPL9fvZO7/rCea8+cyKjK0r6cthzh9HeJxEHBkyMvrK9nV3M7H5xZ2+tjCxMFDE4UMLi0qNfHdqTS7NzTxo49baTSaQrMSBQYRYkCBpcW8pMFG/j+s+s4fdIwfjh3FqVFCeZMrOEjP1jAqu17FDzSPV3wSEwUPDly2qRhPH7DGRw9vCKv/RYlChhTVcaYqrIu9994/nG8d8pITqytpKQwAcAxI6Mxrtq+hzOPGZ63scrAoyseiYOCJ4emjB7S30N4GzPjlLqh+5XVVJRQU17Mmh17+2lUIvJOouVMAsDxY4bw1IodrN2p8JGuaaZN4qLgEQBu/qsppN15/7f+l58u3EAqnf2vmXQv6srApq++ljhoqk0AOG7UEB79zOl8/v4l3PzQMp5esYNvfeQkykuil0hbMsXz6+tZtX0vWxv2sa2ple1NrWysb2HHnjaGV5Rw/JghTBtTybSxQ5gxrloLFY4wrlsXSEwUPPKWMVVl/OyaOdzzpw188VfLOes/fsdlM2tJptL8z0tb2NXcDkBZUYJRlaWMHFLCuycNY2xVGW80tLL8jUZ+v/rNt66Wjh05mLOOHc5fnTiaE2ur9utrb1uSpZsaWLtzLxvrW9iwq4W9bUlGDill5JBSxlaXcdrRNXlfnCE90+ICiYOCR/ZjZsw9rY4Taiv5xvxVzHtuHe7Oe6eM5PLZ45heW8XQ8uJuP2ja2pHitW17eH79Ln63Mvp80PefW8eHZtYy97Q6frdyB48v28aKrU10ztCVFBYwfuggBpcW8vz6enbsaaUj5RQWGD/6+CmcMVkr7USOJKbL557NmjXLFy1a1N/D6Dct7UnceWvKrbf2tHbwnWfW8sPfryMZkuaUumreNbGGmXVDOW7UYIZXlOx3u5902tm8ex9X3LmAwSVFPPqZ0zGDNTv28qd1uxhaXszsuqGMGKKpvHy64b7FLNnUwLP/+J7+HooMAGb2orvP6mqfrnikR4OK+/YSGVxaxI0XHMdlM8eyYF09p08aRt2w8h6PKSgwxtcM4nPvPYbP3/8yZ/3H72hpT/Hm3rb96p0wtpL3TR/NRSeO6fZzSxIvzbRJHHIaPGZ2A3AN0ev1B+7+TTP7EPBFYAow290XZdS/CbgaSAF/5+5PhPLzgf8CEsAP3f1roXwCcB9QA7wIfMzd282sBLgHmAnsAv7a3V/vqQ/JrUkjBjNpxOBeHXPxjLFsbWxl8cYGhpQVMuuooZw+aRi7W9r549pdPL5sK7c+9hq3PvYap9RVc91fHM05U0bm6AxEJC45Cx4zm0YUOrOBduA3ZvYosAy4FPj+AfWPBy4HpgJjgKfM7Jiw+zvAXwKbgRfM7BF3fxW4DfiGu99nZncQBcr3ws/d7j7JzC4P9f66uz7cPZWr/w5y6BIFxvXvmfS28vE1g5g+ropPnnU0699s5tGX3+CBlzZz9d2LuPTksXzp/VMP6XZD0jPNyktccvk5ninAQndvcfck8CxwqbuvcPeVXdS/GLjP3dvcfT2whii0ZgNr3H2du7cTXeFcbNG722cDD4Tj7wYuyWjr7rD9AHBOqN9dHzJATRhWzmfOmcxTn/8LbjhnMr9cvIULb/89jy59g71tyf4e3hFHdy+XOORyqm0Z8FUzqwH2ARcCPb1LPxZYkPF8cygD2HRA+alE02sNIdQOrD+28xh3T5pZY6jfUx9vMbNrgWsBxo8f3+NJyuGhKFHA5/7yGM6YPIzP3b+ET9+7mOJEAadPHsZHZo/n7ONGvO27kOKQTKV5aWMDT63YzlOvbmf9rmZqyospLymktSPFhGHlzJ5Qw8yjqlm9fQ9PrdjOSxsbwKG0qIBBxYXR9y11fg9TcYIhpUUMLi1kSFkRo4aUMqaqjJOPqmLE4P5bTPHK5kYeefkNaqv1Xpr0Xc6Cx91XmNltwJNAM7CE6H2Vw567zwPmQbSqrZ+HI70wq24oz/z9WSzasJv5r27n10u3cs09i6itLuN908cwprKU4sICSgoTVA4qYlx1GWOrBlFWnOi2zRder+cnf9rAkLJCZoyr5piRFWzY1cL8V7fz7KqdNO7roChhzJlYwwUnjGLX3nZa2lMUFxawevsevv3b1W8tHT925GA+eupRFBcW0NqRoqU9SUt7+MqLZIq9bUm2NOyjuS1JQ0sHbcnoKy6KEwV8/UMncvGMt/2d1CV35zfLtvGrpW+wYVcLp9QN5bKZtUwdM6RXVy372lP855MrufMP6wHYvHtf1seKdCeniwvc/U7gTgAzu5XoCqM7W4BxGc9rQxndlO8CqsysMFz1ZNbvbGuzmRUClaF+T33IEaIwUcCciTXMmVjDTRccx5Ovbue/F2zgjmfXdvk+hRm878Qx3HjBcYypKiOZSrNy+x6WbGpgycYGHl7yBiVFBeDw3ws2vnVcTXkx750ykrOPG8GZxwzr9n2l3c3tLHujkQnDyqmtHpT1ebg7u1s62Fjfwq2/XsEXHlhKcZijwywAAAjKSURBVKKAsdVl1FSUUBGWuHfmiAE79rTxzGs7ePClLazY2sSIwSVMHlnBvQs38uM/vs64oWVMHV1J3bByUuk0z616k1GVpXz67EkcVTOI3c0d7NzTxubdLSzZ1MD8V7ezq7mdvzl1PPcu3Nj9YEV6Iaef4zGzEe6+w8zGE135zHH3hrDvd8A/dK5qM7OpwL1E77mMAZ4GJhP9e1oFnEMUEi8Af+Puy83sF8CDGYsLlrr7d83seuAEd78uLC641N0/3F0fPS0ueKd/judI0pZM0bQvSXsqTXsyTX1zG5t37+OVzY3cs2ADHak0YyrL2Lm3jfZwpVE9qIh3TxrGv10yjcGlRazbuZd1bzYzrKKEGeOqcjJ915UdTa2879v/y/amtoNXBqaOGcIVpx7Fh2fVUpgooKGlnV8t3cof17zJym172Fjfgll0B/U3Gvbx5t72t7VRUVLIWccO56NzjmLOxBo+dudCVm/fy4J/Pifu05MjUE+f48l18Pye6L2VDuDz7v60mX0A+BYwHGgAlrj7eaH+zcAngCTwWXd/PJRfCHyTaDn1Xe7+1VA+kWixwVBgMfBRd28zs1LgJ8BJQD1wubuv66mP7ih43hk21bfw0OItvP5mM0PLizmhtpIZ46oYP3TQYfOG+t62JEs3N9DSlmLn3jZa2lNvu39aeUkhp08axrih2V9ZNbcleWL5NprbklSXFzO8ooTRlWXUVpft98Fedz9s/lvI4a/fgudIoOAREem9noJHX4sgIiJ5peAREZG8UvCIiEheKXhERCSvFDwiIpJXCh4REckrBY+IiOSVgkdERPJKHyA9CDPbCWw4hEOHAW/GPJx80zkcHo6Ec4Aj4zx0Dtk7yt2Hd7VDwZMjZraou0/tDhQ6h8PDkXAOcGSch84hHppqExGRvFLwiIhIXil4cmdefw8gBjqHw8ORcA5wZJyHziEGeo9HRETySlc8IiKSVwoeERHJKwVPDpjZ+Wa20szWmNmN/TSGu8xsh5ktyygbambzzWx1+Fkdys3Mbg/jXWpmJ2ccMzfUX21mczPKZ5rZK+GY2y18NWV3fRzC+MeZ2TNm9qqZLTezGwbgOZSa2fNm9nI4hy+F8glmtjD0+3MzKw7lJeH5mrC/LqOtm0L5SjM7L6O8y9dad30cKjNLmNliM3t0AJ/D6+H/9xIzWxTKBszrKbRVZWYPmNlrZrbCzN410M4BiL7OVo/4HkRfz70WmAgUAy8Dx/fDOM4ETgaWZZT9O3Bj2L4RuC1sXwg8DhgwB1gYyocC68LP6rBdHfY9H+paOPaCnvo4hPGPBk4O24OBVcDxA+wcDKgI20XAwtDf/URfxw5wB/DJsP0p4I6wfTnw87B9fHgdlQATwusr0dNrrbs++vB6+jxwL/BoT+0f5ufwOjDsgLIB83oKx98N/G3YLgaqBto5uLuCJ+4H8C7giYznNwE39dNY6tg/eFYCo8P2aGBl2P4+8JED6wEfAb6fUf79UDYaeC2j/K163fURw7k8DPzlQD0HYBDwEnAq0afGCw98vQBPAO8K24Whnh34Guqs191rLRzTZR+HOPZa4GngbODRnto/XM8htPE6bw+eAfN6AiqB9YRFYQPxHDofmmqL31hgU8bzzaHscDDS3beG7W3AyLDd3Zh7Kt/cRXlPfRyyMF1zEtEVw4A6hzBFtQTYAcwn+uu+wd2TXfT71ljD/kag5hDOraaHPg7FN4EvAOnwvKf2D9dzAHDgSTN70cyuDWUD6fU0AdgJ/ChMe/7QzMoH2DkAeo/nHcujP11yupY+jj7MrAJ4EPisuzfF3f7B9LUPd0+5+wyiq4bZwHFxjS0fzOwiYIe7v9jfY4nB6e5+MnABcL2ZnZm5cwC8ngqJps+/5+4nAc1E015xtZ+VOPpQ8MRvCzAu43ltKDscbDez0QDh545Q3t2Yeyqv7aK8pz56zcyKiELnp+7+PwPxHDq5ewPwDNGUUZWZFXbR71tjDfsrgV2HcG67euijt94NvN/MXgfuI5pu+68Bdg4AuPuW8HMH8BDRHwID6fW0Gdjs7gvD8weIgmggnQOg4MmFF4DJYUVOMdEbrI/085g6PQJ0rmCZS/S+SWf5lWEVzBygMVxWPwGca2bVYRXLuUTz7FuBJjObE1a9XHlAW1310Suh3TuBFe7+/wboOQw3s6qwXUb0HtUKogC6rJtz6Oz3MuC34a/LR4DLLVoxNgGYTPQmcJevtXBMd330irvf5O617l4X2v+tu18xkM4BwMzKzWxw5zbR62AZA+j15O7bgE1mdmwoOgd4dSCdQ+bJ6BHzg2g1ySqi+fyb+2kMPwO2Ah1EfyldTTRv/jSwGngKGBrqGvCdMN5XgFkZ7XwCWBMeH88on0X0D3ct8G3+fBeMLvs4hPGfTnQ5vxRYEh4XDrBzOBFYHM5hGfCvoXwi0S/dNcAvgJJQXhqerwn7J2a0dXMY50rCSqOeXmvd9dHH19RZ/HlV24A6h9DWy+GxvLOfgfR6Cm3NABaF19QviValDahzcHfdMkdERPJLU20iIpJXCh4REckrBY+IiOSVgkdERPJKwSMiInml4BE5zFh0B+JPhe0xZvZAf49JJE5aTi1ymAn3pnvU3af181BEcqLw4FVEJM++Bhwdbi66Gpji7tPM7CrgEqCc6JP//0F0a/yPAW3Ahe5eb2ZHE31wcDjQAlzj7q/l/zREuqapNpHDz43AWo9uLvqPB+ybBlwKnAJ8FWjx6IaRfyK6xQnAPOAz7j4T+Afgu3kZtUiWdMUjMrA84+57gD1m1gj8KpS/ApwY7uZ9GvCL8OWREH35mshhQ8EjMrC0ZWynM56nif49FxB9j82MfA9MJFuaahM5/Owh+rrvXvPoO4vWm9mHILrLt5lNj3NwIn2l4BE5zLj7LuAPZrYM+PohNHEFcLWZdd6J+eI4xyfSV1pOLSIieaUrHhERySsFj4iI5JWCR0RE8krBIyIieaXgERGRvFLwiIhIXil4REQkr/4/QeYkyH1TlAsAAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -}