def save_cohort(cohort, filename): # Check to ensure that the animals in the cohort have a unique identifier # and sex. It's OK to share the same identifier as long as one is male and # the other female. markers = map(op.attrgetter('identifier', 'sex'), cohort.animals) if len(set(markers)) < len(markers): raise ValueError, 'Each animal must have a unique identifier and sex' # If everything's OK, then save the cohort to the file with tables.openFile(filename, 'a') as fh: cohort_node = h5.get_or_append_node(fh.root, 'Cohort_0') animals_node = h5.get_or_append_node(cohort_node, 'animals') cohort_node._v_attrs['description'] = cohort.description for animal in cohort.animals: name = '{}_{}'.format(animal.identifier, animal.sex).upper() animal_node = h5.get_or_append_node(animals_node, name) save_animal(animal, animal_node)
def launch_experiment(self, info, selected): ''' Runs specified experiment type. On successful completion of an experiment, marks the animal as processed and saves the last paradigm used. If the experiment is launched but not run, changes to the paradigm will not be saved. ''' filename = selected._store_filename pathname = selected._store_pathname cohort_folder = filename[:-4] if not os.path.exists(cohort_folder): os.makedirs(cohort_folder) with tables.openFile(filename, 'a', rootUEP=pathname) as fh: # We need to call prepare_experiment prior to loading a saved # paradigm. prepare_experiment adds the roving parameters as traits # on the TrialSetting object. If a paradigm is loaded before the # traits are added, wonky things may happen. paradigm_name = get_experiment(self.args.type).node_name animal_folder = '{}_{}'.format(selected.identifier.upper(), selected.sex.upper()) paradigm_folder = os.path.join(cohort_folder, animal_folder, paradigm_name) log.debug('paradigm folder %s', paradigm_folder) if not os.path.exists(paradigm_folder): os.makedirs(paradigm_folder) globpattern = os.path.join(paradigm_folder, 'session_*.hd5') log.debug('globbing for files in the paradigm folder using %s', globpattern) session_files = sorted(glob(globpattern)) if len(session_files): last_session_file = session_files[-1] log.debug('found last session file %s', last_session_file) last_session_id = int(last_session_file[-8:-4]) + 1 else: # There are no prior sessions last_session_id = 0 session_name = 'session_{:04d}'.format(last_session_id) log.debug('session name %s', session_name) file_name = os.path.join(paradigm_folder, session_name + '.hd5') relative_file_name = os.path.join(os.path.basename(cohort_folder), animal_folder, paradigm_name, session_name) # Calling abspath converts all / to the proper \ format. Typically # it does not matter if the path separator uses / or \; however, # PyTables has some code that fails if we use the / separator when # creating a hardlink. file_name = os.path.abspath(file_name) log.debug('session file %s', file_name) with tables.openFile(file_name, 'a') as fh_data: node = fh_data.root model, controller = prepare_experiment(self.args, node, create_child=False) model.animal = selected # Node that will contain the hard links to the actual experiment # file link_node = get_or_append_node(fh.root, 'experiments') link_name = paradigm_name + '_' + session_name link_target = relative_file_name + ':' + node._v_pathname link_target = str(link_target) log.debug('creating external link to %s', link_target) fh.createExternalLink(link_node, link_name, link_target) # Try to load settings from the last time the subject was run. # If we cannot load the settings for whatever reason, notify the # user and fall back to the default settings. paradigm_node = get_or_append_node(link_node, 'last_paradigm') paradigm_hash = paradigm_name + '_' + '_'.join(self.args.rove) # Attempt to load the last used paradigm paradigm = None try: paradigm = paradigm_node._v_attrs[paradigm_hash] except KeyError as e: log.exception(e) mesg = 'No prior paradigm found' log.debug(mesg) information(info.ui.control, mesg) except pickle.UnpicklingError as e: log.exception(e) mesg = 'Prior settings found, but unable to load' log.debug(mesg) information(info.ui.control, mesg) try: if paradigm is not None: log.debug('Using paradigm from last time this animal was run') model.paradigm = paradigm elif self.last_paradigm is not None: log.debug('Animal does not have any prior paradigm.') model.paradigm = self.last_paradigm mesg = 'Using paradigm from previous animal' information(info.ui.control, mesg) log.debug(mesg) except TraitError: log.debug('Prior paradigm is not compatible with experiment') try: model.edit_traits(parent=info.ui.control, kind='livemodal', handler=controller) # One very nice feature of PyTables is that it will # automatically pickle classes into strings that can be # stored as node attributes. paradigm_node._v_attrs[paradigm_hash] = model.paradigm self.last_paradigm = model.paradigm selected.processed = True log.debug('Saved paradigm for animal to the datafile') except AttributeError, e: log.exception(e) except SystemError, e: from textwrap import dedent mesg = """\ Could not launch experiment. This likely means that you forgot to turn on a piece of equipment. Please check and ensure that the RX6, RZ5 and PA5 are turned on. If you still get this error message, please try power-cycling the rack. If this still does not fix the error, power-cycle the computer as well. Please remember that you need to give the equipment rack a minute to boot up once you turn it back on before attempting to launch an experiment. """ error(info.ui.control, str(e) + '\n\n' + dedent(mesg))