Changeset 423

Show
Ignore:
Timestamp:
07/17/08 20:37:45 (1 month ago)
Author:
apdavison
Message:

Started modifications to allow specifying an open file to write data to rather than just a filename. This is a preliminary to supporting HDF5 and other formats.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/nest2/__init__.py

    r416 r423  
    112112        assert variable in RECORDING_DEVICE_NAMES 
    113113        self.variable = variable 
    114         self.filename = file or Non
     114        self.file = fil
    115115        self.population = population # needed for writing header information 
    116116        self.recorded = Set([])         
     
    159159     
    160160    def write(self, file=None, gather=False, compatible_output=True): 
    161         user_filename = file or self.filename 
     161        user_file = file or self.file 
     162        if isinstance(user_file, basestring) and num_processes() > 1: 
     163            user_file += '.%d' % rank() 
    162164        nest_filename = _merge_files(self._device, gather) 
    163         if num_processes() > 1: 
    164             user_filename += '.%d' % rank() 
    165165        if compatible_output: 
    166166            # We should do the post processing (i.e the compatible output) in a distributed 
     
    168168            # that should be taken into account to be really clean. Otherwise, if the # symbol 
    169169            # is escaped while reading the file, there is no problem 
    170            recording.write_compatible_output(nest_filename, user_filename, Recorder.formats[self.variable],self.population, get_time_step()) 
    171         else: 
    172             system_line = 'cat %s > %s' % (nest_filename, user_filename) 
    173             os.system(system_line) 
     170           recording.write_compatible_output(nest_filename, user_file, 
     171                                              self.variable, 
     172                                              Recorder.formats[self.variable], 
     173                                              self.population, get_time_step()) 
     174        else: 
     175            if isinstance(userfile, basestring): 
     176                os.system('cat %s > %s' % (nest_filename, user_file)) 
     177            elif hasattr(user_file, 'write'): 
     178                nest_file = open(nest_filename) 
     179                user_file.write(nest_file.read()) 
     180                nest_file.close() 
     181            else: 
     182                raise Exception('Must provide a filename or an open file') 
    174183        if gather == True and num_processes() > 1: 
    175184            root_file = file or self.filename 
  • trunk/src/recording.py

    r416 r423  
    1212DEFAULT_BUFFER_SIZE = 10000 
    1313 
    14 class RecordingManager(object): 
    15      
    16     def __init__(self, setup_function, get_function): 
    17         """ 
    18         `setup_function` should take a variable, a source list, and an optional filename 
    19         and return an identifier. 
    20         `get_function` should take the identifier returned by `setup_function` and 
    21         return the recorded spikes, Vm trace, etc. 
    22          
    23         Example: 
    24         rm = RecordingManager(_nest_record, _nest_get) 
    25         """ 
    26         # create temporary directory 
    27         tempdir = tempfile.mkdtemp() 
    28         # initialise mapping from recording identifiers to temporary filenames 
    29         self.recorder_list = [] 
    30         # for parallel simulations, determine if this is the master node 
    31         self._setup = setup_function 
    32         self._get = get_function 
    33      
    34     def add_recording(self, sources, variable, filename=None): 
    35         recorder = self._setup(variable, sources, filename) 
    36         self.recorder_list.append(recorder) 
    37      
    38     def get_recording(self, recording_id): 
    39         return self._get(recording_id) 
    40      
    41     def write(self, recording_id, filename_or_obj, format="compatible", gather=True): 
    42         pass 
     14#class RecordingManager(object): 
     15#     
     16#    def __init__(self, setup_function, get_function): 
     17#        """ 
     18#        `setup_function` should take a variable, a source list, and an optional filename 
     19#        and return an identifier. 
     20#        `get_function` should take the identifier returned by `setup_function` and 
     21#        return the recorded spikes, Vm trace, etc. 
     22#         
     23#        Example: 
     24#        rm = RecordingManager(_nest_record, _nest_get) 
     25#        """ 
     26#        # create temporary directory 
     27#        tempdir = tempfile.mkdtemp() 
     28#        # initialise mapping from recording identifiers to temporary filenames 
     29#        self.recorder_list = [] 
     30#        # for parallel simulations, determine if this is the master node 
     31#        self._setup = setup_function 
     32#        self._get = get_function 
     33#     
     34#    def add_recording(self, sources, variable, filename=None): 
     35#        recorder = self._setup(variable, sources, filename) 
     36#        self.recorder_list.append(recorder) 
     37#     
     38#    def get_recording(self, recording_id): 
     39#        return self._get(recording_id) 
     40#     
     41#    def write(self, recording_id, filename_or_obj, format="compatible", gather=True): 
     42#        pass 
    4343 
    4444def convert_compatible_output(data, population, variable): 
     
    5959             
    6060     
    61 def write_compatible_output(sim_filename, user_filename, input_format, population, dt): 
     61def write_compatible_output(sim_filename, user_filename, variable, input_format, population, dt): 
    6262    """ 
    6363    Rewrite simulation data in a standard format: 
     
    115115    else: 
    116116        logging.info("%s is empty" % sim_filename) 
    117      
     117 
     118def write_compatible_output1(data_source, user_filename, variable, input_format, population, dt): 
     119    """ 
     120    Rewrite simulation data in a standard format: 
     121        spiketime (in ms) cell_id-min(cell_id) 
     122    """ 
     123    if isinstance(data_source, numpy.ndarray): 
     124        logging.info("Writing %s in compatible format (from memory)" % user_filename) 
     125        N = len(data_source) 
     126    else: # assume data is a filename or open file object 
     127        logging.info("Writing %s in compatible format (was %s)" % (user_filename, data_source)) 
     128        try:  
     129            N = os.path.getsize(data_source) 
     130        except Exception: 
     131            N = 0 
     132     
     133    if N > 0: 
     134        user_file = StandardTextFile(user_filename)     
     135        # Write header info (e.g., dimensions of the population) 
     136        metadata = {} 
     137        if population is not None: 
     138            metadata.update({ 
     139                'dimensions': "\t".join([str(d) for d in population.dim]), 
     140                'first_id': population.first_id, 
     141                'last_id': population.first_id + len(population)-1 
     142            }) 
     143            id_offset = population.first_id 
     144        else: 
     145            id_offset = 0 
     146        metadata['dt'] = dt 
     147         
     148        input_format = input_format.split() 
     149        time_column = input_format.index('t') 
     150        id_column = input_format.index('id') 
     151         
     152        if variable == 'conductance': 
     153            ge_column = input_format.index('ge') 
     154            gi_column = input_format.index('gi') 
     155            column_map = [ge_column, gi_column, id_column] 
     156            raise Exception("Not yet implemented") 
     157        elif variable == 'v': # voltage files 
     158            v_column = input_format.index('v') 
     159            column_map = [v_column, id_column] 
     160        elif variable == 'spikes': # spike files 
     161            column_map = [time_column, id_column] 
     162        else: 
     163            raise Exception("Invalid variable") 
     164         
     165        # Read/select data 
     166        if isinstance(data_source, numpy.ndarray): 
     167            data_array = data_source[:, column_map] 
     168        else: # assume data is a filename or open file object 
     169            #data_array = numpy.loadtxt(data_source, usecols=column_map) 
     170            data_array = readArray(sim_filename, sepchar=None) 
     171        data_array[:,-1] -= id_offset # replies on fact that id is always last column 
     172        metadata['n'] = data_array.shape[0] 
     173         
     174        user_file.write(data_array, metadata) 
     175    else: 
     176        logging.warning("%s is empty" % sim_filename) 
     177 
    118178def readArray(filename, sepchar=None, skipchar='#'): 
    119179    """ 
     
    140200        #if ((Nrow == 1) or (Ncol == 1)): a = numpy.ravel(a) 
    141201    return a 
     202 
     203 
     204class StandardTextFile(object): 
     205     
     206     
     207    def __init__(self, filename, gather=False): 
     208        self.name = filename 
     209        self.gather = gather 
     210        self.fileobj = open(self.name, 'w', DEFAULT_BUFFER_SIZE) 
     211         
     212    def write(self, data, metadata): 
     213        # can we write to the file more than once? In this case, should use seek,tell 
     214        # to always put the header information at the top? 
     215        # write header 
     216        header_lines = ["# %s = %s" % item for item in metadata.items()] 
     217        self.fileobj.write("\n".join(header_lines) + '\n') 
     218        # write data 
     219        numpy.savetxt(self.fileobj, data, fmt = '%s', delimiter='\t') 
     220        self.fileobj.close() 
     221