shipgrav 1.0.6__tar.gz → 1.0.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. {shipgrav-1.0.6 → shipgrav-1.0.9}/.github/workflows/release-publish.yml +1 -1
  2. {shipgrav-1.0.6 → shipgrav-1.0.9}/CHANGELOG +19 -0
  3. {shipgrav-1.0.6 → shipgrav-1.0.9}/PKG-INFO +3 -2
  4. shipgrav-1.0.9/docs/_static/TN400_ccp.png +0 -0
  5. {shipgrav-1.0.6 → shipgrav-1.0.9}/example-scripts/dgs_ccp_calc.py +49 -7
  6. {shipgrav-1.0.6 → shipgrav-1.0.9}/pyproject.toml +1 -1
  7. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/__init__.py +3 -3
  8. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/database.toml +1 -0
  9. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/io.py +32 -9
  10. shipgrav-1.0.6/docs/_static/TN400_ccp.png +0 -0
  11. {shipgrav-1.0.6 → shipgrav-1.0.9}/.github/test_conda_env.yml +0 -0
  12. {shipgrav-1.0.6 → shipgrav-1.0.9}/.github/workflows/draft-pdf.yml +0 -0
  13. {shipgrav-1.0.6 → shipgrav-1.0.9}/.github/workflows/test.yml +0 -0
  14. {shipgrav-1.0.6 → shipgrav-1.0.9}/.gitignore +0 -0
  15. {shipgrav-1.0.6 → shipgrav-1.0.9}/.readthedocs.yml +0 -0
  16. {shipgrav-1.0.6 → shipgrav-1.0.9}/CONTRIBUTORS.md +0 -0
  17. {shipgrav-1.0.6 → shipgrav-1.0.9}/LICENSE +0 -0
  18. {shipgrav-1.0.6 → shipgrav-1.0.9}/docs/Makefile +0 -0
  19. {shipgrav-1.0.6 → shipgrav-1.0.9}/docs/_static/SR2312_serial_laptop.png +0 -0
  20. {shipgrav-1.0.6 → shipgrav-1.0.9}/docs/_static/TN400_FAA.png +0 -0
  21. {shipgrav-1.0.6 → shipgrav-1.0.9}/docs/_static/cursor.png +0 -0
  22. {shipgrav-1.0.6 → shipgrav-1.0.9}/docs/_static/rmba.png +0 -0
  23. {shipgrav-1.0.6 → shipgrav-1.0.9}/docs/_static/roll_coherence.png +0 -0
  24. {shipgrav-1.0.6 → shipgrav-1.0.9}/docs/_templates/mynavigation.html +0 -0
  25. {shipgrav-1.0.6 → shipgrav-1.0.9}/docs/conf.py +0 -0
  26. {shipgrav-1.0.6 → shipgrav-1.0.9}/docs/index.rst +0 -0
  27. {shipgrav-1.0.6 → shipgrav-1.0.9}/docs/make.bat +0 -0
  28. {shipgrav-1.0.6 → shipgrav-1.0.9}/docs/requirements.txt +0 -0
  29. {shipgrav-1.0.6 → shipgrav-1.0.9}/example-scripts/RMBA_calc.py +0 -0
  30. {shipgrav-1.0.6 → shipgrav-1.0.9}/example-scripts/dgs_bgm_comp.py +0 -0
  31. {shipgrav-1.0.6 → shipgrav-1.0.9}/example-scripts/dgs_raw_comp.py +0 -0
  32. {shipgrav-1.0.6 → shipgrav-1.0.9}/example-scripts/interactive_line_pick.py +0 -0
  33. {shipgrav-1.0.6 → shipgrav-1.0.9}/example-scripts/mru_coherence.py +0 -0
  34. {shipgrav-1.0.6 → shipgrav-1.0.9}/joss/paper.bib +0 -0
  35. {shipgrav-1.0.6 → shipgrav-1.0.9}/joss/paper.md +0 -0
  36. {shipgrav-1.0.6 → shipgrav-1.0.9}/readme.md +0 -0
  37. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/grav.py +0 -0
  38. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/nav.py +0 -0
  39. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/__init__.py +0 -0
  40. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/__main__.py +0 -0
  41. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/AT01_bgm.BGM +0 -0
  42. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/AT01_nav.gps +0 -0
  43. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/AT05_01_bgm.RGS +0 -0
  44. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/DGStest_laptop.dat +0 -0
  45. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/IXBlue.yaml +0 -0
  46. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/MGL2003_bgm.y2020d244 +0 -0
  47. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/MGL2003_nav.y2020d244 +0 -0
  48. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/NBP_2301_nav.d013 +0 -0
  49. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/RR2212_bgm.txt +0 -0
  50. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/RR2212_nav.txt +0 -0
  51. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/SR2302_nav.raw +0 -0
  52. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/SR2312_dgs_raw.txt +0 -0
  53. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/SR2312_mru.txt +0 -0
  54. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/TN400_bgm.Raw +0 -0
  55. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/TN400_dgs_proc.Raw +0 -0
  56. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/TN400_dgs_raw.Raw +0 -0
  57. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/ex_files/TN400_nav.Raw +0 -0
  58. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/test_grav_data.py +0 -0
  59. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/test_grav_nodata.py +0 -0
  60. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/test_io.py +0 -0
  61. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/test_nav.py +0 -0
  62. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/tests/test_utils.py +0 -0
  63. {shipgrav-1.0.6 → shipgrav-1.0.9}/shipgrav/utils.py +0 -0
@@ -69,7 +69,7 @@ jobs:
69
69
  name: python-package-distributions
70
70
  path: dist/
71
71
  - name: Sign the dists with Sigstore
72
- uses: sigstore/gh-action-sigstore-python@v2.1.1
72
+ uses: sigstore/gh-action-sigstore-python@v3.2.0
73
73
  with:
74
74
  inputs: >-
75
75
  ./dist/*.tar.gz
@@ -1,3 +1,22 @@
1
+ v1.0.9
2
+
3
+ 2026-02-02 Hannah F Mark <hmark@whoi.edu>
4
+ * minor version bump to catch up pyproject.toml, sorry
5
+
6
+ v1.0.8
7
+
8
+ 2026-02-02 Hannah F Mark <hmark@whoi.edu>
9
+ * minor version bump to make the release work after updating sigstore
10
+
11
+ v1.0.7
12
+
13
+ 2025-06-20 Hannah F Mark <hmark@whoi.edu>
14
+ * add nav interpolation to the TN400 cross-coupling example script; fixes dropout section
15
+ * related: update documentation with new figure
16
+
17
+ 2024-12-25 Hannah F Mark <hmark@whoi.edu>
18
+ * add option to decimate nav data, per file as it is being read
19
+
1
20
  v1.0.6
2
21
 
3
22
  2024-11-21 Hannah F Mark <hmark@whoi.edu>
@@ -1,9 +1,10 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: shipgrav
3
- Version: 1.0.6
3
+ Version: 1.0.9
4
4
  Summary: Functions for marine gravity data processing and reduction
5
5
  Author-email: "Hannah F. Mark" <hmark@whoi.edu>
6
6
  Maintainer-email: "Hannah F. Mark" <hmark@whoi.edu>
7
+ License-File: LICENSE
7
8
  Keywords: UNOLS,gravimetry,marine gravity
8
9
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
9
10
  Classifier: Operating System :: OS Independent
@@ -27,6 +27,7 @@ import shipgrav.grav as sgg
27
27
  import shipgrav.io as sgi
28
28
  import shipgrav.nav as sgn
29
29
  import tomli as tm
30
+ from scipy.interpolate import interp1d
30
31
  from scipy.signal import filtfilt, firwin
31
32
 
32
33
  # %%
@@ -49,6 +50,24 @@ dgs_files = pooch.retrieve(url="https://zenodo.org/records/12733929/files/data.z
49
50
  members=['data/Thompson/TN400/gravimeter/DGS/AT1M-Grav-PROC_20220314-000001.Raw',
50
51
  'data/Thompson/TN400/gravimeter/DGS/AT1M-Grav-PROC_20220313-000001.Raw']))
51
52
 
53
+ nav_files = pooch.retrieve(url="https://service.rvdata.us/data/cruise/TN400/fileset/151457",
54
+ known_hash="76e66365c41d393510bb7ab9637305296282e9041415c1343faa171af28abf85",progressbar=True,
55
+ processor=pooch.Untar(
56
+ members=['TN400/151457/data/POSMV-V5-INGGA-RAW_20220313-000001.Raw',
57
+ 'TN400/151457/data/POSMV-V5-INGGA-RAW_20220314-000001.Raw']))
58
+
59
+ # %%
60
+ # read and sort the nav data
61
+ gps_nav = sgi.read_nav(ship, nav_files)
62
+ gps_nav.sort_values('time_sec', inplace=True)
63
+ gps_nav.reset_index(inplace=True, drop=True)
64
+
65
+ # %%
66
+ # we happen to know that there are some weird nav dropouts in this dataset
67
+ # so clean them up here
68
+ bad_inds = np.where(np.diff(gps_nav['lon']) > 1)[0]
69
+ gps_nav.drop(bad_inds, axis=0, inplace=True)
70
+
52
71
  # %%
53
72
  # read and sort the gravimeter data
54
73
  dgs_data = sgi.read_dgs_laptop(dgs_files, ship)
@@ -59,18 +78,25 @@ dgs_data['tsec'] = [e.timestamp()
59
78
  dgs_data['grav'] = dgs_data['rgrav'] + bias_dgs
60
79
 
61
80
  # %%
62
- # trim some bits that we happen to know are bad
63
- dgs_data = dgs_data.iloc[1000:]
81
+ # sync data geographic coordinates to nav by interpolating with timestamps
82
+ # (interpolators use posix timestamps, not datetimes)
83
+ gps_lon_int = interp1d(gps_nav['time_sec'].values, gps_nav['lon'].values,
84
+ kind='linear', fill_value='extrapolate')
85
+ gps_lat_int = interp1d(gps_nav['time_sec'].values, gps_nav['lat'].values,
86
+ kind='linear', fill_value='extrapolate')
87
+ dgs_data['lon_new'] = gps_lon_int(dgs_data['tsec'].values)
88
+ dgs_data['lat_new'] = gps_lat_int(dgs_data['tsec'].values)
89
+
64
90
 
65
91
  # %%
66
92
  # calculate corrections for FAA
67
93
  ellipsoid_ht = np.zeros(len(dgs_data)) # we are working at sea level
68
- lat_corr = sgg.wgs_grav(dgs_data['lat']) + \
69
- sgg.free_air_second_order(dgs_data['lat'], ellipsoid_ht)
70
- eotvos_corr = sgg.eotvos_full(dgs_data['lon'].values, dgs_data['lat'].values,
94
+ lat_corr = sgg.wgs_grav(dgs_data['lat_new']) + \
95
+ sgg.free_air_second_order(dgs_data['lat_new'], ellipsoid_ht)
96
+ eotvos_corr = sgg.eotvos_full(dgs_data['lon_new'].values, dgs_data['lat_new'].values,
71
97
  ellipsoid_ht, sampling)
72
98
  tide_corr = sgg.longman_tide_prediction(
73
- dgs_data['lon'], dgs_data['lat'], dgs_data['date_time'])
99
+ dgs_data['lon_new'], dgs_data['lat_new'], dgs_data['date_time'])
74
100
 
75
101
  dgs_data['faa'] = dgs_data['grav'] - lat_corr + eotvos_corr + tide_corr
76
102
  dgs_data['full_field'] = dgs_data['grav'] + eotvos_corr + tide_corr
@@ -79,7 +105,7 @@ dgs_data['full_field'] = dgs_data['grav'] + eotvos_corr + tide_corr
79
105
  # calculate kinematic variables and corrections for tilt correction
80
106
  # (maybe not strictly necessary? depends who you ask)
81
107
  gps_vn, gps_ve = sgn.latlon_to_EN(
82
- dgs_data['lon'].values, dgs_data['lat'].values)
108
+ dgs_data['lon_new'].values, dgs_data['lat_new'].values)
83
109
  gps_vn = sampling*gps_vn
84
110
  gps_ve = sampling*gps_ve
85
111
 
@@ -102,6 +128,8 @@ cross_in_plat = acc_cross*up_vecs[1, :]
102
128
  long_in_plat = acc_long*up_vecs[0, :]
103
129
  level_error = lat_corr - igf_in_plat - long_in_plat + cross_in_plat
104
130
 
131
+ dgs_data = dgs_data.iloc[2:] # the first two points' FAA has some edge effect
132
+
105
133
  # %%
106
134
  # calculate cross-coupling coefficients
107
135
  _, model = sgg.calc_cross_coupling_coefficients(dgs_data['faa'].values, dgs_data['vcc'].values, dgs_data['ve'].values,
@@ -118,6 +146,7 @@ dgs_data['faa_ccp'] = dgs_data['faa'] + model.params.ve*dgs_data['ve'] + \
118
146
  model.params.al*dgs_data['al'] + \
119
147
  model.params.ax*dgs_data['ax']
120
148
 
149
+ # filter FAA
121
150
  taps = 2*240
122
151
  freq = 1./240
123
152
  # we resampled to the specified sampling rate when reading the data
@@ -128,12 +157,25 @@ B = firwin(taps, wn, window='blackman') # approx equivalent to matlab fir1
128
157
  ffaa = filtfilt(B, 1, dgs_data['faa'])
129
158
  cfaa = filtfilt(B, 1, dgs_data['faa_ccp'])
130
159
 
160
+ # %%
161
+ # load satellite data for comparison
162
+ sat_path = pooch.retrieve(url="https://zenodo.org/records/12733929/files/data.zip",
163
+ known_hash="md5:83b0411926c0fef9d7ccb2515bb27cc0", progressbar=True,
164
+ processor=pooch.Unzip(
165
+ members=['data/Thompson/TN400/sandwell_tracked.llg']))
166
+ sat_grav = np.loadtxt(sat_path[0], usecols=(3,),
167
+ delimiter=',', skiprows=1)
168
+ sat_grav = sat_grav[2:]
169
+
170
+
131
171
  # %%
132
172
  plt.figure(figsize=(11, 4.8))
133
173
  plt.plot(dgs_data.iloc[taps:-taps//2]['date_time'],
134
174
  ffaa[taps:-taps//2], label='no ccp')
135
175
  plt.plot(dgs_data.iloc[taps:-taps//2]['date_time'],
136
176
  cfaa[taps:-taps//2], label='with ccp')
177
+ plt.plot(dgs_data.iloc[taps:-taps//2]['date_time'],
178
+ sat_grav[taps:-taps//2], label='satellite')
137
179
  plt.xlabel('Timestamp')
138
180
  plt.ylabel('Free air anomaly [mGal]')
139
181
  plt.legend(fontsize=8)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "shipgrav"
7
- version = "1.0.6"
7
+ version = "1.0.9"
8
8
  authors = [
9
9
  {name = "Hannah F. Mark", email = "hmark@whoi.edu"},
10
10
  ]
@@ -62,7 +62,7 @@ Navigation data
62
62
 
63
63
  Which navigation data should you use to process gravimeter data?
64
64
 
65
- In an ideal world, the gravimeter pulls navigation info from the ship's feed and synchronizes it perfectly with acquisition such that the output files have the correct geographic coordinates in them at the start. In practice, this synchronization doesn't always work as expected (see ``example-scripts/dgs_raw_comp.py`` for a case where the serial files do not have GPS info). So, we like to take the timestamped navigation data directly from the ship's feed and match up the gravimeter timestamps to obtain more accurate coordinates.
65
+ In an ideal world, the gravimeter pulls navigation info from the ship's feed and synchronizes it perfectly with acquisition such that the output files have the correct geographic coordinates in them at the start. In practice, this synchronization doesn't always work as expected (see ``example-scripts/dgs_raw_comp.py`` for a case where the serial files do not have GPS info). So, we like to take the timestamped navigation data directly from the ship's feed and match up the gravimeter timestamps to obtain more accurate coordinates. Using navigation from a feed separate from the gravimeter is **highly recommended**.
66
66
 
67
67
  The database file included in shipgrav lists the navigation talkers that we expect are good to use for specific UNOLS vessels. Find the files that contain those feeds, and you should be able to read in timestamped coordinates from them.
68
68
 
@@ -94,10 +94,10 @@ The data files can be downloaded from R2R and Zenodo, and the scripts will do th
94
94
  :height: 250px
95
95
  :align: center
96
96
 
97
- ``dgs_ccp_calc.py`` reads DGS files from R/V Thompson cruise TN400, calculates the FAA and various kinematic variables, and fits for cross-coupling coefficients. The cross-coupling correction is applied and the data are plotted with and without correction.
97
+ ``dgs_ccp_calc.py`` reads DGS files from R/V Thompson cruise TN400, calculates the FAA and various kinematic variables, and fits for cross-coupling coefficients. The cross-coupling correction is applied and the data are plotted with and without correction. Satellite-derived FAA is also plotted
98
98
 
99
99
  .. image:: _static/TN400_ccp.png
100
- :alt: FAA for TN400, with and without cross-coupling correction applied.
100
+ :alt: FAA for TN400, with and without cross-coupling correction applied; and satellite-derived FAA.
101
101
  :height: 250px
102
102
  :align: center
103
103
 
@@ -5,6 +5,7 @@ Revelle = {'dgs'=968888.6465, 'bgm'=855240.81987}
5
5
  NBP = {'dgs'=968634.2514, 'bgm'=-999}
6
6
  Ride = {'dgs'=968895.7718, 'bgm'=-999}
7
7
  Langseth = {'dgs'=-999, 'bgm'=854974.4}
8
+ Sikuliaq = {'dgs'=969538.8152, 'bgm'=-999}
8
9
 
9
10
  [nav-talkers]
10
11
  Atlantis = 'GPGGA'
@@ -17,7 +17,7 @@ from tqdm import tqdm
17
17
  ########################################################################
18
18
 
19
19
 
20
- def read_nav(ship, pathlist, sampling=1, talker=None, ship_function=None, progressbar=True):
20
+ def read_nav(ship, pathlist, sampling=1, talker=None, ship_function=None, decimate=0, progressbar=True):
21
21
  """ Read navigation strings from .GPS (or similar) files.
22
22
 
23
23
  Ships have different formats and use different talkers for preferred
@@ -38,6 +38,8 @@ def read_nav(ship, pathlist, sampling=1, talker=None, ship_function=None, progre
38
38
  This function should return arrays of lon, lat, and timestamps.
39
39
  Look at _navcoords() and navdate_Atlantis() (and similar functions) for examples.
40
40
  :type ship_function: function, optional
41
+ :param decimate: integer skip for decimating data, default 0 returns all points
42
+ :type decimate: int, optional
41
43
  :param progressbar: display progress bar while list of files is read
42
44
  :type progressbar: bool
43
45
 
@@ -119,6 +121,12 @@ def read_nav(ship, pathlist, sampling=1, talker=None, ship_function=None, progre
119
121
  lon_out = np.interp(sec_time, sec_time[idx], lon[idx])
120
122
  lat_out = np.interp(sec_time, sec_time[idx], lat[idx])
121
123
 
124
+ # decimate if we're doing that
125
+ if decimate:
126
+ sec_time = sec_time[::decimate]
127
+ lon_out = lon_out[::decimate]
128
+ lat_out = lat_out[::decimate]
129
+
122
130
  timetime = np.append(timetime, sec_time)
123
131
  lonlon = np.append(lonlon, lon_out)
124
132
  latlat = np.append(latlat, lat_out)
@@ -325,14 +333,16 @@ def _navcoords(allnav, talker):
325
333
  post = subnav[i].split(talker)[-1].lstrip().split(',')
326
334
  if post[0] == '':
327
335
  post = post[1:] # correct for spacing in some files
328
-
329
- lat[i] = int(post[1][:2]) + float(post[1][2:]) / \
330
- 60 # convert to decimal degrees
331
- if post[2] == 'S':
332
- lat[i] = -lat[i] # handle coordinate sign
333
- lon[i] = int(post[3][:3]) + float(post[3][3:])/60
334
- if post[4] == 'W':
335
- lon[i] = -lon[i]
336
+ if post[1] == '' or post[3] == '': # no coords, nav dropped out?
337
+ lat[i] = np.nan; lon[i] = np.nan
338
+ else:
339
+ lat[i] = int(post[1][:2]) + float(post[1][2:]) / \
340
+ 60 # convert to decimal degrees
341
+ if post[2] == 'S':
342
+ lat[i] = -lat[i] # handle coordinate sign
343
+ lon[i] = int(post[3][:3]) + float(post[3][3:])/60
344
+ if post[4] == 'W':
345
+ lon[i] = -lon[i]
336
346
 
337
347
  return lon, lat
338
348
 
@@ -560,6 +570,8 @@ def read_dgs_laptop(fp, ship, ship_function=None, progressbar=True):
560
570
  dat = _dgs_laptop_general(path)
561
571
  elif ship == 'Thompson':
562
572
  dat = _dgs_laptop_Thompson(path)
573
+ elif ship == 'Sikuliaq':
574
+ dat = _dgs_laptop_Sikuliaq(path)
563
575
  else:
564
576
  print('R/V %s not supported for dgs laptop file read' % ship)
565
577
  return -999
@@ -581,6 +593,17 @@ def _dgs_laptop_general(path):
581
593
  return dat
582
594
 
583
595
 
596
+ def _dgs_laptop_Sikuliaq(path):
597
+ """Read single laptop file for Sikuliaq, has more of a header than the others
598
+ """
599
+ dat = pd.read_csv(path,skiprows=19,names=['rgrav','long_a','crss_a','status','ve','vcc',
600
+ 'al','ax','lat','lon','year','month','day',
601
+ 'hour','minute','second'],
602
+ usecols=(1,2,3,6,10,11,12,13,14,15,19,20,21,22,23,24))
603
+ dat['date_time'] = pd.to_datetime(dat[['year','month','day','hour','minute','second']],utc=True)
604
+ return dat
605
+
606
+
584
607
  def _dgs_laptop_Thompson(path):
585
608
  """Read single laptop file for Thompson, which does things its own way.
586
609
  """
Binary file
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes