pastastore 1.11.0__py3-none-any.whl → 1.12.1__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.
- docs/conf.py +10 -97
- pastastore/base.py +171 -37
- pastastore/connectors.py +151 -25
- pastastore/datasets.py +0 -4
- pastastore/store.py +17 -5
- pastastore/styling.py +4 -2
- pastastore/util.py +3 -0
- pastastore/validator.py +53 -3
- pastastore/version.py +2 -2
- {pastastore-1.11.0.dist-info → pastastore-1.12.1.dist-info}/METADATA +4 -4
- pastastore-1.12.1.dist-info/RECORD +31 -0
- {pastastore-1.11.0.dist-info → pastastore-1.12.1.dist-info}/WHEEL +1 -1
- tests/conftest.py +153 -51
- tests/test_003_pastastore.py +3 -1
- tests/test_009_parallel.py +393 -0
- pastastore-1.11.0.dist-info/RECORD +0 -30
- {pastastore-1.11.0.dist-info → pastastore-1.12.1.dist-info}/licenses/LICENSE +0 -0
- {pastastore-1.11.0.dist-info → pastastore-1.12.1.dist-info}/top_level.txt +0 -0
docs/conf.py
CHANGED
|
@@ -53,8 +53,7 @@ extensions = [
|
|
|
53
53
|
"sphinx.ext.viewcode",
|
|
54
54
|
"IPython.sphinxext.ipython_console_highlighting", # lowercase didn't work
|
|
55
55
|
"sphinx.ext.autosectionlabel",
|
|
56
|
-
"
|
|
57
|
-
"nbsphinx_link",
|
|
56
|
+
"myst_nb",
|
|
58
57
|
]
|
|
59
58
|
|
|
60
59
|
# Add any paths that contain templates here, relative to this directory.
|
|
@@ -114,102 +113,16 @@ html_theme_options = {
|
|
|
114
113
|
# Add any paths that contain custom static files (such as style sheets) here,
|
|
115
114
|
# relative to this directory. They are copied after the builtin static files,
|
|
116
115
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
|
117
|
-
html_static_path = ["_static"]
|
|
116
|
+
# html_static_path = ["_static"]
|
|
118
117
|
|
|
119
|
-
# Custom sidebar templates, must be a dictionary that maps document names
|
|
120
|
-
# to template names.
|
|
121
|
-
#
|
|
122
|
-
# The default sidebars (for documents that don't match any pattern) are
|
|
123
|
-
# defined by theme itself. Builtin themes are using these templates by
|
|
124
|
-
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
|
|
125
|
-
# 'searchbox.html']``.
|
|
126
|
-
#
|
|
127
|
-
# html_sidebars = {}
|
|
128
|
-
|
|
129
|
-
# -- Options for HTMLHelp output ---------------------------------------------
|
|
130
|
-
|
|
131
|
-
# Output file base name for HTML help builder.
|
|
132
|
-
htmlhelp_basename = "pastastoredoc"
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
# -- Options for LaTeX output ------------------------------------------------
|
|
136
|
-
|
|
137
|
-
latex_elements = {
|
|
138
|
-
# The paper size ('letterpaper' or 'a4paper').
|
|
139
|
-
#
|
|
140
|
-
# 'papersize': 'letterpaper',
|
|
141
|
-
# The font size ('10pt', '11pt' or '12pt').
|
|
142
|
-
#
|
|
143
|
-
# 'pointsize': '10pt',
|
|
144
|
-
# Additional stuff for the LaTeX preamble.
|
|
145
|
-
#
|
|
146
|
-
"preamble": r"""\makeatletter
|
|
147
|
-
\def\UTFviii@defined#1{%
|
|
148
|
-
\ifx#1\relax
|
|
149
|
-
-%
|
|
150
|
-
\else\expandafter
|
|
151
|
-
#1%
|
|
152
|
-
\fi
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
\makeatother""",
|
|
156
|
-
# Latex figure (float) alignment
|
|
157
|
-
#
|
|
158
|
-
# 'figure_align': 'htbp',
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
# Grouping the document tree into LaTeX files. List of tuples
|
|
162
|
-
# (source start file, target name, title,
|
|
163
|
-
# author, documentclass [howto, manual, or own class]).
|
|
164
|
-
latex_documents = [
|
|
165
|
-
(
|
|
166
|
-
master_doc,
|
|
167
|
-
"pastastore.tex",
|
|
168
|
-
"pastastore Documentation",
|
|
169
|
-
"D.A. Brakenhoff",
|
|
170
|
-
"manual",
|
|
171
|
-
),
|
|
172
|
-
]
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
# -- Options for manual page output ------------------------------------------
|
|
176
|
-
|
|
177
|
-
# One entry per manual page. List of tuples
|
|
178
|
-
# (source start file, name, description, authors, manual section).
|
|
179
|
-
man_pages = [(master_doc, "pastastore", "pastastore Documentation", [author], 1)]
|
|
180
118
|
|
|
119
|
+
# -- myst_nb options ------------------------------------------------------------------
|
|
181
120
|
|
|
182
|
-
#
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
# (source start file, target name, title, author,
|
|
186
|
-
# dir menu entry, description, category)
|
|
187
|
-
texinfo_documents = [
|
|
188
|
-
(
|
|
189
|
-
master_doc,
|
|
190
|
-
"pastastore",
|
|
191
|
-
"pastastore Documentation",
|
|
192
|
-
author,
|
|
193
|
-
"pastastore",
|
|
194
|
-
"Tools for managing time series and Pastas models",
|
|
195
|
-
"Miscellaneous",
|
|
196
|
-
),
|
|
197
|
-
]
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
# -- Options for Epub output -------------------------------------------------
|
|
201
|
-
|
|
202
|
-
# Bibliographic Dublin Core info.
|
|
203
|
-
epub_title = project
|
|
204
|
-
|
|
205
|
-
# The unique identifier of the text. This can be a ISBN number
|
|
206
|
-
# or the project homepage.
|
|
207
|
-
#
|
|
208
|
-
# epub_identifier = ''
|
|
209
|
-
|
|
210
|
-
# A unique identification for the text.
|
|
211
|
-
#
|
|
212
|
-
# epub_uid = ''
|
|
121
|
+
nb_execution_allow_errors = True # Allow errors in notebooks, to see the error online
|
|
122
|
+
nb_execution_mode = "off"
|
|
123
|
+
nb_merge_streams = True
|
|
213
124
|
|
|
214
|
-
|
|
215
|
-
|
|
125
|
+
myst_enable_extensions = ["dollarmath", "amsmath"]
|
|
126
|
+
myst_dmath_double_inline = True
|
|
127
|
+
nb_render_markdown_format = "myst" # Enable MyST markdown parsing in notebooks
|
|
128
|
+
nb_render_text_lexer = "myst-ansi" # Better rendering of ANSI output
|
pastastore/base.py
CHANGED
|
@@ -164,7 +164,7 @@ class ConnectorUtil:
|
|
|
164
164
|
for stress in ts["stress"]:
|
|
165
165
|
if "series" not in stress:
|
|
166
166
|
name = str(stress["name"])
|
|
167
|
-
if
|
|
167
|
+
if self._item_exists("stresses", name):
|
|
168
168
|
stress["series"] = self.get_stresses(name).squeeze()
|
|
169
169
|
# update tmin/tmax from time series
|
|
170
170
|
if update_ts_settings:
|
|
@@ -179,7 +179,7 @@ class ConnectorUtil:
|
|
|
179
179
|
for stress in ts["stress"] if PASFILE_LEQ_022 else [ts["stress"]]:
|
|
180
180
|
if "series" not in stress:
|
|
181
181
|
name = str(stress["name"])
|
|
182
|
-
if
|
|
182
|
+
if self._item_exists("stresses", name):
|
|
183
183
|
stress["series"] = self.get_stresses(name).squeeze()
|
|
184
184
|
# update tmin/tmax from time series
|
|
185
185
|
if update_ts_settings:
|
|
@@ -195,7 +195,7 @@ class ConnectorUtil:
|
|
|
195
195
|
for stress in [ts["prec"], ts["evap"]]:
|
|
196
196
|
if "series" not in stress:
|
|
197
197
|
name = str(stress["name"])
|
|
198
|
-
if
|
|
198
|
+
if self._item_exists("stresses", name):
|
|
199
199
|
stress["series"] = self.get_stresses(name).squeeze()
|
|
200
200
|
# update tmin/tmax from time series
|
|
201
201
|
if update_ts_settings:
|
|
@@ -250,6 +250,29 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
250
250
|
_conn_type: Optional[str] = None
|
|
251
251
|
_validator: Optional[Validator] = None
|
|
252
252
|
name = None
|
|
253
|
+
_added_models = [] # internal list of added models used for updating links
|
|
254
|
+
|
|
255
|
+
def __getstate__(self):
|
|
256
|
+
"""Replace Manager proxies with simple values for pickling.
|
|
257
|
+
|
|
258
|
+
Manager proxies cannot be pickled, so we convert them to simple booleans.
|
|
259
|
+
This allows connectors to be pickled for multiprocessing.
|
|
260
|
+
"""
|
|
261
|
+
state = self.__dict__.copy()
|
|
262
|
+
# Replace unpicklable Manager proxies with their values
|
|
263
|
+
state["_oseries_links_need_update"] = self._oseries_links_need_update.value
|
|
264
|
+
state["_stresses_links_need_update"] = self._stresses_links_need_update.value
|
|
265
|
+
return state
|
|
266
|
+
|
|
267
|
+
def __setstate__(self, state):
|
|
268
|
+
"""Replace Manager proxies with simple booleans after unpickling.
|
|
269
|
+
|
|
270
|
+
After unpickling, use simple booleans instead of recreating Manager.
|
|
271
|
+
This works because worker processes don't need shared memory - they
|
|
272
|
+
work on independent copies of the connector.
|
|
273
|
+
"""
|
|
274
|
+
self.__dict__.update(state)
|
|
275
|
+
# Flags are already simple booleans from __getstate__
|
|
253
276
|
|
|
254
277
|
def __repr__(self):
|
|
255
278
|
"""Representation string of the object."""
|
|
@@ -390,6 +413,10 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
390
413
|
def _list_symbols(self, libname: AllLibs) -> List[str]:
|
|
391
414
|
"""Return list of symbol names in library."""
|
|
392
415
|
|
|
416
|
+
@abstractmethod
|
|
417
|
+
def _item_exists(self, libname: AllLibs, name: str) -> bool:
|
|
418
|
+
"""Return True if item present in library, else False."""
|
|
419
|
+
|
|
393
420
|
@property
|
|
394
421
|
def oseries_names(self):
|
|
395
422
|
"""List of oseries names.
|
|
@@ -420,6 +447,7 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
420
447
|
|
|
421
448
|
Property must be overridden by subclass.
|
|
422
449
|
"""
|
|
450
|
+
self._trigger_links_update_if_needed()
|
|
423
451
|
return self._list_symbols("oseries_models")
|
|
424
452
|
|
|
425
453
|
@property
|
|
@@ -428,6 +456,7 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
428
456
|
|
|
429
457
|
Property must be overridden by subclass.
|
|
430
458
|
"""
|
|
459
|
+
self._trigger_links_update_if_needed()
|
|
431
460
|
return self._list_symbols("stresses_models")
|
|
432
461
|
|
|
433
462
|
@abstractmethod
|
|
@@ -552,6 +581,7 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
552
581
|
dictionary with oseries names as keys and list of model names as
|
|
553
582
|
values
|
|
554
583
|
"""
|
|
584
|
+
self._trigger_links_update_if_needed()
|
|
555
585
|
d = {}
|
|
556
586
|
for onam in self.oseries_with_models:
|
|
557
587
|
d[onam] = self._get_item("oseries_models", onam)
|
|
@@ -568,6 +598,7 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
568
598
|
dictionary with stress names as keys and list of model names as
|
|
569
599
|
values
|
|
570
600
|
"""
|
|
601
|
+
self._trigger_links_update_if_needed()
|
|
571
602
|
d = {}
|
|
572
603
|
for stress_name in self.stresses_with_models:
|
|
573
604
|
d[stress_name] = self._get_item("stresses_models", stress_name)
|
|
@@ -608,6 +639,8 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
608
639
|
"""
|
|
609
640
|
if not isinstance(name, str):
|
|
610
641
|
name = str(name)
|
|
642
|
+
if metadata:
|
|
643
|
+
self.validator.validate_metadata(metadata)
|
|
611
644
|
self.validator.validate_input_series(series)
|
|
612
645
|
series = self.validator.set_series_name(series, name)
|
|
613
646
|
if self.validator.pastas_validation_status(validate):
|
|
@@ -631,8 +664,8 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
631
664
|
if name not in in_store or overwrite:
|
|
632
665
|
self._add_item(libname, series, name, metadata=metadata)
|
|
633
666
|
self._clear_cache(libname)
|
|
634
|
-
elif (libname == "oseries" and
|
|
635
|
-
libname == "stresses" and
|
|
667
|
+
elif (libname == "oseries" and self._item_exists("oseries_models", name)) or (
|
|
668
|
+
libname == "stresses" and self._item_exists("stresses_models", name)
|
|
636
669
|
):
|
|
637
670
|
raise SeriesUsedByModel(
|
|
638
671
|
f"Time series with name '{name}' is used by a model! "
|
|
@@ -881,7 +914,7 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
881
914
|
raise TypeError("Expected pastas.Model or dict!")
|
|
882
915
|
if not isinstance(name, str):
|
|
883
916
|
name = str(name)
|
|
884
|
-
if
|
|
917
|
+
if not self._item_exists("models", name) or overwrite:
|
|
885
918
|
# check if stressmodels supported
|
|
886
919
|
self.validator.check_stressmodels_supported(ml)
|
|
887
920
|
# check oseries and stresses names and if they exist in store
|
|
@@ -891,8 +924,20 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
891
924
|
# write model to store
|
|
892
925
|
self._add_item("models", mldict, name, metadata=metadata)
|
|
893
926
|
self._clear_cache("_modelnames_cache")
|
|
894
|
-
|
|
895
|
-
|
|
927
|
+
# avoid updating links so parallel operations do not simultaneously
|
|
928
|
+
# access the same object. Indicate that these links need updating and
|
|
929
|
+
# clear existing caches. Handle both Manager proxies and booleans
|
|
930
|
+
if hasattr(self._oseries_links_need_update, "value"):
|
|
931
|
+
self._oseries_links_need_update.value = True
|
|
932
|
+
self._stresses_links_need_update.value = True
|
|
933
|
+
# this won't update main instance in parallel
|
|
934
|
+
self._added_models.append(name)
|
|
935
|
+
else:
|
|
936
|
+
self._oseries_links_need_update = True
|
|
937
|
+
self._stresses_links_need_update = True
|
|
938
|
+
self._added_models.append(name)
|
|
939
|
+
self._clear_cache("oseries_models")
|
|
940
|
+
self._clear_cache("stresses_models")
|
|
896
941
|
else:
|
|
897
942
|
raise ItemInLibraryException(
|
|
898
943
|
f"Model with name '{name}' already in 'models' library! "
|
|
@@ -1072,8 +1117,12 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
1072
1117
|
mldict = self.get_models(n, return_dict=True)
|
|
1073
1118
|
oname = mldict["oseries"]["name"]
|
|
1074
1119
|
self._del_item("models", n)
|
|
1075
|
-
|
|
1076
|
-
self.
|
|
1120
|
+
# delete reference to added model if present
|
|
1121
|
+
if n in self._added_models:
|
|
1122
|
+
self._added_models.remove(n)
|
|
1123
|
+
else:
|
|
1124
|
+
self._del_oseries_model_link(oname, n)
|
|
1125
|
+
self._del_stress_model_link(self._get_model_stress_names(mldict), n)
|
|
1077
1126
|
self._clear_cache("_modelnames_cache")
|
|
1078
1127
|
if verbose:
|
|
1079
1128
|
logger.info("Deleted %d model(s) from database.", len(names))
|
|
@@ -1125,7 +1174,7 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
1125
1174
|
)
|
|
1126
1175
|
self.del_models(modelnames, verbose=verbose)
|
|
1127
1176
|
if verbose:
|
|
1128
|
-
logger.info("Deleted %d
|
|
1177
|
+
logger.info("Deleted %d model(s) from database.", len(modelnames))
|
|
1129
1178
|
|
|
1130
1179
|
def del_stress(
|
|
1131
1180
|
self,
|
|
@@ -1160,7 +1209,7 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
1160
1209
|
)
|
|
1161
1210
|
self.del_models(modelnames, verbose=verbose)
|
|
1162
1211
|
if verbose:
|
|
1163
|
-
logger.info("Deleted %d
|
|
1212
|
+
logger.info("Deleted %d model(s) from database.", len(modelnames))
|
|
1164
1213
|
|
|
1165
1214
|
def _get_series(
|
|
1166
1215
|
self,
|
|
@@ -1485,8 +1534,8 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
1485
1534
|
return
|
|
1486
1535
|
|
|
1487
1536
|
if libname == "models":
|
|
1488
|
-
# also delete linked modelnames linked to oseries
|
|
1489
|
-
libs = ["models", "oseries_models"]
|
|
1537
|
+
# also delete linked modelnames linked to oseries and stresses
|
|
1538
|
+
libs = ["models", "oseries_models", "stresses_models"]
|
|
1490
1539
|
else:
|
|
1491
1540
|
libs = [libname]
|
|
1492
1541
|
|
|
@@ -1583,7 +1632,10 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
1583
1632
|
yield self.get_models(mlnam, return_dict=return_dict, progressbar=False)
|
|
1584
1633
|
|
|
1585
1634
|
def _add_oseries_model_links(
|
|
1586
|
-
self,
|
|
1635
|
+
self,
|
|
1636
|
+
oseries_name: str,
|
|
1637
|
+
model_names: Union[str, List[str]],
|
|
1638
|
+
_clear_cache: bool = True,
|
|
1587
1639
|
):
|
|
1588
1640
|
"""Add model name to stored list of models per oseries.
|
|
1589
1641
|
|
|
@@ -1594,9 +1646,12 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
1594
1646
|
model_names : Union[str, List[str]]
|
|
1595
1647
|
model name or list of model names for an oseries with name
|
|
1596
1648
|
oseries_name.
|
|
1649
|
+
_clear_cache : bool, optional
|
|
1650
|
+
whether to clear the cache after adding, by default True.
|
|
1651
|
+
Set to False during bulk operations to improve performance.
|
|
1597
1652
|
"""
|
|
1598
1653
|
# get stored list of model names
|
|
1599
|
-
if
|
|
1654
|
+
if self._item_exists("oseries_models", oseries_name):
|
|
1600
1655
|
modellist = self._get_item("oseries_models", oseries_name)
|
|
1601
1656
|
else:
|
|
1602
1657
|
# else empty list
|
|
@@ -1610,9 +1665,12 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
1610
1665
|
if iml not in modellist:
|
|
1611
1666
|
modellist.append(iml)
|
|
1612
1667
|
self._add_item("oseries_models", modellist, oseries_name)
|
|
1613
|
-
|
|
1668
|
+
if _clear_cache:
|
|
1669
|
+
self._clear_cache("oseries_models")
|
|
1614
1670
|
|
|
1615
|
-
def _add_stresses_model_links(
|
|
1671
|
+
def _add_stresses_model_links(
|
|
1672
|
+
self, stress_names, model_names, _clear_cache: bool = True
|
|
1673
|
+
):
|
|
1616
1674
|
"""Add model name to stored list of models per stress.
|
|
1617
1675
|
|
|
1618
1676
|
Parameters
|
|
@@ -1621,13 +1679,16 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
1621
1679
|
names of stresses
|
|
1622
1680
|
model_names : Union[str, List[str]]
|
|
1623
1681
|
model name or list of model names for a stress with name
|
|
1682
|
+
_clear_cache : bool, optional
|
|
1683
|
+
whether to clear the cache after adding, by default True.
|
|
1684
|
+
Set to False during bulk operations to improve performance.
|
|
1624
1685
|
"""
|
|
1625
1686
|
# if one model name, make list for loop
|
|
1626
1687
|
if isinstance(model_names, str):
|
|
1627
1688
|
model_names = [model_names]
|
|
1628
1689
|
for snam in stress_names:
|
|
1629
1690
|
# get stored list of model names
|
|
1630
|
-
if str(snam)
|
|
1691
|
+
if self._item_exists("stresses_models", str(snam)):
|
|
1631
1692
|
modellist = self._get_item("stresses_models", snam)
|
|
1632
1693
|
else:
|
|
1633
1694
|
# else empty list
|
|
@@ -1638,7 +1699,8 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
1638
1699
|
if iml not in modellist:
|
|
1639
1700
|
modellist.append(iml)
|
|
1640
1701
|
self._add_item("stresses_models", modellist, snam)
|
|
1641
|
-
|
|
1702
|
+
if _clear_cache:
|
|
1703
|
+
self._clear_cache("stresses_models")
|
|
1642
1704
|
|
|
1643
1705
|
def _del_oseries_model_link(self, onam, mlnam):
|
|
1644
1706
|
"""Delete model name from stored list of models per oseries.
|
|
@@ -1677,31 +1739,102 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
1677
1739
|
self._add_item("stresses_models", modellist, stress_name)
|
|
1678
1740
|
self._clear_cache("stresses_models")
|
|
1679
1741
|
|
|
1680
|
-
def _update_time_series_model_links(
|
|
1742
|
+
def _update_time_series_model_links(
|
|
1743
|
+
self,
|
|
1744
|
+
libraries: list[str] = None,
|
|
1745
|
+
modelnames: Optional[List[str]] = None,
|
|
1746
|
+
recompute: bool = True,
|
|
1747
|
+
progressbar: bool = False,
|
|
1748
|
+
):
|
|
1681
1749
|
"""Add all model names to reverse lookup time series dictionaries.
|
|
1682
1750
|
|
|
1683
1751
|
Used for old PastaStore versions, where relationship between time series and
|
|
1684
1752
|
models was not stored. If there are any models in the database and if the
|
|
1685
1753
|
oseries_models or stresses_models libraries are empty, loop through all models
|
|
1686
1754
|
to determine which time series are used in each model.
|
|
1755
|
+
|
|
1756
|
+
Parameters
|
|
1757
|
+
----------
|
|
1758
|
+
libraries : list of str, optional
|
|
1759
|
+
list of time series libraries to update model links for,
|
|
1760
|
+
by default None which will update both 'oseries' and 'stresses'
|
|
1761
|
+
modelnames : Optional[List[str]], optional
|
|
1762
|
+
list of model names to update links for, by default None
|
|
1763
|
+
recompute : bool, optional
|
|
1764
|
+
Indicate operation is an update/recompute of existing links,
|
|
1765
|
+
by default False
|
|
1766
|
+
progressbar : bool, optional
|
|
1767
|
+
show progressbar, by default True
|
|
1687
1768
|
"""
|
|
1688
1769
|
# get oseries_models and stresses_models libraries,
|
|
1689
1770
|
# if empty add all time series -> model links.
|
|
1771
|
+
if libraries is None:
|
|
1772
|
+
libraries = ["oseries", "stresses"]
|
|
1690
1773
|
if self.n_models > 0:
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1774
|
+
logger.debug("Updating time series -> models links in store.")
|
|
1775
|
+
links = self._get_time_series_model_links(
|
|
1776
|
+
modelnames=modelnames, recompute=recompute, progressbar=progressbar
|
|
1777
|
+
)
|
|
1778
|
+
for k in libraries:
|
|
1779
|
+
if recompute:
|
|
1780
|
+
desc = f"Updating {k}-models links"
|
|
1781
|
+
else:
|
|
1782
|
+
desc = f"Storing {k}-models links"
|
|
1783
|
+
for name, model_links in tqdm(
|
|
1784
|
+
links[k].items(),
|
|
1785
|
+
desc=desc,
|
|
1786
|
+
total=len(links[k]),
|
|
1787
|
+
disable=not progressbar,
|
|
1788
|
+
):
|
|
1789
|
+
if k == "oseries":
|
|
1790
|
+
self._add_oseries_model_links(
|
|
1791
|
+
name, model_links, _clear_cache=False
|
|
1792
|
+
)
|
|
1793
|
+
elif k == "stresses":
|
|
1794
|
+
self._add_stresses_model_links(
|
|
1795
|
+
[name], model_links, _clear_cache=False
|
|
1796
|
+
)
|
|
1797
|
+
# Clear caches after all updates are complete
|
|
1798
|
+
if "oseries" in libraries:
|
|
1799
|
+
self._clear_cache("oseries_models")
|
|
1800
|
+
if "stresses" in libraries:
|
|
1801
|
+
self._clear_cache("stresses_models")
|
|
1802
|
+
|
|
1803
|
+
def _trigger_links_update_if_needed(
|
|
1804
|
+
self, modelnames: Optional[list[str]] = None, progressbar: bool = False
|
|
1805
|
+
):
|
|
1806
|
+
# Check if time series-> model links need updating
|
|
1807
|
+
# Handle both Manager proxies (main) and booleans (worker after pickle)
|
|
1808
|
+
needs_update = (
|
|
1809
|
+
self._oseries_links_need_update.value
|
|
1810
|
+
if hasattr(self._oseries_links_need_update, "value")
|
|
1811
|
+
else self._oseries_links_need_update
|
|
1812
|
+
)
|
|
1813
|
+
if needs_update:
|
|
1814
|
+
self._clear_cache("_modelnames_cache")
|
|
1815
|
+
# Set BOTH flags to False BEFORE updating to prevent recursion
|
|
1816
|
+
# (update always recomputes both oseries and stresses links)
|
|
1817
|
+
if hasattr(self._oseries_links_need_update, "value"):
|
|
1818
|
+
self._oseries_links_need_update.value = False
|
|
1819
|
+
self._stresses_links_need_update.value = False
|
|
1820
|
+
else:
|
|
1821
|
+
self._oseries_links_need_update = False
|
|
1822
|
+
self._stresses_links_need_update = False
|
|
1823
|
+
modelnames = self._added_models
|
|
1824
|
+
if modelnames is None or len(modelnames) > 0:
|
|
1825
|
+
self._update_time_series_model_links(
|
|
1826
|
+
modelnames=modelnames, recompute=True, progressbar=progressbar
|
|
1827
|
+
)
|
|
1828
|
+
self._added_models = [] # reset list of added models
|
|
1829
|
+
else:
|
|
1830
|
+
self._added_models = [] # reset list of added models
|
|
1831
|
+
|
|
1832
|
+
def _get_time_series_model_links(
|
|
1833
|
+
self,
|
|
1834
|
+
modelnames: Optional[list[str]] = None,
|
|
1835
|
+
recompute: bool = False,
|
|
1836
|
+
progressbar: bool = True,
|
|
1837
|
+
) -> dict:
|
|
1705
1838
|
"""Get model names per oseries and stresses time series in a dictionary.
|
|
1706
1839
|
|
|
1707
1840
|
Returns
|
|
@@ -1714,9 +1847,10 @@ class BaseConnector(ABC, ConnectorUtil):
|
|
|
1714
1847
|
oseries_links = {}
|
|
1715
1848
|
stresses_links = {}
|
|
1716
1849
|
for mldict in tqdm(
|
|
1717
|
-
self.iter_models(return_dict=True),
|
|
1850
|
+
self.iter_models(modelnames=modelnames, return_dict=True),
|
|
1718
1851
|
total=self.n_models,
|
|
1719
|
-
desc="Get models per time series",
|
|
1852
|
+
desc=f"{'Recompute' if recompute else 'Get'} models per time series",
|
|
1853
|
+
disable=not progressbar,
|
|
1720
1854
|
):
|
|
1721
1855
|
mlnam = mldict["name"]
|
|
1722
1856
|
# oseries
|