From e7d261d2c46a04cebb9b73ff9eaf6f0cd0970d26 Mon Sep 17 00:00:00 2001 From: Mario Fink Date: Tue, 26 Jan 2021 16:15:41 +0100 Subject: [PATCH] clean up repo, include print methods in cython, update README python docu --- README.md | 40 ++++++++++- cython/py_tdm_reaper.pyx | 50 ++++---------- cython/pytdm_ripper.pyx | 142 --------------------------------------- cython/tdm_reaper.pxd | 20 +----- cython/tdm_ripper.pxd | 36 ---------- lib/tdm_reaper.cpp | 60 ++++++++++------- python/example.py | 56 --------------- python/extract_all.py | 62 ----------------- python/usage.py | 38 ++++++++--- 9 files changed, 115 insertions(+), 389 deletions(-) delete mode 100644 cython/pytdm_ripper.pyx delete mode 100644 cython/tdm_ripper.pxd delete mode 100644 python/example.py delete mode 100644 python/extract_all.py diff --git a/README.md b/README.md index f6171af..7b4db00 100644 --- a/README.md +++ b/README.md @@ -230,8 +230,44 @@ grpids = jack.get_channelgroup_ids() chnids = jack.get_channel_ids() ``` -For a full example and to see how the actual data is extracted see the example -`python/usage.py`. +As a use case, we have look at listing the ids of all channelgroups and printing +their data to separate files: + +```Python +import tdm_reaper +import re + +# create 'tdm_reaper' instance object +try : + jack = tdm_reaper.tdmreaper(b'samples/SineData.tdm',b'samples/SineData.tdx') +except RuntimeError as e : + print("failed to load/decode TDM files: " + str(e)) + +# list ids of channelgroups +grpids = jack.get_channelgroup_ids() +grpids = [x.decode() for x in grpids] +print("list of channelgroups: ",grpids) + +for grp in grpids : + + # obtain meta data of channelgroups + grpinfo = jack.get_channelgroup_info(grp.encode()) + print( json.dumps(grpinfo,sort_keys=False,indent=4) ) + + # write this channelgroup to file + try : + grpname = re.sub('[^A-Za-z0-9]','',grpinfo['name']) + grpfile = "channelgroup_" + str(grp) + "_" + str(grpname) + ".csv" + jack.print_channelgroup(grp.encode(), # id of group to be printed + grpfile.encode(), # filename + True, # include metadata as fileheader + ord(' ') # delimiter char + ) + except RuntimeError as e : + print("failed to print channelgroup: " + str(grp) + " : " + str(e)) +``` + +For a full example including more details see `python/usage.py`. ## References diff --git a/cython/py_tdm_reaper.pyx b/cython/py_tdm_reaper.pyx index 80e8f69..c66f081 100644 --- a/cython/py_tdm_reaper.pyx +++ b/cython/py_tdm_reaper.pyx @@ -1,10 +1,8 @@ # distutils: language = c++ from tdm_reaper cimport tdm_reaper -import json as jsn +import json as jn import numpy as np -# import re -# import os cdef class tdmreaper: @@ -29,40 +27,18 @@ cdef class tdmreaper: def get_channel(self, string id): return self.cpp_tdm.get_channel_as_double(id) - # get meta-data of channel(-group) + # get meta-data of channel(-group) (as dictionary) def get_channelgroup_info(self, string id): - return self.cpp_tdm.get_channelgroup_info(id) + grpstr = self.cpp_tdm.get_channelgroup_info(id) + return jn.loads(grpstr.decode()) def get_channel_info(self, string id): - return self.cpp_tdm.get_channel_info(id) + chnstr = self.cpp_tdm.get_channel_info(id) + return jn.loads(chnstr.decode()) - # def set_file(self, string rawfile): - # if not os.path.isfile(rawfile) : - # raise ValueError("'" + str(rawfile) + "' does not exist") - # self.rawit.set_file(rawfile) - # - # def do_conversion(self): - # self.rawit.setup_and_conversion() - # - # def validity(self): - # return self.rawit.get_valid() - # - # def channel_name(self): - # return self.rawit.get_name() - # - # def unit(self): - # return self.rawit.get_unit() - # - # def dt(self): - # return self.rawit.get_dt() - # - # def time_unit(self): - # return self.rawit.get_temp_unit() - # - # def get_time(self): - # return self.rawit.get_time() - # - # def get_channel(self): - # return self.rawit.get_data() - # - # def write_table(self, const char* csvfile, char delimiter): - # self.rawit.write_table(csvfile,delimiter) + # print a channel(-group) + def print_channelgroup(self, string id, const char* filename, + bool include_meta, char delimiter): + self.cpp_tdm.print_group(id,filename,include_meta,delimiter) + def print_channel(self, string id, const char* filename, + bool include_meta): + self.cpp_tdm.print_channel(id,filename,include_meta) diff --git a/cython/pytdm_ripper.pyx b/cython/pytdm_ripper.pyx deleted file mode 100644 index a32f0c1..0000000 --- a/cython/pytdm_ripper.pyx +++ /dev/null @@ -1,142 +0,0 @@ - -from tdm_ripper cimport tdm_ripper -import numpy as np -import re - -cdef class pytdmripper: - - # pointer to C++ instance (since there's no nullary constructor) - cdef tdm_ripper *cripp - - def __cinit__(self, string tdmfile, string tdxfile = b""): - self.cripp = new tdm_ripper(tdmfile,tdxfile) - - def __dealloc__(self): - del self.cripp - - def show_channels(self): - self.cripp.list_channels() - - def show_groups(self): - self.cripp.list_groups() - - def num_channels(self): - return self.cripp.num_channels() - - def no_channels(self, int groupid): - assert (groupid >= 0 and groupid < self.cripp.num_groups()), "index of group must be in [0,n-1]" - return self.cripp.no_channels(groupid) - - def num_groups(self): - return self.cripp.num_groups() - - def no_channel_groups(self): - return self.cripp.num_groups() - - def channel_name(self,int groupid,int channelid): - return self.cripp.channel_name(groupid,channelid).decode('utf-8') - - def group_name(self,int groupid): - return self.cripp.group_name(groupid).decode('utf-8') - - def channel_unit(self,int groupid,int channelid): - return (self.cripp.channel_unit(groupid,channelid)) - - def channel_exists(self,int groupid, string channelname): - return self.cripp.channel_exists(groupid,channelname) - - def obtain_channel_id(self,int groupid, int channelid): - return self.cripp.obtain_channel_id(groupid,channelid) - - def get_channel(self, int channelid): - return np.asarray(self.cripp.get_channel(channelid)) - - def channel(self,int groupid,int channelid): - return self.cripp.channel(groupid,channelid) - - def channel_length(self,int groupid, int channelid): - return self.cripp.channel_length(groupid,channelid) - - def time_stamp(self,int groupid, bool startstop): - return self.cripp.time_stamp(groupid,startstop) - - def get_min(self,int groupid, int channelid): - return self.cripp.get_min(groupid,channelid) - - def get_max(self,int groupid, int channelid): - return self.cripp.get_max(groupid,channelid) - - def print_channel(self, int channelid, const char* filename): - self.cripp.print_channel(channelid,filename) - - def meta_info(self, string attribute_name): - return self.cripp.get_meta(attribute_name) - - def print_meta(self, const char* filename): - self.cripp.print_meta(filename) - - def close(self): - dummy = "" - -#=============================================================================# - -def extract_all(string tdmfile, string tdxfile, string outdirx = b"./", string prfxnam = b""): - """ - Python function extracting all available data from .tdm and .tdx to .csv dump - - Args: - tdmfile: path and filename of .tdm file - tdxfile: path and filename of associated .tdx file - outdirx: directory where all .csv output is dumped - prfxnam: optionally specify a name prefix for all .csv files - - Return: - None - """ - - # TODO preliminary: assume utf-8 - encoding = 'utf-8' - - # set up instance of Cython ripper - td = pytdmripper(tdmfile,tdxfile) - - # if no name prefix is given, .tdm filename will be used - prfx = "" - if prfxnam.decode(encoding) == prfx : - prfx = tdmfile.decode(encoding).rstrip('.tdm').split('/')[-1] - else: - prfx = prfxnam.decode(encoding) - - # obtain number of available groups and channels - numgr = td.num_groups() - numch = td.num_channels() - - # generate list of all files produced - filelist = [] - - # dump all meta information - metafile = outdirx.decode(encoding)+prfx+'.csv' - td.print_meta(metafile.encode(encoding)) - filelist.append(metafile.lstrip("./")) - - # dump all available groups and channels - for g in range(0,numgr): - numgrch = td.no_channels(g) - for c in range(0,numgrch): - # obtained overall channel id - chid = td.obtain_channel_id(g,c) - # get group's and channel's name - gname = td.group_name(g) - cname = td.channel_name(g,c) - # use regular expression replacement to sanitize group and channel names - gname = re.sub('[!@#$%^&*()-+= ,]','',gname) - cname = re.sub('[!@#$%^&*()-+= ,]','',cname) - # generate filename - fichan = prfx + '_' + str(g+1) + '_' + str(c+1) + '_' + gname + '_' + cname + '.csv' - # print channel - td.print_channel(chid,(outdirx.decode(encoding)+fichan).encode(encoding)) - # append filename to list - filelist.append(fichan) - - # return list of all files - return filelist diff --git a/cython/tdm_reaper.pxd b/cython/tdm_reaper.pxd index 7b5b70c..c2b0705 100644 --- a/cython/tdm_reaper.pxd +++ b/cython/tdm_reaper.pxd @@ -23,20 +23,6 @@ cdef extern from "tdm_reaper.hpp": # get meta-data string get_channelgroup_info(string id) except+ string get_channel_info(string id) except+ - - # void set_file(string) - # # perform conversion (pass any C++ exceptions to Python) - # void setup_and_conversion() except + - # # get validity of data format - # bool get_valid() - # # get channel name and unit - # string get_name() - # string get_unit() - # # get time step and time unit - # double get_dt() - # string get_temp_unit() - # # get data array of time and measured quantity's channel - # vector[double] get_time() - # vector[double] get_data() - # # dump all data to .csv - # void write_table(const char*,char delimiter) + # print a channel(-group) + void print_group(string id, const char* filename, bool include_meta, char delimiter) + void print_channel(string id, const char* filename, bool include_meta) diff --git a/cython/tdm_ripper.pxd b/cython/tdm_ripper.pxd deleted file mode 100644 index df41656..0000000 --- a/cython/tdm_ripper.pxd +++ /dev/null @@ -1,36 +0,0 @@ -# cython: language_level = 3 -# distutils: language = c++ - -# use some C++ STL libraries -from libcpp.string cimport string -from libcpp.vector cimport vector -from libcpp cimport bool - -cdef extern from "tdm_ripper.cpp": - pass - -cdef extern from "tdm_ripper.hpp": - cdef cppclass tdm_ripper: - tdm_ripper(string,string) except + - void list_channels() - void list_groups() - int num_channels() - int no_channels(int) - int num_groups() - int no_channel_groups() - string channel_name(int,int) - string group_name(int) - string channel_unit(int,int) - int channel_exists(int,string) - int obtain_channel_id(int,int) - vector[double] get_channel(int) - int channel_length(int,int) - string time_stamp(int,bool) - double get_min(int,int) - double get_max(int,int) - vector[double] channel(int,int) - void print_channel(int,const char*) - string get_meta(string attribute_name) - void print_meta(const char*) - # dummy method for compatibility - void close() diff --git a/lib/tdm_reaper.cpp b/lib/tdm_reaper.cpp index e82f88b..c667792 100644 --- a/lib/tdm_reaper.cpp +++ b/lib/tdm_reaper.cpp @@ -610,36 +610,44 @@ std::vector tdm_reaper::get_channel(std::string& id) void tdm_reaper::print_channel(std::string &id, const char* filename, bool include_meta) { - // declare file stream - std::ofstream fou; - try { - fou.open(filename); - } catch ( const std::exception& e) { - throw std::runtime_error( std::string("failed to open file to dump channel") - + e.what() ); - } - - // get channel object - tdm_channel chn = this->tdmchannels_.at(id); - if ( include_meta ) + // check for channel id + if ( this->tdmchannels_.count(id) != 1 ) { - int width = 20; - fou< chndata = this->get_channel(id); - for ( auto el: chndata ) fou<tdmchannels_.at(id); + if ( include_meta ) + { + int width = 20; + fou< chndata = this->get_channel(id); + for ( auto el: chndata ) fou<