steer-core 0.1.15__py3-none-any.whl → 0.1.17__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.
@@ -25,8 +25,10 @@ A_TO_mA = 1e3
25
25
  mA_TO_A = 1e-3
26
26
 
27
27
  # Time units
28
- S_TO_H = 1/3600
28
+ S_TO_H = 1 / 3600
29
29
  H_TO_S = 3600
30
+ S_TO_Y = 1 / (3600 * 24 * 365)
31
+ Y_TO_S = 3600 * 24 * 365
30
32
 
31
33
  # Energy units
32
34
  W_TO_KW = 1e-3
@@ -34,3 +36,6 @@ W_TO_KW = 1e-3
34
36
  # Angle units
35
37
  DEG_TO_RAD = 0.017453292519943295
36
38
 
39
+ # Percentage units
40
+ PERCENT_TO_FRACTION = 1e-2
41
+ FRACTION_TO_PERCENT = 1e2
Binary file
steer_core/DataManager.py CHANGED
@@ -7,9 +7,7 @@ from steer_core.Constants.Units import *
7
7
 
8
8
 
9
9
  class DataManager:
10
-
11
10
  def __init__(self):
12
-
13
11
  with importlib.resources.path("steer_core.Data", "database.db") as db_path:
14
12
  self._db_path = db_path
15
13
  self._connection = sql.connect(self._db_path)
@@ -22,8 +20,8 @@ class DataManager:
22
20
  :param table_name: Name of the table.
23
21
  :param columns: Dictionary of columns and their types.
24
22
  """
25
- columns_str = ', '.join([f'{k} {v}' for k, v in columns.items()])
26
- self._cursor.execute(f'CREATE TABLE IF NOT EXISTS {table_name} ({columns_str})')
23
+ columns_str = ", ".join([f"{k} {v}" for k, v in columns.items()])
24
+ self._cursor.execute(f"CREATE TABLE IF NOT EXISTS {table_name} ({columns_str})")
27
25
  self._connection.commit()
28
26
 
29
27
  def drop_table(self, table_name: str):
@@ -32,7 +30,7 @@ class DataManager:
32
30
 
33
31
  :param table_name: Name of the table.
34
32
  """
35
- self._cursor.execute(f'DROP TABLE IF EXISTS {table_name}')
33
+ self._cursor.execute(f"DROP TABLE IF EXISTS {table_name}")
36
34
  self._connection.commit()
37
35
 
38
36
  def get_table_names(self):
@@ -52,9 +50,9 @@ class DataManager:
52
50
  :param data: DataFrame containing the data to insert.
53
51
  """
54
52
  for _, row in data.iterrows():
55
- conditions = ' AND '.join([f"{col} = ?" for col in data.columns])
53
+ conditions = " AND ".join([f"{col} = ?" for col in data.columns])
56
54
  check_query = f"SELECT COUNT(*) FROM {table_name} WHERE {conditions}"
57
-
55
+
58
56
  self._cursor.execute(check_query, tuple(row))
59
57
  if self._cursor.fetchone()[0] == 0: # If the row does not exist, insert it
60
58
  insert_query = f"INSERT INTO {table_name} ({', '.join(data.columns)}) VALUES ({', '.join(['?'] * len(row))})"
@@ -62,11 +60,13 @@ class DataManager:
62
60
 
63
61
  self._connection.commit()
64
62
 
65
- def get_data(self,
66
- table_name: str,
67
- columns: list = None,
68
- condition: str | list[str] = None,
69
- latest_column: str = None):
63
+ def get_data(
64
+ self,
65
+ table_name: str,
66
+ columns: list = None,
67
+ condition: str | list[str] = None,
68
+ latest_column: str = None,
69
+ ):
70
70
  """
71
71
  Retrieve data from the database.
72
72
 
@@ -81,15 +81,17 @@ class DataManager:
81
81
  columns_info = self._cursor.fetchall()
82
82
  columns = [col[1] for col in columns_info] # Extract column names
83
83
  if not columns:
84
- raise ValueError(f"Table '{table_name}' does not exist or has no columns.")
84
+ raise ValueError(
85
+ f"Table '{table_name}' does not exist or has no columns."
86
+ )
85
87
 
86
- columns_str = ', '.join(columns)
88
+ columns_str = ", ".join(columns)
87
89
  query = f"SELECT {columns_str} FROM {table_name}"
88
90
 
89
91
  # Add condition if specified
90
92
  if condition:
91
93
  if isinstance(condition, list):
92
- condition_str = ' AND '.join(condition)
94
+ condition_str = " AND ".join(condition)
93
95
  else:
94
96
  condition_str = condition
95
97
  query += f" WHERE {condition_str}"
@@ -101,13 +103,13 @@ class DataManager:
101
103
  # Execute and return the result
102
104
  self._cursor.execute(query)
103
105
  data = self._cursor.fetchall()
104
-
106
+
105
107
  return pd.DataFrame(data, columns=columns)
106
-
108
+
107
109
  def get_unique_values(self, table_name: str, column_name: str):
108
110
  """
109
111
  Retrieves all unique values from a specified column.
110
-
112
+
111
113
  :param table_name: The name of the table.
112
114
  :param column_name: The column to retrieve unique values from.
113
115
  :return: A list of unique values.
@@ -115,7 +117,7 @@ class DataManager:
115
117
  query = f"SELECT DISTINCT {column_name} FROM {table_name}"
116
118
  self._cursor.execute(query)
117
119
  return [row[0] for row in self._cursor.fetchall()]
118
-
120
+
119
121
  def get_current_collector_materials(self, most_recent: bool = True) -> pd.DataFrame:
120
122
  """
121
123
  Retrieves current collector materials from the database.
@@ -123,15 +125,19 @@ class DataManager:
123
125
  :param most_recent: If True, returns only the most recent entry.
124
126
  :return: DataFrame with current collector materials.
125
127
  """
126
- data = (self
127
- .get_data(table_name='current_collector_materials')
128
- .groupby('name', group_keys=False)
129
- .apply(lambda x: x.sort_values('date', ascending=False).head(1) if most_recent else x)
130
- .reset_index(drop=True)
131
- )
132
-
128
+ data = (
129
+ self.get_data(table_name="current_collector_materials")
130
+ .groupby("name", group_keys=False)
131
+ .apply(
132
+ lambda x: x.sort_values("date", ascending=False).head(1)
133
+ if most_recent
134
+ else x
135
+ )
136
+ .reset_index(drop=True)
137
+ )
138
+
133
139
  return data
134
-
140
+
135
141
  def get_insulation_materials(self, most_recent: bool = True) -> pd.DataFrame:
136
142
  """
137
143
  Retrieves insulation materials from the database.
@@ -140,18 +146,16 @@ class DataManager:
140
146
  :return: DataFrame with insulation materials.
141
147
  """
142
148
  data = (
143
- self
144
- .get_data(
145
- table_name='insulation_materials'
146
- ).groupby(
147
- 'name', group_keys=False
148
- ).apply(
149
- lambda x: x.sort_values('date', ascending=False).head(1) if most_recent else x
150
- ).reset_index(
151
- drop=True
149
+ self.get_data(table_name="insulation_materials")
150
+ .groupby("name", group_keys=False)
151
+ .apply(
152
+ lambda x: x.sort_values("date", ascending=False).head(1)
153
+ if most_recent
154
+ else x
152
155
  )
153
- )
154
-
156
+ .reset_index(drop=True)
157
+ )
158
+
155
159
  return data
156
160
 
157
161
  def get_cathode_materials(self, most_recent: bool = True) -> pd.DataFrame:
@@ -162,21 +166,18 @@ class DataManager:
162
166
  :return: DataFrame with cathode materials.
163
167
  """
164
168
  data = (
165
- self
166
- .get_data(
167
- table_name='cathode_materials'
168
- ).groupby(
169
- 'name',
170
- group_keys=False
171
- ).apply(
172
- lambda x: x.sort_values('date', ascending=False).head(1) if most_recent else x
173
- ).reset_index(
174
- drop=True
169
+ self.get_data(table_name="cathode_materials")
170
+ .groupby("name", group_keys=False)
171
+ .apply(
172
+ lambda x: x.sort_values("date", ascending=False).head(1)
173
+ if most_recent
174
+ else x
175
175
  )
176
- )
177
-
176
+ .reset_index(drop=True)
177
+ )
178
+
178
179
  return data
179
-
180
+
180
181
  def get_anode_materials(self, most_recent: bool = True) -> pd.DataFrame:
181
182
  """
182
183
  Retrieves anode materials from the database.
@@ -185,21 +186,18 @@ class DataManager:
185
186
  :return: DataFrame with anode materials.
186
187
  """
187
188
  data = (
188
- self
189
- .get_data(
190
- table_name='anode_materials'
191
- ).groupby(
192
- 'name',
193
- group_keys=False
194
- ).apply(
195
- lambda x: x.sort_values('date', ascending=False).head(1) if most_recent else x
196
- ).reset_index(
197
- drop=True
189
+ self.get_data(table_name="anode_materials")
190
+ .groupby("name", group_keys=False)
191
+ .apply(
192
+ lambda x: x.sort_values("date", ascending=False).head(1)
193
+ if most_recent
194
+ else x
198
195
  )
199
- )
200
-
196
+ .reset_index(drop=True)
197
+ )
198
+
201
199
  return data
202
-
200
+
203
201
  def get_binder_materials(self, most_recent: bool = True) -> pd.DataFrame:
204
202
  """
205
203
  Retrieves binder materials from the database.
@@ -208,22 +206,21 @@ class DataManager:
208
206
  :return: DataFrame with binder materials.
209
207
  """
210
208
  data = (
211
- self
212
- .get_data(
213
- table_name='binder_materials'
214
- ).groupby(
215
- 'name',
216
- group_keys=False
217
- ).apply(
218
- lambda x: x.sort_values('date', ascending=False).head(1) if most_recent else x
219
- ).reset_index(
220
- drop=True
209
+ self.get_data(table_name="binder_materials")
210
+ .groupby("name", group_keys=False)
211
+ .apply(
212
+ lambda x: x.sort_values("date", ascending=False).head(1)
213
+ if most_recent
214
+ else x
221
215
  )
222
- )
223
-
216
+ .reset_index(drop=True)
217
+ )
218
+
224
219
  return data
225
-
226
- def get_conductive_additive_materials(self, most_recent: bool = True) -> pd.DataFrame:
220
+
221
+ def get_conductive_additive_materials(
222
+ self, most_recent: bool = True
223
+ ) -> pd.DataFrame:
227
224
  """
228
225
  Retrieves conductive additives from the database.
229
226
 
@@ -231,19 +228,16 @@ class DataManager:
231
228
  :return: DataFrame with conductive additives.
232
229
  """
233
230
  data = (
234
- self
235
- .get_data(
236
- table_name='conductive_additive_materials'
237
- ).groupby(
238
- 'name',
239
- group_keys=False
240
- ).apply(
241
- lambda x: x.sort_values('date', ascending=False).head(1) if most_recent else x
242
- ).reset_index(
243
- drop=True
231
+ self.get_data(table_name="conductive_additive_materials")
232
+ .groupby("name", group_keys=False)
233
+ .apply(
234
+ lambda x: x.sort_values("date", ascending=False).head(1)
235
+ if most_recent
236
+ else x
244
237
  )
245
- )
246
-
238
+ .reset_index(drop=True)
239
+ )
240
+
247
241
  return data
248
242
 
249
243
  def get_separator_materials(self, most_recent: bool = True) -> pd.DataFrame:
@@ -254,19 +248,16 @@ class DataManager:
254
248
  :return: DataFrame with separator materials.
255
249
  """
256
250
  data = (
257
- self
258
- .get_data(
259
- table_name='separator_materials'
260
- ).groupby(
261
- 'name',
262
- group_keys=False
263
- ).apply(
264
- lambda x: x.sort_values('date', ascending=False).head(1) if most_recent else x
265
- ).reset_index(
266
- drop=True
251
+ self.get_data(table_name="separator_materials")
252
+ .groupby("name", group_keys=False)
253
+ .apply(
254
+ lambda x: x.sort_values("date", ascending=False).head(1)
255
+ if most_recent
256
+ else x
267
257
  )
268
- )
269
-
258
+ .reset_index(drop=True)
259
+ )
260
+
270
261
  return data
271
262
 
272
263
  @staticmethod
@@ -281,27 +272,39 @@ class DataManager:
281
272
  data = pd.read_csv(half_cell_path)
282
273
  except:
283
274
  raise FileNotFoundError(f"Could not find the file at {half_cell_path}")
284
-
285
- if 'Specific Capacity (mAh/g)' not in data.columns:
286
- raise ValueError("The file must have a column named 'Specific Capacity (mAh/g)'")
287
-
288
- if 'Voltage (V)' not in data.columns:
275
+
276
+ if "Specific Capacity (mAh/g)" not in data.columns:
277
+ raise ValueError(
278
+ "The file must have a column named 'Specific Capacity (mAh/g)'"
279
+ )
280
+
281
+ if "Voltage (V)" not in data.columns:
289
282
  raise ValueError("The file must have a column named 'Voltage (V)'")
290
-
291
- if 'Step_ID' not in data.columns:
283
+
284
+ if "Step_ID" not in data.columns:
292
285
  raise ValueError("The file must have a column named 'Step_ID'")
293
-
294
- data = (data
295
- .rename(columns={'Specific Capacity (mAh/g)': 'specific_capacity', 'Voltage (V)': 'voltage', 'Step_ID': 'step_id'})
296
- .assign(specific_capacity=lambda x: x['specific_capacity'] * (H_TO_S * mA_TO_A / G_TO_KG))
297
- .filter(['specific_capacity', 'voltage', 'step_id'])
298
- .groupby(['specific_capacity', 'step_id'], group_keys=False)['voltage'].max()
299
- .reset_index()
300
- .sort_values(['step_id', 'specific_capacity'])
301
- )
286
+
287
+ data = (
288
+ data.rename(
289
+ columns={
290
+ "Specific Capacity (mAh/g)": "specific_capacity",
291
+ "Voltage (V)": "voltage",
292
+ "Step_ID": "step_id",
293
+ }
294
+ )
295
+ .assign(
296
+ specific_capacity=lambda x: x["specific_capacity"]
297
+ * (H_TO_S * mA_TO_A / G_TO_KG)
298
+ )
299
+ .filter(["specific_capacity", "voltage", "step_id"])
300
+ .groupby(["specific_capacity", "step_id"], group_keys=False)["voltage"]
301
+ .max()
302
+ .reset_index()
303
+ .sort_values(["step_id", "specific_capacity"])
304
+ )
302
305
 
303
306
  return data
304
-
307
+
305
308
  def remove_data(self, table_name: str, condition: str):
306
309
  """
307
310
  Function to remove data from the database.
@@ -311,8 +314,6 @@ class DataManager:
311
314
  """
312
315
  self._cursor.execute(f"DELETE FROM {table_name} WHERE {condition}")
313
316
  self._connection.commit()
314
-
317
+
315
318
  def __del__(self):
316
319
  self._connection.close()
317
-
318
-
@@ -6,12 +6,14 @@ def calculate_coordinates(func):
6
6
  Decorator to recalculate spatial properties after a method call.
7
7
  This is useful for methods that modify the geometry of a component.
8
8
  """
9
+
9
10
  @wraps(func)
10
11
  def wrapper(self, *args, **kwargs):
11
12
  result = func(self, *args, **kwargs)
12
- if hasattr(self, '_update_properties') and self._update_properties:
13
+ if hasattr(self, "_update_properties") and self._update_properties:
13
14
  self._calculate_coordinates()
14
15
  return result
16
+
15
17
  return wrapper
16
18
 
17
19
 
@@ -20,13 +22,15 @@ def calculate_areas(func):
20
22
  Decorator to recalculate areas after a method call.
21
23
  This is useful for methods that modify the geometry of a component.
22
24
  """
25
+
23
26
  @wraps(func)
24
27
  def wrapper(self, *args, **kwargs):
25
28
  result = func(self, *args, **kwargs)
26
- if hasattr(self, '_update_properties') and self._update_properties:
29
+ if hasattr(self, "_update_properties") and self._update_properties:
27
30
  self._calculate_coordinates()
28
31
  self._calculate_areas()
29
32
  return result
33
+
30
34
  return wrapper
31
35
 
32
36
 
@@ -35,12 +39,13 @@ def calculate_volumes(func):
35
39
  Decorator to recalculate volumes after a method call.
36
40
  This is useful for methods that modify the geometry of a component.
37
41
  """
42
+
38
43
  @wraps(func)
39
44
  def wrapper(self, *args, **kwargs):
40
45
  result = func(self, *args, **kwargs)
41
- if hasattr(self, '_update_properties') and self._update_properties:
46
+ if hasattr(self, "_update_properties") and self._update_properties:
42
47
  self._calculate_bulk_properties()
43
48
  self._calculate_coordinates()
44
49
  return result
45
- return wrapper
46
50
 
51
+ return wrapper
@@ -1,16 +1,19 @@
1
1
  from functools import wraps
2
2
 
3
+
3
4
  def calculate_half_cell_curve(func):
4
5
  """
5
6
  Decorator to recalculate half-cell curve properties after a method call.
6
7
  This is useful for methods that modify the half-cell curve data.
7
8
  """
9
+
8
10
  @wraps(func)
9
11
  def wrapper(self, *args, **kwargs):
10
12
  result = func(self, *args, **kwargs)
11
- if hasattr(self, '_update_properties') and self._update_properties:
13
+ if hasattr(self, "_update_properties") and self._update_properties:
12
14
  self._calculate_half_cell_curve()
13
15
  return result
16
+
14
17
  return wrapper
15
18
 
16
19
 
@@ -19,10 +22,12 @@ def calculate_half_cell_curves_properties(func):
19
22
  Decorator to recalculate half-cell curves properties after a method call.
20
23
  This is useful for methods that modify the half-cell curves data.
21
24
  """
25
+
22
26
  @wraps(func)
23
27
  def wrapper(self, *args, **kwargs):
24
28
  result = func(self, *args, **kwargs)
25
- if hasattr(self, '_update_properties') and self._update_properties:
29
+ if hasattr(self, "_update_properties") and self._update_properties:
26
30
  self._calculate_half_cell_curves_properties()
27
31
  return result
32
+
28
33
  return wrapper
@@ -1,16 +1,19 @@
1
1
  from functools import wraps
2
2
 
3
+
3
4
  def calculate_bulk_properties(func):
4
5
  """
5
6
  Decorator to recalculate bulk properties after a method call.
6
7
  This is useful for methods that modify the material properties.
7
8
  """
9
+
8
10
  @wraps(func)
9
11
  def wrapper(self, *args, **kwargs):
10
12
  result = func(self, *args, **kwargs)
11
- if hasattr(self, '_update_properties') and self._update_properties:
13
+ if hasattr(self, "_update_properties") and self._update_properties:
12
14
  self._calculate_bulk_properties()
13
15
  return result
16
+
14
17
  return wrapper
15
18
 
16
19
 
@@ -19,12 +22,12 @@ def calculate_all_properties(func):
19
22
  Decorator to recalculate both spatial and bulk properties after a method call.
20
23
  This is useful for methods that modify both geometry and material properties.
21
24
  """
25
+
22
26
  @wraps(func)
23
27
  def wrapper(self, *args, **kwargs):
24
28
  result = func(self, *args, **kwargs)
25
- if hasattr(self, '_update_properties') and self._update_properties:
29
+ if hasattr(self, "_update_properties") and self._update_properties:
26
30
  self._calculate_all_properties()
27
31
  return result
28
- return wrapper
29
-
30
32
 
33
+ return wrapper
@@ -1,14 +1,17 @@
1
1
  from functools import wraps
2
2
 
3
+
3
4
  def calculate_weld_tab_properties(func):
4
5
  """
5
6
  Decorator to recalculate weld tab properties after a method call.
6
7
  This is useful for methods that modify the weld tab geometry or material.
7
8
  """
9
+
8
10
  @wraps(func)
9
11
  def wrapper(self, *args, **kwargs):
10
12
  result = func(self, *args, **kwargs)
11
- if hasattr(self, '_update_properties') and self._update_properties:
13
+ if hasattr(self, "_update_properties") and self._update_properties:
12
14
  self._calculate_weld_tab_properties()
13
15
  return result
16
+
14
17
  return wrapper