1
###############################################################################
2
#    pyrpl - DSP servo controller for quantum optics with the RedPitaya
3
#    Copyright (C) 2014-2016  Leonhard Neuhaus  (neuhaus@spectro.jussieu.fr)
4
#
5
#    This program is free software: you can redistribute it and/or modify
6
#    it under the terms of the GNU General Public License as published by
7
#    the Free Software Foundation, either version 3 of the License, or
8
#    (at your option) any later version.
9
#
10
#    This program is distributed in the hope that it will be useful,
11
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
#    GNU General Public License for more details.
14
#
15
#    You should have received a copy of the GNU General Public License
16
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
###############################################################################
18

19

20
# Dummy version of CurveDB class
21
#
22
# The original version of this code uses a package called pyinstruments, which
23
# is a database for experimental measurement data.
24
# This class simulates the functionality of pyinstruments to guarantee
25
# standalone functionality of the rplockbox package.
26
# In case you
27
# For full performance, download pyinstruments to replace this class
28
# otherwise you can custimize here what is to be done to your data
29
#
30 3
import numpy as np
31 3
import pandas as pd
32 3
import os
33 3
import logging
34 3
import pickle as file_backend
35
#import json as file_backend  # currently unable to store pandas
36

37

38
# optional override of CurveDB class with custom module, as defined in
39
# ./pyrpl/config/global_config.yml
40 3
try:
41 3
    from . import global_config
42 3
    CurveDB = __import__(global_config.general.curvedb).CurveDB
43 3
except:
44 3
    from . import user_curve_dir
45 3
    class CurveDB(object):
46 3
        _dirname = user_curve_dir
47 3
        file_extension = '.dat'
48

49 3
        if not os.path.exists(_dirname): # if _dirname doesn't exist, some unexpected errors will occur.
50 0
            os.mkdir(_dirname)
51

52 3
        def __init__(self, name="some_curve"):
53
            """
54
            A CurveDB object has
55
            - name   = string to give the curve a name
56
            - pk     = integer to uniquely identify the curve (the database primary key)
57
            - data   = pandas.Series() object to hold any data
58
            - params = dict() with all kinds of parameters
59
            """
60 0
            self.logger = logging.getLogger(name=__name__)
61 0
            self.params = dict()
62 0
            x, y = np.array([], dtype=np.float), np.array([], dtype=np.float)
63 0
            self.data = (x, y)
64 0
            self.name = name
65

66 3
        @property
67
        def name(self):
68 0
            return self.params["name"]
69

70 3
        @name.setter
71
        def name(self, val):
72 0
            self.params["name"] = val
73 0
            return val
74

75 3
        @classmethod
76
        def create(cls, *args, **kwds):
77
            """
78
            Creates a new curve, first arguments should be either
79
            Series(y, index=x) or x, y.
80
            kwds will be passed to self.params
81
            """
82 0
            if len(args) == 0:
83 0
                ser = (np.array([], dtype=np.float), np.array([], dtype=np.float))
84 0
            if len(args) == 1:
85 0
                if isinstance(args[0], pd.Series):
86 0
                    x, y = args[0].index.values, args[0].values
87 0
                    ser = (x, y)
88 0
                elif isinstance(args[0], (np.array, list, tuple)):
89 0
                    ser = args[0]
90
                else:
91 0
                    raise ValueError("cannot recognize argument %s as numpy.array or pandas.Series.", args[0])
92 0
            elif len(args) == 2:
93 0
                x = np.array(args[0])
94 0
                y = np.array(args[1])
95 0
                ser = (x, y)
96
            else:
97 0
                raise ValueError("first arguments should be either x or x, y")
98 0
            obj = cls()
99 0
            obj.data = ser
100 0
            obj.params = kwds
101 0
            if not 'name' in obj.params:
102 0
                obj.params['name'] = 'new_curve'
103 0
            pk = obj.pk  # make a pk
104 0
            if "childs" not in obj.params:
105 0
                obj.params["childs"] = None
106 0
            if ("autosave" not in kwds) or (kwds["autosave"]):
107 0
                obj.save()
108 0
            return obj
109

110 3
        def plot(self):
111 0
            self.data.plot()
112

113
        # Implement the following methods if you want to save curves permanently
114 3
        @classmethod
115
        def get(cls, curve):
116 0
            if isinstance(curve, CurveDB):
117 0
                return curve
118 0
            elif isinstance(curve, list):
119 0
                return [CurveDB.get(c) for c in curve]
120
            else:
121 0
                with open(os.path.join(CurveDB._dirname, str(curve) + cls.file_extension),
122
                          'rb' if file_backend.__name__ == 'pickle' else 'r')\
123
                        as f:
124
                    # rb is for compatibility with python 3
125
                    # see http://stackoverflow.com/questions/5512811/builtins-typeerror-must-be-str-not-bytes
126 0
                    curve = CurveDB()
127 0
                    curve._pk, curve.params, data = file_backend.load(f)
128 0
                    curve.data = tuple([np.asarray(a) for a in data])
129 0
                if isinstance(curve.data, pd.Series):  # for backwards compatibility
130 0
                    x, y = curve.data.index.values, curve.data.values
131 0
                    curve.data = (x, y)
132 0
                return curve
133

134 3
        def save(self):
135 0
            with open(os.path.join(self._dirname, str(self.pk) + self.file_extension),
136
                      'wb' if file_backend.__name__ == 'pickle' else 'w')\
137
                    as f:
138
                # wb is for compatibility with python 3
139
                # see http://stackoverflow.com/questions/5512811/builtins-typeerror-must-be-str-not-bytes
140 0
                data = [a.tolist() for a in self.data]
141 0
                file_backend.dump([self.pk, self.params, data], f, )
142

143 3
        def delete(self):
144
            # remove the file
145 0
            delpk = self.pk
146 0
            parent = self.parent
147 0
            childs = self.childs
148 0
            if isinstance(childs, list) and len(childs)> 0:
149 0
                self.logger.debug("Deleting all childs of curve %d"%delpk)
150 0
                for child in childs:
151 0
                    child.delete()
152 0
            self.logger.debug("Deleting curve %d" % delpk)
153 0
            try:
154 0
                filename = os.path.join(self._dirname, str(self.pk) + self.file_extension)
155 0
                os.remove(filename)
156 0
            except OSError:
157 0
                self.logger.warning("Could not find and remove the file %s. ",
158
                                    filename)
159 0
            if parent:
160 0
                parentchilds = parent.childs
161 0
                parentchilds.remove(delpk)
162 0
                parent.childs = parentchilds
163 0
                parent.save()
164

165
        # Implement the following methods if you want to use a hierarchical
166
        # structure for curves
167 3
        @property
168
        def childs(self):
169 0
            try:
170 0
                childs = self.params["childs"]
171 0
            except KeyError:
172 0
                return []
173 0
            if childs is None:
174 0
                return []
175
            else:
176 0
                try:
177 0
                    return CurveDB.get(childs)
178 0
                except KeyError:
179 0
                    return []
180

181 3
        @property
182
        def parent(self):
183 0
            try:
184 0
                parentid = self.params["parent"]
185 0
            except KeyError:
186 0
                self.logger.debug("No parent found.")
187 0
                return None
188
            else:
189 0
                return CurveDB.get(parentid)
190

191 3
        def add_child(self, child_curve):
192 0
            child = CurveDB.get(child_curve)
193 0
            child.params["parent"] = self.pk
194 0
            child.save()
195 0
            childs = self.params["childs"] or []
196 0
            self.params["childs"] = list(childs+[child.pk])
197 0
            self.save()
198

199 3
        @classmethod
200
        def all_pks(cls):
201
            """
202
            Returns:
203
                list of int: A list of the primary keys of all CurveDB objects on the computer.
204
            """
205 0
            pks = [int(f.split('.dat')[0])
206
                   for f in os.listdir(cls._dirname) if f.endswith('.dat')]
207 0
            return sorted(pks, reverse=True)
208

209 3
        @classmethod
210
        def all(cls):
211
            """
212
            Returns:
213
                list of CurveDB: A list of all CurveDB objects on the computer.
214
            """
215 0
            return [cls.get(pk) for pk in cls.all_pks()]
216

217 3
        @property
218
        def pk(self):
219
            """
220
            (int): The primary Key of the
221
            """
222 0
            if hasattr(self, "_pk"):
223 0
                return self._pk
224
            else:
225 0
                pks = self.all_pks()
226 0
                if len(pks) == 0:
227 0
                    self._pk = 1
228
                else:
229 0
                    self._pk = max(pks) + 1
230
                # create the file to make this pk choice persistent
231 0
                with open(os.path.join(self._dirname,
232
                                       str(self._pk) + ".dat"), 'w') as f:
233 0
                    f.close()
234 0
                return self._pk
235 0
            return -1
236
            # a proper implementation will assign the database primary key for pk
237
            # the primary key is used to load a curve from the storage into memory
238

239 3
        def sort(self):
240
            """numerically sorts the data series so that indexing can be used"""
241 0
            X, Y = self.data
242 0
            xs = np.array([x for (x, y) in sorted(zip(X, Y))], dtype=np.float64)
243 0
            ys = np.array([y for (x, y) in sorted(zip(X, Y))], dtype=np.float64)
244 0
            self.data = (xs, ys)
245

246 3
        def fit(self):
247
            """ prototype for fitting a curve """
248 0
            self.logger.warning("Not implemented")
249 0
            pass
250

251 3
        def get_child(self, name):
252
            """
253
            Returns the child of the curve with name 'name'
254

255
            Arguments:
256
                name (str): Name of the child curve to be retrieved. If
257
                    several childs have the same name, the first one is
258
                    returned.
259

260
            Returns:
261
                CurveDB: the child curve
262
            """
263 0
            for c in self.childs:
264 0
                if c.name == name:
265 0
                    return c

Read our documentation on viewing source code .

Loading