pyelq 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,229 @@
1
+ # SPDX-FileCopyrightText: 2024 Shell Global Solutions International B.V. All Rights Reserved.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ # -*- coding: utf-8 -*-
6
+ """Spatio-temporal interpolation module.
7
+
8
+ Support function to perform interpolation in various ways
9
+
10
+ """
11
+ import warnings
12
+ from typing import Tuple, Union
13
+
14
+ import numpy as np
15
+ import pandas as pd
16
+ from scipy.interpolate import griddata
17
+
18
+
19
+ def interpolate(
20
+ location_in: np.ndarray = None,
21
+ time_in: Union[np.ndarray, pd.arrays.DatetimeArray] = None,
22
+ values_in: np.ndarray = None,
23
+ location_out: np.ndarray = None,
24
+ time_out: Union[np.ndarray, pd.arrays.DatetimeArray] = None,
25
+ **kwargs,
26
+ ) -> np.ndarray:
27
+ """Interpolates data based on input.
28
+
29
+ Interpolation using scipy.griddata function. Which in turn uses linear barycentric interpolation.
30
+
31
+ It is assumed that the shape of location_in, time_in and values_in is consistent
32
+
33
+ When time_out has the same size as number of rows of location_out, it is assumed these are aligned and be treated as
34
+ consistent, hence the output will be a column vector.
35
+ If this is not the case an interpolation will be performed for all combinations of rows in location out with times
36
+ of time_out and output wil be shaped as [nof_location_values x dimension]
37
+
38
+ If location_out == None, we only perform temporal (1D) interpolation.
39
+ If time_out == None we only perform spatial interpolation
40
+
41
+ If linear interpolation is not possible for spatio or spatiotemporal interpolation, we use nearest neighbor
42
+ interpolation, a warning will be displayed
43
+
44
+ Args:
45
+ location_in (np.ndarray): Array of size [nof_values x dimension] with locations to interpolate from
46
+ time_in (Union[np.ndarray, pd.arrays.DatetimeArray]): Array of size [nof_values x 1] with timestamps or some
47
+ form of time values (seconds) to interpolate from
48
+ values_in (np.ndarray): Array of size [nof_values x 1] with values to interpolate from
49
+ location_out (np.ndarray): Array of size [nof_location_values x dimension] with locations to interpolate to
50
+ time_out (Union[np.ndarray, pd.arrays.DatetimeArray]): Array of size [nof_time_values x 1] with
51
+ timestamps or some form of time values (seconds) to interpolate to
52
+ **kwargs (dict): Other keyword arguments which get passed into the griddata interpolation function
53
+
54
+ Returns:
55
+ result (np.ndarray): Array of size [nof_location_values x nof_time_values] with interpolated values
56
+
57
+ """
58
+ _sense_check_interpolate_inputs(
59
+ location_in=location_in, time_in=time_in, values_in=values_in, location_out=location_out, time_out=time_out
60
+ )
61
+
62
+ if (
63
+ time_out is not None
64
+ and isinstance(time_out, pd.arrays.DatetimeArray)
65
+ and isinstance(time_in, pd.arrays.DatetimeArray)
66
+ ):
67
+ min_time_out = np.amin(time_out)
68
+ time_out = (time_out - min_time_out).total_seconds()
69
+ time_in = (time_in - min_time_out).total_seconds()
70
+
71
+ if location_out is None:
72
+ return _griddata(points_in=time_in, values=values_in, points_out=time_out, **kwargs)
73
+
74
+ if time_out is None:
75
+ return _griddata(points_in=location_in, values=values_in, points_out=location_out, **kwargs)
76
+
77
+ if location_in.shape[0] != time_in.size:
78
+ raise ValueError("Location and time are do not have consistent sizes")
79
+
80
+ if location_out.shape[0] != time_out.size:
81
+ location_temp = np.tile(location_out, (time_out.size, 1))
82
+ time_temp = np.repeat(time_out.squeeze(), location_out.shape[0])
83
+ out_array = np.column_stack((location_temp, time_temp))
84
+ else:
85
+ out_array = np.column_stack((location_out, time_out))
86
+
87
+ in_array = np.column_stack((location_in, time_in))
88
+
89
+ result = _griddata(points_in=in_array, values=values_in, points_out=out_array, **kwargs)
90
+
91
+ if location_out.shape[0] != time_out.size:
92
+ result = result.reshape((location_out.shape[0], time_out.size), order="C")
93
+
94
+ return result
95
+
96
+
97
+ def _sense_check_interpolate_inputs(
98
+ location_in: np.ndarray,
99
+ time_in: Union[np.ndarray, pd.arrays.DatetimeArray],
100
+ values_in: np.ndarray,
101
+ location_out: np.ndarray,
102
+ time_out: Union[np.ndarray, pd.arrays.DatetimeArray],
103
+ ):
104
+ """Helper function to sense check inputs and raise errors when applicable.
105
+
106
+ Args:
107
+ location_in (np.ndarray): Array of size [nof_values x dimension] with locations to interpolate from
108
+ time_in (Union[np.ndarray, pd.arrays.DatetimeArray]): Array of size [nof_values x 1] with timestamps or some
109
+ form of time values (seconds) to interpolate from
110
+ values_in (np.ndarray): Array of size [nof_values x 1] with values to interpolate from
111
+ location_out (np.ndarray): Array of size [nof_location_values x dimension] with locations to interpolate to
112
+ time_out (Union[np.ndarray, pd.arrays.DatetimeArray]): Array of size [nof_time_values x 1] with
113
+ timestamps or some form of time values (seconds) to interpolate to
114
+
115
+ Raises:
116
+ ValueError: When inputs do not match up.
117
+
118
+ """
119
+ if location_out is not None and location_in is None:
120
+ raise ValueError("Cannot specify output location without input location")
121
+ if time_out is not None and time_in is None:
122
+ raise ValueError("Cannot specify output time without input time")
123
+ if values_in is None:
124
+ raise ValueError("Must provide values_in")
125
+ if location_out is None and time_out is None:
126
+ raise ValueError("location_out or time_out not specified. Need to specify somewhere to interpolate to")
127
+
128
+
129
+ def _griddata(points_in: np.ndarray, values: np.ndarray, points_out: np.ndarray, **kwargs):
130
+ """Wrapped function to handle special cases around the gridded interpolate.
131
+
132
+ Will try nearest neighbour method when few enough points that spatial cases fail.
133
+
134
+ Syntax like scipy.griddata
135
+
136
+ Args:
137
+ points_in (np.ndarray): 2-D ndarray of floats with shape (n, D), or length D tuple of 1-D
138
+ nd-arrays with shape (n,). Data point coordinates.
139
+ values (np.ndarray): _ndarray of float or complex, shape (n,). Data values
140
+ points_out (np.ndarray): 2-D ndarray of floats with shape (m, D), or length D tuple of nd-arrays
141
+ broadcastable to the same shape. Points at which to interpolate data.
142
+
143
+ Returns:
144
+ ndarray: Array of interpolated values.
145
+
146
+ """
147
+ if values.size == 1:
148
+ return np.ones((points_out.shape[0], 1)) * values
149
+
150
+ try:
151
+ return griddata(points=points_in, values=values.flatten(), xi=points_out, **kwargs)
152
+ except RuntimeError:
153
+ warnings.warn(
154
+ "Warning linear interpolation did not succeed, most likely too few input points (<5),"
155
+ "trying again with method==nearest"
156
+ )
157
+ if "method" in kwargs:
158
+ del kwargs["method"]
159
+ return griddata(points=points_in, values=values, xi=points_out, method="nearest", **kwargs)
160
+
161
+
162
+ def temporal_resampling(
163
+ time_in: Union[np.ndarray, pd.arrays.DatetimeArray],
164
+ values_in: np.ndarray,
165
+ time_bin_edges: Union[np.ndarray, pd.arrays.DatetimeArray],
166
+ aggregate_function: str = "mean",
167
+ side: str = "center",
168
+ ) -> Tuple[Union[np.ndarray, pd.arrays.DatetimeArray], np.ndarray]:
169
+ """Resamples data into a set of time bins.
170
+
171
+ Checks which values of time_in are withing 2 consecutive values of time_bin_edges and performs the aggregate
172
+ function on the corresponding values from values_in. time_in values outside the time_bin_edges are ignored.
173
+ Empty bins will be assigned a 'NaN' value.
174
+
175
+ When 'time_in' is a sequence of time stamps, a DatetimeArray should be used. Otherwise, a np.ndarray should be used.
176
+
177
+ Args:
178
+ time_in (Union[np.ndarray, pd.arrays.DatetimeArray]): A vector of times which correspond to values_in.
179
+ values_in (np.ndarray): A vector of the values to be resampled.
180
+ time_bin_edges (Union[np.ndarray, pd.arrays.DatetimeArray]): A vector of times which define the edges of the
181
+ bins into which the data will be resampled.
182
+ aggregate_function (str, optional): The function which is used to aggregate the data after it has been
183
+ sorted into bins. Defaults to mean.
184
+ side (str, optional): Which side of the time bins should be used to generate times_out. Possible values are:
185
+ 'left', 'center', and 'right'. Defaults to 'center'.
186
+
187
+ Returns:
188
+ time_out (Union[np.ndarray, pd.arrays.DatetimeArray]): Vector-like object containing the times of the resampled
189
+ values consistent with time_in dtype and side input
190
+ argument.
191
+ values_out (np.ndarray): A vector of resampled values, according to the time bins and the aggregate function.
192
+
193
+ Raises:
194
+ ValueError: If any of the input arguments are not of the correct type or shape, this error is raised.
195
+
196
+ """
197
+ if not isinstance(time_bin_edges, type(time_in)) or values_in.size != time_in.size:
198
+ raise ValueError("Arguments 'time_in', 'time_bin_edges' and/or 'values_in' are not of consistent type or size.")
199
+
200
+ if not isinstance(aggregate_function, str):
201
+ raise ValueError("The supplied 'aggregate_function' is not a string.")
202
+
203
+ if side == "center":
204
+ time_out = np.diff(time_bin_edges) / 2 + time_bin_edges[:-1]
205
+ elif side == "left":
206
+ time_out = time_bin_edges[:-1]
207
+ elif side == "right":
208
+ time_out = time_bin_edges[1:]
209
+ else:
210
+ raise ValueError(f"The 'side' argument must be 'left', 'center', or 'right', but received '{side}'.")
211
+
212
+ zero_value = 0
213
+ if isinstance(time_bin_edges, pd.arrays.DatetimeArray):
214
+ zero_value = np.array(0).astype("<m8[ns]")
215
+
216
+ if not np.all(np.diff(time_bin_edges) > zero_value):
217
+ raise ValueError("Argument 'time_bin_edges' does not monotonically increase.")
218
+
219
+ if np.any(time_in < time_bin_edges[0]) or np.any(time_in > time_bin_edges[-1]):
220
+ warnings.warn("Values in time_in are outside of range of time_bin_edges. These values will be ignored.")
221
+
222
+ index = np.searchsorted(time_bin_edges, time_in, side="left")
223
+ grouped_vals = pd.Series(values_in).groupby(index).agg(aggregate_function)
224
+ grouped_vals = grouped_vals.drop(index=[0, time_bin_edges.size], errors="ignore").sort_index()
225
+
226
+ values_out = np.full(time_out.shape, np.nan)
227
+ values_out[grouped_vals.index - 1] = grouped_vals.to_numpy()
228
+
229
+ return time_out, values_out
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
@@ -0,0 +1,73 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
10
+
11
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
12
+
13
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
14
+
15
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
16
+
17
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
18
+
19
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
20
+
21
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
22
+
23
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
24
+
25
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
26
+
27
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
28
+
29
+ 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
30
+
31
+ 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
32
+
33
+ 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
34
+
35
+ (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
36
+
37
+ (b) You must cause any modified files to carry prominent notices stating that You changed the files; and
38
+
39
+ (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
40
+
41
+ (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
42
+
43
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
44
+
45
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
46
+
47
+ 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
48
+
49
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
50
+
51
+ 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
52
+
53
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
54
+
55
+ END OF TERMS AND CONDITIONS
56
+
57
+ APPENDIX: How to apply the Apache License to your work.
58
+
59
+ To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
60
+
61
+ Copyright [yyyy] [name of copyright owner]
62
+
63
+ Licensed under the Apache License, Version 2.0 (the "License");
64
+ you may not use this file except in compliance with the License.
65
+ You may obtain a copy of the License at
66
+
67
+ http://www.apache.org/licenses/LICENSE-2.0
68
+
69
+ Unless required by applicable law or agreed to in writing, software
70
+ distributed under the License is distributed on an "AS IS" BASIS,
71
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
72
+ See the License for the specific language governing permissions and
73
+ limitations under the License.
@@ -0,0 +1,127 @@
1
+ Metadata-Version: 2.3
2
+ Name: pyelq
3
+ Version: 1.1.0
4
+ Summary: Package for detection, localization and quantification code.
5
+ License: Apache-2.0
6
+ Keywords: gas dispersion,emission,detection,localization,quantification
7
+ Author: Bas van de Kerkhof
8
+ Requires-Python: >=3.9,<3.12
9
+ Classifier: License :: OSI Approved :: Apache Software License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Requires-Dist: geojson (>=3.2.0)
15
+ Requires-Dist: numpy (>=2.0.2)
16
+ Requires-Dist: openmcmc (==1.0.5)
17
+ Requires-Dist: pandas (>=2.2.3)
18
+ Requires-Dist: plotly (>=6.0.0)
19
+ Requires-Dist: pymap3d (>=3.1.0)
20
+ Requires-Dist: scikit-learn (>=1.6.1)
21
+ Requires-Dist: scipy (>=1.13.1)
22
+ Requires-Dist: shapely (>=2.0.7)
23
+ Project-URL: Documentation, https://sede-open.github.io/pyELQ/
24
+ Project-URL: Homepage, https://sede-open.github.io/pyELQ/
25
+ Project-URL: Repository, https://github.com/sede-open/pyELQ
26
+ Description-Content-Type: text/markdown
27
+
28
+ <!--
29
+ SPDX-FileCopyrightText: 2024 Shell Global Solutions International B.V. All Rights Reserved.
30
+
31
+ SPDX-License-Identifier: Apache-2.0
32
+ -->
33
+
34
+ <div align="center">
35
+
36
+ [![PyPI version](https://img.shields.io/pypi/v/pyelq.svg?logo=pypi&logoColor=FFE873)](https://pypi.org/project/pyelq/)
37
+ [![Supported Python versions](https://img.shields.io/pypi/pyversions/pyelq.svg?logo=python&logoColor=FFE873)](https://pypi.org/project/pyelq/)
38
+ [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
39
+ [![Code Style Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
40
+
41
+ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=pyelq_pyelq&metric=coverage)](https://sonarcloud.io/summary/new_code?id=pyelq_pyelq)
42
+ [![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=pyelq_pyelq&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=pyelq_pyelq)
43
+ [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=pyelq_pyelq&metric=bugs)](https://sonarcloud.io/summary/new_code?id=pyelq_pyelq)
44
+ [![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=pyelq_pyelq&metric=ncloc)](https://sonarcloud.io/summary/new_code?id=pyelq_pyelq)
45
+ [![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=pyelq_pyelq&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=pyelq_pyelq)
46
+ [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=pyelq_pyelq&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=pyelq_pyelq)
47
+ [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=pyelq_pyelq&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=pyelq_pyelq)
48
+ [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=pyelq_pyelq&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=pyelq_pyelq)
49
+ </div>
50
+
51
+ # pyELQ
52
+ This repository contains the Python Emission Localization and Quantification software we call pyELQ. It is code used
53
+ for gas dispersion modelling, in particular methane emissions detection, localization and quantification.
54
+
55
+ ***
56
+ # Background
57
+ The **py**thon **E**mission **L**ocalization and **Q**uantification (pyELQ) code aims to maximize effective use of
58
+ existing measurement data, especially from continuous monitoring solutions. The code has been developed to detect,
59
+ localize, and quantify methane emissions from concentration and wind measurements. It can be used in combination with
60
+ point or beam sensors that are placed strategically on an area of interest.
61
+
62
+ The algorithms in the pyELQ code are based a Bayesian statistics framework. pyELQ can ingest long-term concentration
63
+ and wind data, and it performs an inversion to predict the likely strengths and locations of persistent methane sources.
64
+ The goal is to arrive at a plausible estimate of methane emissions from an area of interest that matches the measured
65
+ data. The predictions from pyELQ come with uncertainty ranges that are representative of probability density functions
66
+ sampled by a Markov Chain Monte Carlo method. Time series of varying length can be processed by pyELQ: in general,
67
+ the Bayesian inversion leads to a more constrained solution if more high-precision measurement data is available.
68
+ We have tested our code under controlled conditions as well as in operating oil and gas facilities.
69
+
70
+ The information on the strength and the approximate location of methane emission sources provided by pyELQ can help
71
+ operators with more efficient identification and quantification of (unexpected) methane sources, in order to start
72
+ appropriate mitigating actions accordingly. The pyELQ code is being made available in an open-source environment,
73
+ to support various assets in their quest to reduce methane emissions.
74
+
75
+ Use cases where the pyELQ code has been applied are described in the following papers:
76
+
77
+ * IJzermans, R., Jones, M., Weidmann, D. et al. "Long-term continuous monitoring of methane emissions at an oil and gas facility using a multi-open-path laser dispersion spectrometer." Sci Rep 14, 623 (2024). (https://doi.org/10.1038/s41598-023-50081-9)
78
+
79
+ * Weidmann, D., Hirst, B. et al. "Locating and Quantifying Methane Emissions by Inverse Analysis of Path-Integrated Concentration Data Using a Markov-Chain Monte Carlo Approach." ACS Earth and Space Chemistry 2022 6 (9), 2190-2198 (https://doi.org/10.1021/acsearthspacechem.2c00093)
80
+
81
+ ## Deployment design
82
+ The pyELQ code needs high-quality methane concentration and wind data to be able to provide reliable output on location
83
+ and quantification of methane emission sources. This requires methane concentration sensors of sufficiently high
84
+ precision in a layout that allows the detection of relevant methane emission sources, in combination with wind
85
+ measurements of high enough frequency and accuracy. The optimal sensor layout typically depends on the prevailing
86
+ meteorological conditions at the site of interest and requires multiple concentration sensors to cover the site under
87
+ different wind directions.
88
+
89
+ ## pyELQ data interpretation
90
+ The results from pyELQ come with uncertainty ranges that are representative of probability density functions sampled
91
+ by a Markov Chain Monte Carlo method. One should take these uncertainty ranges into account when interpreting the pyELQ
92
+ output data. Remember that absence of evidence for methane emissions does not always imply evidence for absence of
93
+ methane emissions; for instance, when meteorological conditions are such that there is no sensor downwind of a methane
94
+ source during the selected monitoring period, then it will be impossible to detect, localize and quantify
95
+ this particular source.
96
+ Also, there are limitations to the forward dispersion model which is used in the analysis.
97
+ For example, the performance of the Gaussian plume dispersion model will degrade at lower wind speeds.
98
+ Therefore, careful interpretation of the data is always required.
99
+
100
+ ***
101
+ # Installing pyELQ as a package
102
+ Suppose you want to use this pyELQ package in a different project.
103
+ You can install it from [PyPi](https://pypi.org/project/pyelq/) through pip
104
+ `pip install pyelq`.
105
+ Or you could clone the repository and install it from the source code.
106
+ After activating the environment you want to install pyELQ in, open a terminal, move to the main pyELQ folder
107
+ where pyproject.toml is located and run `pip install .`, optionally you can pass the `-e` flag is for editable mode.
108
+ All the main options, info and settings for the package are found in the pyproject.toml file which sits in this repo
109
+ as well.
110
+
111
+ ***
112
+
113
+ # Examples
114
+ For some examples on how to use this package please check out these [Examples](https://github.com/sede-open/pyELQ/blob/main/examples)
115
+
116
+ ***
117
+
118
+ # Contribution
119
+ This project welcomes contributions and suggestions. If you have a suggestion that would make this better you can simply open an issue with a relevant title. Don't forget to give the project a star! Thanks again!
120
+
121
+ For more details on contributing to this repository, see the [Contributing guide](https://github.com/sede-open/pyELQ/blob/main/CONTRIBUTING.md).
122
+
123
+ ***
124
+ # Licensing
125
+
126
+ Distributed under the Apache License Version 2.0. See the [license file](https://github.com/sede-open/pyELQ/blob/main/LICENSE.md) for more information.
127
+