From 00528e9460e89f25de52bc1a271c049a71f46926 Mon Sep 17 00:00:00 2001 From: Mario Fink Date: Tue, 26 Jan 2021 13:21:54 +0100 Subject: [PATCH] complete cython interface, python example usage.py --- cython/py_tdm_reaper.pyx | 23 ++++++++++++++++++++++- cython/tdm_reaper.pxd | 16 +++++++++++++--- lib/tdm_datamodel.hpp | 25 +++++++++++++++++++++++++ lib/tdm_datatype.hpp | 14 ++++++++++++++ lib/tdm_reaper.hpp | 28 ++++++++++++++++++++++++++++ makefile | 5 +++-- python/usage.py | 40 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 145 insertions(+), 6 deletions(-) create mode 100644 python/usage.py diff --git a/cython/py_tdm_reaper.pyx b/cython/py_tdm_reaper.pyx index 7bf9cab..80e8f69 100644 --- a/cython/py_tdm_reaper.pyx +++ b/cython/py_tdm_reaper.pyx @@ -1,7 +1,8 @@ # distutils: language = c++ from tdm_reaper cimport tdm_reaper -# import numpy as np +import json as jsn +import numpy as np # import re # import os @@ -14,6 +15,26 @@ cdef class tdmreaper: def __cinit__(self, string tdmfile, string tdxfile): self.cpp_tdm = tdm_reaper(tdmfile,tdxfile) + # provide TDM files + def submit_files(self,string tdmfile, string tdxfile): + self.cpp_tdm.submit_files(tdmfile,tdxfile) + + # get list of channel(-group) ids + def get_channelgroup_ids(self): + return self.cpp_tdm.get_channelgroup_ids() + def get_channel_ids(self): + return self.cpp_tdm.get_channel_ids() + + # get data of specific channel + def get_channel(self, string id): + return self.cpp_tdm.get_channel_as_double(id) + + # get meta-data of channel(-group) + def get_channelgroup_info(self, string id): + return self.cpp_tdm.get_channelgroup_info(id) + def get_channel_info(self, string id): + return self.cpp_tdm.get_channel_info(id) + # def set_file(self, string rawfile): # if not os.path.isfile(rawfile) : # raise ValueError("'" + str(rawfile) + "' does not exist") diff --git a/cython/tdm_reaper.pxd b/cython/tdm_reaper.pxd index 4644486..7b5b70c 100644 --- a/cython/tdm_reaper.pxd +++ b/cython/tdm_reaper.pxd @@ -2,8 +2,8 @@ # use some C++ STL libraries from libcpp.string cimport string -# from libcpp.vector cimport vector -# from libcpp cimport bool +from libcpp.vector cimport vector +from libcpp cimport bool cdef extern from "tdm_reaper.cpp": pass @@ -13,7 +13,17 @@ cdef extern from "tdm_reaper.hpp": # constructor(s) tdm_reaper() except + tdm_reaper(string tdmfile, string tdxfile) except + - # set new file for decoding + # provide TDM files + void submit_files(string tdmfile, string tdxfile) except+ + # get list of channel(-group) ids + vector[string] get_channelgroup_ids() except+ + vector[string] get_channel_ids() except+ + # get data of specific channel + vector[double] get_channel_as_double(string id) except+ + # 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 + diff --git a/lib/tdm_datamodel.hpp b/lib/tdm_datamodel.hpp index 271281c..76c4389 100644 --- a/lib/tdm_datamodel.hpp +++ b/lib/tdm_datamodel.hpp @@ -160,6 +160,17 @@ struct tdm_channelgroup { return formatter.get_info(); } + const std::string get_json() + { + std::stringstream ss; + ss<<"{"<<"\"group-id\":\""< get_channel(std::string& id); + // additional methods for Cython/Python compatibiliy + // + // extract and return any channel as datatype double + std::vector get_channel_as_double(std::string id) + { + std::vector tdmchn = this->get_channel(id); + std::vector chn; + for ( tdmdatatype el: tdmchn ) chn.push_back(el.as_double()); + return chn; + } + // get channel(-group) meta-data + std::string get_channelgroup_info(std::string id) + { + if ( tdmchannelgroups_.count(id) == 1 ) { + return tdmchannelgroups_.at(id).get_json(); + } else { + throw std::runtime_error(std::string("channelgroup does not exist: ") + id); + } + } + std::string get_channel_info(std::string id) + { + if ( tdmchannels_.count(id) == 1 ) { + return tdmchannels_.at(id).get_json(); + } else { + throw std::runtime_error(std::string("channel does not exist: ") + id); + } + } + // dump a single channel/entire group (identified by id) to file void print_channel(std::string &id, const char* filename, bool include_meta = true); void print_group(std::string &id, const char* filename, bool include_meta = true, char sep = ' '); diff --git a/makefile b/makefile index 01e7cfa..4ebe3e7 100644 --- a/makefile +++ b/makefile @@ -79,13 +79,14 @@ cython-list : cython/setup.py cython-build : cython/setup.py cython/tdm_reaper.pxd cython/py_tdm_reaper.pyx $(HPP) lib/tdm_reaper.cpp python3 $< build_ext --inplace - # python3 $< build_ext + cp -v tdm_reaper.cpython-*.so python/ cython-install : cython/setup.py cython/tdm_reaper.pyx cython/tdm_reaper.pyx python3 $< install clean-cython : - rm -vf cython/py_tdm_reaper.cpp tdm_reaper.cpython-*.so + rm -vf cython/py_tdm_reaper.cpp + rm -vf tdm_reaper.cpython-*.so python/tdm_reaper.cpython-*.so rm -rf build # --------------------------------------------------------------------------- # diff --git a/python/usage.py b/python/usage.py new file mode 100644 index 0000000..f0b4ff7 --- /dev/null +++ b/python/usage.py @@ -0,0 +1,40 @@ + +import tdm_reaper +import numpy as np +import json + +# 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) + +# obtain meta data of channelgroups +for grp in grpids[0:2] : + grpinfostr = jack.get_channelgroup_info(grp.encode()) + grpinfostr = grpinfostr.decode() + grpinfo = json.loads(grpinfostr) + print( json.dumps(grpinfo,sort_keys=False,indent=4) ) + +# list ids of channels +chnids = jack.get_channel_ids() +chnids = [x.decode() for x in chnids] +print("list of channels: ",chnids) + +# get (meta-)data of channels +for chn in chnids[0:3] : + + # obtain meta-data + chninfostr = jack.get_channel_info(chn.encode()) + chninfostr = chninfostr.decode() + chninfo = json.loads(chninfostr) + print( json.dumps(chninfo,sort_keys=False,indent=4) ) + + # channel data + chndata = jack.get_channel(chn.encode()) + print(str(chndata[0:6]) + " ...")