fosanalysis
A framework to evaluate distributed fiber optic sensor data
Loading...
Searching...
No Matches
base.py
Go to the documentation of this file.
2r"""
3Contains the base class for all preprocessing classes.
4
5\author Bertram Richter
6\date 2023
7"""
8
9from abc import abstractmethod
10import copy
11
12import numpy as np
13
14from fosanalysis import utils
15
17 r"""
18 Abstract base class for preprocessing classes.
19 """
20 @abstractmethod
21 def __init__(self,
22 *args, **kwargs):
23 r"""
24 Construct an instance of the class.
25 As this is an abstract class, it may not be instantiated directly itself.
26 \param *args Additional positional arguments, will be passed to the superconstructor.
27 \param **kwargs Additional keyword arguments, will be passed to the superconstructor.
28 """
29 super().__init__(*args, **kwargs)
30 @abstractmethod
31 def run(self,
32 x: np.array = None,
33 y: np.array = None,
34 z: np.array = None,
35 make_copy: bool = True,
36 *args, **kwargs) -> tuple:
37 r"""
38 Each preprocessing.Base object has a `run()` method to carry out
39 the preprocessing task and return the preprocessed data.
40 \param x Array of measuring point positions.
41 \param y Array of time stamps.
42 \param z Array of strain data in accordance to `x` and `y`.
43 \param make_copy Switch, whether a deepcopy of the passed data should be done.
44 Defaults to `True`.
45 \param *args Additional positional arguments to customize the behaviour.
46 \param **kwargs Additional keyword arguments to customize the behaviour.
47 \return Returns a tuple like `(x, y, z)`.
48 They correspond to the input variables of the same name.
49 Each of those might be changed.
50 """
51 x, y, z = [np.array(data) for data in [x, y, z]]
52 if make_copy:
53 x, y, z = [copy.deepcopy(data) for data in [x, y, z]]
54 return x, y, z
55
56class Task(Base):
57 r"""
58 Abstract base class for preprocessing task classes.
59 """
60 def __init__(self,
61 timespace: str = "1d_space",
62 *args, **kwargs):
63 r"""
64 Construct an instance of the class.
65 As this is an abstract class, it may not be instantiated directly itself.
66 \param timespace \copybrief timespace For more, see \ref timespace.
67 \param *args Additional positional arguments, will be passed to the superconstructor.
68 \param **kwargs Additional keyword arguments, will be passed to the superconstructor.
69 """
70 super().__init__(*args, **kwargs)
71
80 self.timespace = timespace
81 def run(self,
82 x: np.array = None,
83 y: np.array = None,
84 z: np.array = None,
85 make_copy: bool = True,
86 timespace: str = None,
87 *args, **kwargs) -> tuple:
88 r"""
89 Each preprocessing.Task object has a `run()` method.
90 The actual operations are reimplemented in \ref _run_1d() and \ref _run_2d().
91 This method decides based on the argument, how is operated over the data.
92 If `z` is a 1D array, the array to pass to \ref _run_1d() is determined:
93 1. Use `x` as the coordinate data, if it matches the shape of `z`.
94 2. Use `y` as the coordinate data, if it matches the shape of `z`.
95 3. Generate an array with indices of the shape of `z`.
96
97 If `z` is a 2D array, three option are available, based on `timespace`:
98 \copydetails timespace
99
100 \param x Array of measuring point positions.
101 \param y Array of time stamps.
102 \param z Array of strain data in accordance to `x` and `y`.
103 \param timespace \copybrief timespace For more, see \ref timespace.
104 Defaults to \ref timespace.
105 \param make_copy Switch, whether a deepcopy of the passed data should be done.
106 Defaults to `True`.
107 \param *args Additional positional arguments to customize the behaviour.
108 Will be passed to the chosen method to call.
109 \param **kwargs Additional keyword arguments to customize the behaviour.
110 Will be passed to the chosen method to call.
111 \return Returns a tuple like `(x, y, z)`.
112 They correspond to the input variables of the same name.
113 Each of those might be changed.
114 """
115 timespace = timespace if timespace is not None else self.timespace
116 x, y, z = super().run(x, y, z, make_copy=make_copy, *args, **kwargs)
117 # Inherent 1D operation
118 if z.ndim == 1:
119 x_dim = x.shape == z.shape
120 y_dim = y.shape == z.shape
121 if not x_dim:
122 x_tmp = x
123 x = np.arange(z.shape[0])
124 if not y_dim:
125 y_tmp = y
126 y = np.arange(z.shape[0])
127 # use x or y or fall back on indices
128 if x_dim:
129 x, z = self._run_1d(x, z, *args, **kwargs)
130 elif y_dim:
131 y, z = self._run_1d(y, z, *args, **kwargs)
132 else:
133 x_tmp = np.arange(z.shape[0])
134 x_tmp, z = self._run_1d(x_tmp, z, *args, **kwargs)
135 # Decide, whether to use real 2D operation or fake 2D operation
136 elif z.ndim == 2:
137 x_dim = (x.ndim == 1 and x.shape[0] == z.shape[1])
138 y_dim = (y.ndim == 1 and y.shape[0] == z.shape[0])
139 if not x_dim:
140 x_tmp = x
141 x = np.arange(z.shape[1])
142 timespace = "1d_time"
143 if not y_dim:
144 y_tmp = y
145 y = np.arange(z.shape[0])
146 timespace = "1d_space"
147 if not x_dim and not y_dim:
148 raise ValueError("Could not decide the 1D operation mode, as both x and y are None")
149 if timespace.lower() == "2d":
150 x, y, z = self._run_2d(x, y, z, *args, **kwargs)
151 else:
152 x, y, z = self._map_2d(x, y, z, timespace=timespace, *args, **kwargs)
153 else:
154 raise ValueError("Dimension of z ({}) non-conformant!".format(z.ndim))
155 # Play back the original data, if it was temporalily fixed
156 if not x_dim:
157 x = x_tmp
158 if not y_dim:
159 y = y_tmp
160 return x, y, z
161 def _run_1d(self,
162 x: np.array,
163 z: np.array,
164 *args, **kwargs) -> tuple:
165 r"""
166 Reimplementations describe a one-dimensional operation.
167 This operation might be applied to on a 2D array by \ref _map_2d().
168 This function is called, if:
169 - the `z` is 1D or
170 - \ref timespace is set to `"1d_space"` or `"1d_time"`.
171 \param x Array of coordinate positions.
172 Dependent on \ref timespace it may hold:
173 - `x`: sensor coordinates, (`timespace = "1d_space"`)
174 - `y`: time data (`timespace = "1d_time"`)
175 - indices, if none of both previous options match the `z`'s shape.
176 \param z Array of strain data in accordance to `x` and `y`.
177 \param *args Additional positional arguments to customize the behaviour.
178 \param **kwargs Additional keyword arguments to customize the behaviour.
179 \return Returns a tuple like `(x, z)`.
180 They correspond to the input variables of the same name.
181 Each of those might be changed.
182 """
183 raise NotImplementedError()
184 def _run_2d(self,
185 x: np.array,
186 y: np.array,
187 z: np.array,
188 *args, **kwargs) -> tuple:
189 r"""
190 Native two-dimensional operation implementation.
191 Needs to be reimplemented by sub-classes.
192 This function is only called, if `z` is 2D and \ref timespace is `"2D"`.
193 \param x Array of measuring point positions.
194 \param y Array of time stamps.
195 \param z Array of strain data in accordance to `x` and `y`.
196 \param *args Additional positional arguments to customize the behaviour.
197 \param **kwargs Additional keyword arguments to customize the behaviour.
198 \return Returns a tuple like `(x, y, z)`.
199 They correspond to the input variables of the same name.
200 Each of those might be changed.
201 """
202 raise NotImplementedError()
203 def _map_2d(self,
204 x: np.array,
205 y: np.array,
206 z: np.array,
207 timespace: str = None,
208 *args, **kwargs) -> tuple:
209 r"""
210 Apply the 1D operation along either the space or time timespace.
211 Used for carrying out 1D-only algorithms on a 2D array row- or column-wise.
212 \param x Array of measuring point positions.
213 \param y Array of time stamps.
214 \param z Array of strain data in accordance to `x` and `y`.
215 \param timespace \copybrief timespace For more, see \ref timespace.
216 Defaults to \ref timespace.
217 \param *args Additional positional arguments to customize the behaviour.
218 Will be passed to the chosen method to call.
219 \param **kwargs Additional keyword arguments to customize the behaviour.
220 Will be passed to the chosen method to call.
221 \return Returns a tuple like `(x, y, z)`.
222 They correspond to the input variables of the same name.
223 Each of those might be changed.
224 """
225 timespace = timespace if timespace is not None else self.timespace
226 x_new = x
227 y_new = y
228 z_new = []
229 if timespace.lower() == "1d_space":
230 for row_id, row in enumerate(z):
231 x_new, z_row = self._run_1d(x, row, *args, **kwargs)
232 z_new.append(z_row)
233 z_new = np.array(z_new)
234 elif timespace.lower() == "1d_time":
235 for col_id, column in enumerate(z.T):
236 y_new, z_col = self._run_1d(y, column, *args, **kwargs)
237 z_new.append(z_col)
238 z_new = np.array(z_new).T
239 else:
240 raise ValueError("No such option for timespace known: '{}'.".format(timespace))
241 return x_new, y_new, z_new
Abstract base class for preprocessing classes.
Definition base.py:16
__init__(self, *args, **kwargs)
Construct an instance of the class.
Definition base.py:22
tuple run(self, np.array x=None, np.array y=None, np.array z=None, bool make_copy=True, *args, **kwargs)
Each preprocessing.Base object has a run() method to carry out the preprocessing task and return the ...
Definition base.py:36
Abstract base class for preprocessing task classes.
Definition base.py:56
tuple run(self, np.array x=None, np.array y=None, np.array z=None, bool make_copy=True, str timespace=None, *args, **kwargs)
Each preprocessing.Task object has a run() method.
Definition base.py:87
tuple _map_2d(self, np.array x, np.array y, np.array z, str timespace=None, *args, **kwargs)
Apply the 1D operation along either the space or time timespace.
Definition base.py:208
__init__(self, str timespace="1d_space", *args, **kwargs)
Construct an instance of the class.
Definition base.py:62
tuple _run_1d(self, np.array x, np.array z, *args, **kwargs)
Reimplementations describe a one-dimensional operation.
Definition base.py:164
tuple _run_2d(self, np.array x, np.array y, np.array z, *args, **kwargs)
Native two-dimensional operation implementation.
Definition base.py:188
timespace
Indicator, which approach is used for operations on a 2d array.
Definition base.py:80
This intermediate class indicates, that a sub-class is implementing a task.
Definition base.py:26