Skip to content

Commit da04952

Browse files
authored
Merge pull request #262 from pennmem/sess_num
cmlreaders version 0.10.5
2 parents eaa81cb + 230a62a commit da04952

5 files changed

Lines changed: 100 additions & 14 deletions

File tree

CHANGELOG.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
Changes
22
=======
3+
Version 0.10.5
4+
-------------
5+
**2024-1-24**
6+
7+
* Added system 4 files to PathFinder, including `archived_eeg` which points to replaced elemem eeg
8+
* Loading events and EGG will automatically modify ``session`` field to match 'session' in data index,
9+
fixing issues where events dataframe contains 'original session' value
10+
311
Version 0.10.4
412
-------------
513
**2023-8-1**

cmlreaders/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
from .readers import * # noqa
99
from .cmlreader import CMLReader # noqa
1010

11-
__version__ = "0.10.4"
11+
__version__ = "0.10.5"
1212
version_info = namedtuple("VersionInfo", "major,minor,patch")(
1313
*__version__.split('.'))

cmlreaders/constants.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,21 +128,33 @@
128128
],
129129
"session_json": [
130130
"data10/RAM/subjects/{subject}/behavioral/{experiment}/session_{session}/session.json",
131+
"data10/RAM/subjects/{subject}/behavioral/{experiment}/session_{session}/session.jsonl",
131132
],
132133
"ramulator_session_folder": [
133134
"data10/RAM/subjects/{subject}/behavioral/{experiment}/session_{session}/host_pc/*",
134135
"protocols/r1/subjects/{subject}/experiments/{experiment}/sessions/{session}/ephys/current_source/host_pc/*",
135136
],
137+
# Elemem-related information
138+
"elemem_session_folder": [
139+
"data10/RAM/subjects/{subject}/behavioral/{experiment}/session_{session}/elemem/*",
140+
"protocols/r1/subjects/{subject}/experiments/{experiment}/sessions/{session}/ephys/current_source/elemem/*",
141+
],
136142
# There can be multiple timestamped folders for the host pc files for when
137143
# a session is restarted
138144
"event_log": [
139145
"data10/RAM/subjects/{subject}/behavioral/{experiment}/session_{session}/host_pc/{timestamped_dir}/event_log.json",
146+
"data10/RAM/subjects/{subject}/behavioral/{experiment}/session_{session}/elemem/{timestamped_dir}/event.log",
140147
],
141148
"experiment_config": [
142149
"data10/RAM/subjects/{subject}/behavioral/{experiment}/session_{session}/host_pc/{timestamped_dir}/experiment_config.json",
150+
"data10/RAM/subjects/{subject}/behavioral/{experiment}/session_{session}/elemem/{timestamped_dir}/experiment_config.json",
143151
],
144152
"raw_eeg": [
145153
"data10/RAM/subjects/{subject}/behavioral/{experiment}/session_{session}/host_pc/{timestamped_dir}/eeg_timeseries.h5",
154+
"data10/RAM/subjects/{subject}/behavioral/{experiment}/session_{session}/elemem/{timestamped_dir}/eeg_data.edf",
155+
],
156+
"archived_eeg": [
157+
"data10/RAM/subjects/{subject}/behavioral/{experiment}/session_{session}/elemem/{timestamped_dir}/eeg_archive/eeg_data.edf",
146158
],
147159
"odin_config": [
148160
"data10/RAM/subjects/{subject}/behavioral/{experiment}/session_{session}/host_pc/{timestamped_dir}/config_files/{subject}_*.csv",
@@ -229,3 +241,12 @@
229241

230242
# All Ramulator files/directories
231243
ramulator_files = host_pc_files + used_classifier_files + ("ramulator_session_folder",)
244+
245+
# All Elemem files/directories
246+
elemem_files = (
247+
"event_log",
248+
"experiment_config",
249+
"raw_eeg",
250+
"elemem_session_folder",
251+
"archived_eeg"
252+
)

cmlreaders/path_finder.py

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from typing import Optional
88

99
from .constants import rhino_paths, localization_files, montage_files, \
10-
subject_files, session_files, ramulator_files, \
10+
subject_files, session_files, ramulator_files, elemem_files, \
1111
PYFR_SUBJECT_CODE_PREFIXES
1212
from .util import get_root_dir
1313
# from .warnings import MultiplePathsFoundWarning
@@ -80,6 +80,8 @@ def __init__(self, subject: Optional[str] = None,
8080

8181
self._paths = rhino_paths
8282

83+
self.system_version = self._determine_system_version()
84+
8385
@property
8486
def path_info(self):
8587
return self._paths
@@ -109,6 +111,21 @@ def subject_files(self):
109111
""" All files that vary only by subject """
110112
return subject_files
111113

114+
def _determine_system_version(self):
115+
elemem_wildcard = self._paths["elemem_session_folder"][0].rstrip('*')
116+
117+
subject_montage = self.subject
118+
if self.montage != '0':
119+
subject_montage = "_".join([self.subject, self.montage])
120+
121+
elemem_path = elemem_wildcard.format(subject=subject_montage,
122+
experiment=self.experiment,
123+
session=self.session)
124+
if os.path.exists(os.path.join(self.rootdir, elemem_path)):
125+
return 4.0
126+
else:
127+
return 3.0 # only 4.0 is matched on, but may want to fully implement
128+
112129
def find(self, data_type):
113130
"""
114131
@@ -148,18 +165,29 @@ def _lookup_file(self, data_type):
148165
timestamped_dir = None
149166

150167
# Only check the host_pc folder if necessary
151-
if data_type in ramulator_files:
152-
folder_wildcard = self._paths['ramulator_session_folder'][0]
153-
ramulator_session_folder = folder_wildcard.format(
154-
subject=subject_montage, experiment=self.experiment,
155-
session=self.session)
156-
157-
timestamped_dir = self._get_most_recent_ramulator_folder(
158-
ramulator_session_folder)
159-
160-
# The user can also just request the folder
161-
if data_type == 'ramulator_session_folder':
162-
return timestamped_dir
168+
if data_type in ramulator_files or data_type in elemem_files:
169+
if self.system_version == 4.0: # system 4
170+
folder_wildcard = self._paths['elemem_session_folder'][0]
171+
elemem_session_folder = folder_wildcard.format(
172+
subject=subject_montage, experiment=self.experiment,
173+
session=self.session)
174+
175+
timestamped_dir = self._get_most_recent_elemem_folder(elemem_session_folder)
176+
177+
if data_type == 'elemem_session_folder':
178+
return timestamped_dir
179+
else: # system 3 (don't think will work for systems 1 and 2)
180+
folder_wildcard = self._paths['ramulator_session_folder'][0]
181+
ramulator_session_folder = folder_wildcard.format(
182+
subject=subject_montage, experiment=self.experiment,
183+
session=self.session)
184+
185+
timestamped_dir = self._get_most_recent_ramulator_folder(
186+
ramulator_session_folder)
187+
188+
# The user can also just request the folder
189+
if data_type == 'ramulator_session_folder':
190+
return timestamped_dir
163191

164192
expected_path = self._find_single_path(paths_to_check,
165193
protocol=self.protocol,
@@ -203,6 +231,27 @@ def _get_most_recent_ramulator_folder(self, base_folder_path):
203231

204232
return latest_directory
205233

234+
def _get_most_recent_elemem_folder(self, base_folder_path):
235+
timestamped_directories = glob.glob(os.path.join(self.rootdir, base_folder_path))
236+
237+
# start of directory should be subject code
238+
timestamped_directories = [
239+
d for d in timestamped_directories
240+
if os.path.isdir(d) and os.path.basename(d)[:len(self.subject)] == self.subject
241+
]
242+
243+
# sort such that most recent appears first
244+
timestamped_directories = sorted(timestamped_directories)[::-1]
245+
246+
if len(timestamped_directories) == 0:
247+
raise RuntimeError("No timestamped folder found in elemem folder.")
248+
249+
# only return the values from the final "/" to the end
250+
latest = timestamped_directories[0]
251+
latest_directory = latest[latest.rfind("/") + 1:]
252+
253+
return latest_directory
254+
206255
def _find_single_path(self, paths, **kwargs):
207256
final_paths = []
208257
for path in paths:

cmlreaders/readers/readers.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,14 @@ def as_dataframe(self):
243243

244244
first = ["eegoffset"]
245245
df = df[first + [col for col in df.columns if col not in first]]
246+
247+
# ensure session field matches data index
248+
# math events given session, other events given original session
249+
if df['session'].unique()[0] != self.session or len(df['session'].unique()) < 1:
250+
warnings.warn(f'Changing events session field from {df["session"].unique()[0]} ' +
251+
f'to {self.session} to match data index.')
252+
df['session'] = self.session
253+
246254
return df
247255

248256

0 commit comments

Comments
 (0)