sxs 2024.0.44__tar.gz → 2025.0.1__tar.gz
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.
- {sxs-2024.0.44 → sxs-2025.0.1}/CITATION.cff +2 -2
- {sxs-2024.0.44 → sxs-2025.0.1}/PKG-INFO +2 -1
- {sxs-2024.0.44 → sxs-2025.0.1}/pyproject.toml +1 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/__init__.py +1 -1
- sxs-2025.0.1/sxs/__version__.py +1 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/handlers.py +3 -19
- sxs-2025.0.1/sxs/metadata/__init__.py +2 -0
- sxs-2025.0.1/sxs/metadata/metadata.py +2 -0
- sxs-2025.0.1/sxs/metadata/metric.py +1 -0
- sxs-2025.0.1/sxs/simulations/local.py +1 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/simulations/simulation.py +19 -4
- sxs-2025.0.1/sxs/simulations/simulations.py +2 -0
- sxs-2025.0.1/sxs/utilities/downloads.py +2 -0
- sxs-2025.0.1/sxs/utilities/string_converters.py +1 -0
- sxs-2025.0.1/sxs/utilities/sxs_directories.py +69 -0
- sxs-2025.0.1/sxs/utilities/sxs_identifiers.py +2 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/zenodo/__init__.py +1 -11
- sxs-2024.0.44/sxs/__version__.py +0 -1
- sxs-2024.0.44/sxs/caltechdata/__init__.py +0 -342
- sxs-2024.0.44/sxs/caltechdata/catalog.py +0 -85
- sxs-2024.0.44/sxs/caltechdata/login.py +0 -506
- sxs-2024.0.44/sxs/metadata/__init__.py +0 -10
- sxs-2024.0.44/sxs/metadata/metadata.py +0 -641
- sxs-2024.0.44/sxs/metadata/metric.py +0 -152
- sxs-2024.0.44/sxs/simulations/local.py +0 -227
- sxs-2024.0.44/sxs/simulations/simulations.py +0 -573
- sxs-2024.0.44/sxs/utilities/downloads.py +0 -104
- sxs-2024.0.44/sxs/utilities/string_converters.py +0 -47
- sxs-2024.0.44/sxs/utilities/sxs_directories.py +0 -273
- sxs-2024.0.44/sxs/utilities/sxs_identifiers.py +0 -127
- {sxs-2024.0.44 → sxs-2025.0.1}/.codecov.yml +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/.github/dependabot.yml +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/.github/scripts/parse_bump_rule.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/.github/workflows/build.yml +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/.github/workflows/pr_rtd_link.yml +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/.gitignore +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/.readthedocs.yaml +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/LICENSE +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/README.md +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/api/catalog.md +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/api/horizons.md +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/api/load.md +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/api/metadata.md +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/api/simulation.md +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/api/simulations.md +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/api/time_series.md +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/api/waveforms.md +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/html/main.html +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/images/favicon.ico +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/index.md +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/javascript/mathjax.js +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/julia.md +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/mathematica.md +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/stylesheets/extra.css +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/tutorials/00-Introduction.ipynb +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/tutorials/01-Simulations_and_Metadata.ipynb +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/tutorials/02-Simulation.ipynb +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/tutorials/03-Horizons.ipynb +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/tutorials/04-Waveforms.ipynb +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/docs/tutorials/05-PreprocessingForFFTs.ipynb +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/mkdocs.yml +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/catalog/__init__.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/catalog/catalog.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/catalog/create.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/catalog/description.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/horizons/__init__.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/horizons/spec_horizons_h5.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/horizons/xor_multishuffle_bzip2.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/julia/GWFrames.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/julia/__init__.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/juliapkg.json +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/simulations/__init__.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/time_series.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/__init__.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/bitwise.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/decimation/__init__.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/decimation/greedy_spline.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/decimation/linear_bisection.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/decimation/peak_greed.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/decimation/suppression.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/dicts.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/files.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/formats.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/inspire.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/lvcnr/__init__.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/lvcnr/comparisons.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/lvcnr/conversion.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/lvcnr/dataset.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/lvcnr/horizons.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/lvcnr/metadata.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/lvcnr/waveform_amp_phase.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/lvcnr/waveforms.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/monotonicity.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/pretty_print.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/references/__init__.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/references/ads.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/references/arxiv.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/references/fairchild_report.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/references/inspire.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/references/journal_abbreviations.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/references/references.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/select.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/smooth_functions.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/utilities/url.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/waveforms/__init__.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/waveforms/alignment.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/waveforms/format_handlers/__init__.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/waveforms/format_handlers/grathena.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/waveforms/format_handlers/lvc.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/waveforms/format_handlers/nrar.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/waveforms/format_handlers/rotating_paired_diff_multishuffle_bzip2.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/waveforms/format_handlers/rotating_paired_xor_multishuffle_bzip2.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/waveforms/format_handlers/spectre_cce_v1.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/waveforms/memory.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/waveforms/mode_utilities.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/waveforms/transformations.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/waveforms/waveform_grid.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/waveforms/waveform_mixin.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/waveforms/waveform_modes.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/waveforms/waveform_signal.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/zenodo/api/__init__.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/zenodo/api/deposit.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/zenodo/api/login.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/zenodo/api/records.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/zenodo/catalog.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/zenodo/creators.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/zenodo/simannex.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/sxs/zenodo/surrogatemodeling.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/tests/__init__.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/tests/conftest.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/tests/test_catalog.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/tests/test_horizons.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/tests/test_julia.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/tests/test_loader.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/tests/test_metadata.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/tests/test_simulation.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/tests/test_time_series.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/tests/test_transformations.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/tests/test_utilities.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/tests/test_waveform_rotations.py +0 -0
- {sxs-2024.0.44 → sxs-2025.0.1}/tests/test_waveforms.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sxs
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2025.0.1
|
|
4
4
|
Summary: Interface to data produced by the Simulating eXtreme Spacetimes collaboration
|
|
5
5
|
Project-URL: Homepage, https://github.com/sxs-collaboration/sxs
|
|
6
6
|
Project-URL: Documentation, https://sxs.readthedocs.io/
|
|
@@ -46,6 +46,7 @@ Requires-Dist: quaternionic>=1.0.15
|
|
|
46
46
|
Requires-Dist: requests>=2.24.0
|
|
47
47
|
Requires-Dist: scipy>=1.13
|
|
48
48
|
Requires-Dist: spherical>=1.0.15
|
|
49
|
+
Requires-Dist: sxscatalog>=3.0.0a1
|
|
49
50
|
Requires-Dist: tqdm>=4.63.1
|
|
50
51
|
Requires-Dist: urllib3>=1.25.10
|
|
51
52
|
Provides-Extra: docs
|
|
@@ -28,7 +28,7 @@ from .waveforms import WaveformModes, WaveformModesDict, to_lvc_conventions #, W
|
|
|
28
28
|
from .waveforms import rotating_paired_xor_multishuffle_bzip2 as rpxmb
|
|
29
29
|
from .waveforms import rotating_paired_diff_multishuffle_bzip2 as rpdmb
|
|
30
30
|
from .waveforms import spectre_cce_v1
|
|
31
|
-
from . import catalog, metadata, horizons, waveforms, zenodo
|
|
31
|
+
from . import catalog, metadata, horizons, waveforms, zenodo
|
|
32
32
|
from .simulations import Simulation, Simulations, write_local_simulations, local_simulations
|
|
33
33
|
from .handlers import load, load_via_sxs_id, loadcontext, load_lvc
|
|
34
34
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2025.0.1"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Functions to facilitate generic handling of SXS-format data files"""
|
|
2
2
|
|
|
3
3
|
import contextlib
|
|
4
|
+
import sxscatalog
|
|
4
5
|
from . import waveforms, doi_url
|
|
5
6
|
|
|
6
7
|
|
|
@@ -280,25 +281,8 @@ def load(location, download=None, cache=None, progress=None, truepath=None, **kw
|
|
|
280
281
|
elif location == "catalog":
|
|
281
282
|
return Catalog.load(download=download)
|
|
282
283
|
|
|
283
|
-
elif location
|
|
284
|
-
return
|
|
285
|
-
download=download,
|
|
286
|
-
local=kwargs.get("local", False),
|
|
287
|
-
annex_dir=kwargs.get("annex_dir", None),
|
|
288
|
-
output_file=kwargs.get("output_file", None),
|
|
289
|
-
compute_md5=kwargs.get("compute_md5", False),
|
|
290
|
-
show_progress=kwargs.get("show_progress", False)
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
elif location == "dataframe":
|
|
294
|
-
return Simulations.load(
|
|
295
|
-
download=download,
|
|
296
|
-
local=kwargs.get("local", False),
|
|
297
|
-
annex_dir=kwargs.get("annex_dir", None),
|
|
298
|
-
output_file=kwargs.get("output_file", None),
|
|
299
|
-
compute_md5=kwargs.get("compute_md5", False),
|
|
300
|
-
show_progress=kwargs.get("show_progress", False)
|
|
301
|
-
).dataframe
|
|
284
|
+
elif location in ["simulations", "dataframe"]:
|
|
285
|
+
return sxscatalog.load(location, download=download, **kwargs)
|
|
302
286
|
|
|
303
287
|
elif sxs_id_version_lev_exact_re.match(location):
|
|
304
288
|
return Simulation(location, download=download, cache=cache, progress=progress, **kwargs)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from sxscatalog.metadata.metric import *
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from sxscatalog.simulations.local import *
|
|
@@ -124,9 +124,15 @@ def Simulation(location, *args, **kwargs):
|
|
|
124
124
|
metadata = Metadata(simulations[simulation_id])
|
|
125
125
|
series = simulations.dataframe.loc[simulation_id]
|
|
126
126
|
|
|
127
|
+
# If input_version is not the default, remove "files" from metadata
|
|
128
|
+
if input_version and input_version != max(metadata.get("DOI_versions", []), default=""):
|
|
129
|
+
metadata = type(metadata)({
|
|
130
|
+
key: value for key, value in metadata.items() if key != "files"
|
|
131
|
+
})
|
|
132
|
+
|
|
127
133
|
# Check if the specified version exists in the simulation catalog
|
|
128
134
|
if not hasattr(metadata, "DOI_versions"):
|
|
129
|
-
input_version = "v0.0"
|
|
135
|
+
input_version = "v0.0" # A fake version, to signal this sim doesn't know about DOIs
|
|
130
136
|
if input_version != "v0.0" and input_version not in metadata.DOI_versions:
|
|
131
137
|
raise ValueError(f"Version '{input_version}' not found in simulation catalog for '{simulation_id}'")
|
|
132
138
|
|
|
@@ -217,10 +223,14 @@ def Simulation(location, *args, **kwargs):
|
|
|
217
223
|
sim = Simulation_v1(
|
|
218
224
|
metadata, series, version, sxs_id_stem, sxs_id, url, files, lev_numbers, output_lev_number, location, *args, **kwargs
|
|
219
225
|
)
|
|
220
|
-
elif 2 <= version_number < 3.0
|
|
226
|
+
elif 2 <= version_number < 3.0:
|
|
221
227
|
sim = Simulation_v2(
|
|
222
228
|
metadata, series, version, sxs_id_stem, sxs_id, url, files, lev_numbers, output_lev_number, location, *args, **kwargs
|
|
223
229
|
)
|
|
230
|
+
elif 3 <= version_number < 4.0 or version == "v0.0":
|
|
231
|
+
sim = Simulation_v3(
|
|
232
|
+
metadata, series, version, sxs_id_stem, sxs_id, url, files, lev_numbers, output_lev_number, location, *args, **kwargs
|
|
233
|
+
)
|
|
224
234
|
else:
|
|
225
235
|
raise ValueError(f"Version '{version}' not yet supported")
|
|
226
236
|
sim.__file__ = str(sxs_directory("cache") / sxs_path_to_system_path(sim.sxs_id))
|
|
@@ -365,7 +375,7 @@ class SimulationBase:
|
|
|
365
375
|
dataframe = load("simulations").dataframe
|
|
366
376
|
metadata_metric = metadata_metric or MetadataMetric()
|
|
367
377
|
if drop_deprecated:
|
|
368
|
-
dataframe = dataframe[~dataframe
|
|
378
|
+
dataframe = dataframe[~dataframe["deprecated"]]
|
|
369
379
|
return dataframe.apply(
|
|
370
380
|
lambda m: sqrt(metadata_metric(self.metadata, m)),
|
|
371
381
|
axis=1
|
|
@@ -824,16 +834,21 @@ class Simulation_v2(SimulationBase):
|
|
|
824
834
|
json_location = self.files.get(json_path)["link"]
|
|
825
835
|
h5_truepath = Path(sxs_path_to_system_path(sxs_id_path / h5_path))
|
|
826
836
|
json_truepath = Path(sxs_path_to_system_path(sxs_id_path / json_path))
|
|
837
|
+
json_truepath = sxs_directory("cache") / json_truepath
|
|
827
838
|
if not Path(json_location).exists() and not json_truepath.exists():
|
|
828
839
|
if not read_config("download", True):
|
|
829
840
|
raise ValueError(f"{json_truepath} not found and download is disabled")
|
|
830
|
-
download_file(json_location,
|
|
841
|
+
download_file(json_location, json_truepath)
|
|
831
842
|
return load(
|
|
832
843
|
h5_location, truepath=h5_truepath, group=group, metadata=self.metadata,
|
|
833
844
|
transform_to_inertial=transform_to_inertial
|
|
834
845
|
)
|
|
835
846
|
|
|
836
847
|
|
|
848
|
+
class Simulation_v3(Simulation_v2):
|
|
849
|
+
pass
|
|
850
|
+
|
|
851
|
+
|
|
837
852
|
def get_file_info(metadata, sxs_id, download=None):
|
|
838
853
|
# TODO: Allow an existing zenodo_metadata.json file to be used
|
|
839
854
|
from .. import load_via_sxs_id
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from sxscatalog.utilities.string_converters import *
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Functions to find user-specific config and cache directories"""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
import platform
|
|
5
|
+
import functools
|
|
6
|
+
from sxscatalog.utilities import read_config, write_config, sxs_directory
|
|
7
|
+
from .sxs_identifiers import sxs_path_re
|
|
8
|
+
|
|
9
|
+
_platform_system = platform.system()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def sxs_path_to_system_path(path):
|
|
13
|
+
r"""Translate SXS path to a system-compatible path
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
path : str
|
|
18
|
+
SXS-style path to a file — for example, r"SXS:BBH:0123\Lev4:Horizons.h5"
|
|
19
|
+
becomes r"SXS_BBH_0123\Lev4_Horizons.h5" on Windows. Other systems can
|
|
20
|
+
handle the original path, so are not changed.
|
|
21
|
+
|
|
22
|
+
Notes
|
|
23
|
+
-----
|
|
24
|
+
SXS-style paths begin with SXS IDs, which contain colon characters. These
|
|
25
|
+
colons are incompatible with Windows file systems, so we simply replace the
|
|
26
|
+
colons with underscores.
|
|
27
|
+
|
|
28
|
+
"""
|
|
29
|
+
if _platform_system == "Windows":
|
|
30
|
+
return sxs_path_re.sub(lambda s: s.group(0).replace(":", "_"), str(path))
|
|
31
|
+
else:
|
|
32
|
+
return path
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def cached_path(path_pattern):
|
|
36
|
+
"""Return path to file in local cache
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
path_pattern : str
|
|
41
|
+
A pattern to search for among the catalog files. See the docstring of
|
|
42
|
+
`sxs.Catalog.select` for details about how this pattern is used.
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
path : pathlib.Path
|
|
47
|
+
Full path to file on this system. The file may not exist.
|
|
48
|
+
|
|
49
|
+
Raises
|
|
50
|
+
------
|
|
51
|
+
StopIteration
|
|
52
|
+
When no result is found for the input `path_pattern`.
|
|
53
|
+
|
|
54
|
+
Notes
|
|
55
|
+
-----
|
|
56
|
+
This function returns just one path, corresponding to the first result returned
|
|
57
|
+
by `catalog.select_files(path_pattern)`.
|
|
58
|
+
|
|
59
|
+
"""
|
|
60
|
+
import contextlib
|
|
61
|
+
from .. import load
|
|
62
|
+
with contextlib.redirect_stdout(None):
|
|
63
|
+
catalog = load("catalog")
|
|
64
|
+
file_infos = catalog.select_files(path_pattern)
|
|
65
|
+
sxs_path, file_info = next(iter(file_infos.items()))
|
|
66
|
+
cache_path = sxs_directory("cache")
|
|
67
|
+
truepath = sxs_path_to_system_path(file_info.get("truepath", sxs_path))
|
|
68
|
+
path = cache_path / truepath
|
|
69
|
+
return path
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import os.path
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
|
|
7
|
+
from sxscatalog.utilities import path_to_invenio, invenio_to_path
|
|
8
8
|
from .api import Login, Deposit, Records
|
|
9
9
|
from . import catalog, simannex, surrogatemodeling
|
|
10
10
|
|
|
@@ -12,16 +12,6 @@ from . import catalog, simannex, surrogatemodeling
|
|
|
12
12
|
# The other python API interface I found is here: https://github.com/moble/zenodo-python
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
def path_to_invenio(file_path):
|
|
16
|
-
"""Convert a file path to an invenio-compatible name"""
|
|
17
|
-
return str(file_path).replace(os.path.sep, ":")
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def invenio_to_path(file_name):
|
|
21
|
-
"""Convert an invenio-compatible name to a file path"""
|
|
22
|
-
return Path(file_name.replace(":", os.path.sep))
|
|
23
|
-
|
|
24
|
-
|
|
25
15
|
def translate(sxs_identifier, url=False):
|
|
26
16
|
"""Query data.black-holes.org to get the current Zenodo equivalent of the given SXS ID
|
|
27
17
|
|
sxs-2024.0.44/sxs/__version__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2024.0.44"
|
|
@@ -1,342 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
import warnings
|
|
3
|
-
import re
|
|
4
|
-
import datetime
|
|
5
|
-
import json
|
|
6
|
-
import pathlib
|
|
7
|
-
|
|
8
|
-
from .login import Login
|
|
9
|
-
from .. import sxs_id, Metadata
|
|
10
|
-
from ..utilities import sxs_identifier_regex, SimpleVersion
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def mtime(f):
|
|
14
|
-
"""Look for git or filesystem modification time
|
|
15
|
-
|
|
16
|
-
If the git call fails for any reason, we fall back to the filesystem's `mtime`.
|
|
17
|
-
|
|
18
|
-
The input `f` is expected to be a path to the file. The return value is a DateTime object
|
|
19
|
-
|
|
20
|
-
"""
|
|
21
|
-
from subprocess import check_output
|
|
22
|
-
try:
|
|
23
|
-
timestamp = check_output(f"""git log -1 --format="%ad" --date=unix -- {f}""", shell=True).decode().strip()
|
|
24
|
-
except:
|
|
25
|
-
timestamp = f.stat().st_mtime
|
|
26
|
-
finally:
|
|
27
|
-
mt = datetime.datetime.fromtimestamp(timestamp, tz=datetime.timezone.utc)
|
|
28
|
-
return mt
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def filter_files(files, utime):
|
|
32
|
-
return [f for f in files if mtime(f) > utime]
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def upload_simannex_dir(login, directory, date=None):
|
|
36
|
-
"""Update/upload data from the SimAnnex to CaltechDATA
|
|
37
|
-
|
|
38
|
-
Parameters
|
|
39
|
-
----------
|
|
40
|
-
login : caltechdata.Login
|
|
41
|
-
This is used to communicate with CaltechDATA.
|
|
42
|
-
directory : str or pathlib.Path
|
|
43
|
-
This must contain either "Public" or "Private", followed by the specific
|
|
44
|
-
directory in SimAnnex to upload. It can also contain higher path elements
|
|
45
|
-
— for example, you can give the absolute path.
|
|
46
|
-
date : str, optional
|
|
47
|
-
If given, this is used as the `publicationDate` field. It must be
|
|
48
|
-
formatted as "%Y-%m-%d". The default is just the current UTC time.
|
|
49
|
-
|
|
50
|
-
"""
|
|
51
|
-
raise Exception("This interface is for the old TIND API; use zenodo for the new API")
|
|
52
|
-
from caltechdata_api import customize_schema, decustomize_schema
|
|
53
|
-
|
|
54
|
-
allowed_files = [
|
|
55
|
-
"metadata.json",
|
|
56
|
-
"Strain_Outer.h5",
|
|
57
|
-
"Strain_N2.h5",
|
|
58
|
-
"Strain_N3.h5",
|
|
59
|
-
"Strain_N4.h5",
|
|
60
|
-
"Horizons.h5",
|
|
61
|
-
"Matter.h5",
|
|
62
|
-
]
|
|
63
|
-
|
|
64
|
-
# Check that `directory` is a valid SXS dataset
|
|
65
|
-
# - Name must contain either "Public" or "Private" followed by at least one subdirectory
|
|
66
|
-
# - Must contain common-metadata.txt (though this will not be uploaded)
|
|
67
|
-
# - Must contain at least one Lev* subdirectory
|
|
68
|
-
# - Each Lev* subdirectory must contain these files (which will be uploaded)
|
|
69
|
-
# - metadata.json
|
|
70
|
-
# - Strain_Outer.h5
|
|
71
|
-
# - Strain_N2.h5
|
|
72
|
-
# - Strain_N3.h5
|
|
73
|
-
# - Strain_N4.h5
|
|
74
|
-
# - Horizons.h5 and/or Matter.h5
|
|
75
|
-
directory = pathlib.Path(directory).expanduser().resolve()
|
|
76
|
-
if "/Public/" not in str(directory) and "/Private/" not in str(directory):
|
|
77
|
-
raise ValueError(f"""Either "Public" or "Private" must be in the input directory "{directory}".""")
|
|
78
|
-
if not (directory / "common-metadata.txt").exists():
|
|
79
|
-
raise ValueError(f"Missing common-metadata.txt in {directory}")
|
|
80
|
-
if not directory.glob("Lev*"):
|
|
81
|
-
raise ValueError(f"Missing Lev* in {directory}")
|
|
82
|
-
for lev in directory.glob("Lev*"):
|
|
83
|
-
warnings.warn("Temporarily skipping file checks")
|
|
84
|
-
# for f in ["Strain_Outer.h5", "Strain_N2.h5", "Strain_N3.h5", "Strain_N4.h5"]:
|
|
85
|
-
# if not (lev / f).exists():
|
|
86
|
-
# raise ValueError(f"""Missing file "{f}" in "{lev}".""")
|
|
87
|
-
# if not (lev / "metadata.json").exists():
|
|
88
|
-
# mtxt = lev / "metadata.txt"
|
|
89
|
-
# if not mtxt.exists():
|
|
90
|
-
# raise ValueError(f"""Missing both "metadata.txt" and "metadata.json" in "{lev}".""")
|
|
91
|
-
# else:
|
|
92
|
-
# m = Metadata.from_txt_file(str(mtxt), cache_json=False).add_extras().reorder_keys()
|
|
93
|
-
# m.to_json_file(str(mtxt.with_suffix(".json")))
|
|
94
|
-
# if not (lev / "Horizons.h5").exists() and not (lev / "Matter.h5").exists():
|
|
95
|
-
# raise ValueError(f"""Missing both "Horizons.h5" and "Matter.h5" in "{lev}".""")
|
|
96
|
-
|
|
97
|
-
# Figure out the "original name" of this simulation — something like "q4_7d/022" or "HighSpinMethods/BBH_SKS_d15.4_q1_..."
|
|
98
|
-
root_dir = [par for par in directory.parents if par.match("Public") or par.match("Private")][0]
|
|
99
|
-
original_name = str(directory.relative_to(root_dir))
|
|
100
|
-
|
|
101
|
-
# Get the SXS ID from common-metadata.txt
|
|
102
|
-
sxs_system_re = re.compile(sxs_identifier_regex)
|
|
103
|
-
sxs_system_type = None
|
|
104
|
-
sxs_system_number = None
|
|
105
|
-
with (directory / "common-metadata.txt").open("r") as f:
|
|
106
|
-
for line in f.readlines():
|
|
107
|
-
line = line.strip()
|
|
108
|
-
if "alternative-names" in line:
|
|
109
|
-
m = sxs_system_re.search(line)
|
|
110
|
-
if m:
|
|
111
|
-
sxs_system_type = m["simulation_type"]
|
|
112
|
-
sxs_system_number = m["sxs_number"]
|
|
113
|
-
break
|
|
114
|
-
if not sxs_system_type or not sxs_system_number:
|
|
115
|
-
raise ValueError(f"No SXS identifier found in {directory / 'common-metadata.txt'}")
|
|
116
|
-
sxs_system = f"SXS:{sxs_system_type}:{sxs_system_number}"
|
|
117
|
-
spec_url = "https://www.black-holes.org/code/SpEC.html"
|
|
118
|
-
if sxs_system_type == "BBH":
|
|
119
|
-
title = f"Binary black-hole simulation {sxs_system}"
|
|
120
|
-
description = f"""Simulation of a black-hole binary system evolved by the <a href="{spec_url}">SpEC code</a>."""
|
|
121
|
-
elif sxs_system_type == "BHNS":
|
|
122
|
-
title = f"Black-hole neutron-star binary simulation {sxs_system}"
|
|
123
|
-
description = f"""Simulation of a black-hole neutron-star binary system evolved by the <a href="{spec_url}">SpEC code</a>."""
|
|
124
|
-
elif sxs_system_type == "NSNS":
|
|
125
|
-
title = f"Binary neutron-star simulation {sxs_system}"
|
|
126
|
-
description = f"""Simulation of a neutron-star binary system evolved by the <a href="{spec_url}">SpEC code</a>."""
|
|
127
|
-
else:
|
|
128
|
-
raise ValueError(
|
|
129
|
-
f"""Did not recognize SXS system type "{sxs_system_type}" in directory "{directory}"; should be BBH, BHNS, or NSNS."""
|
|
130
|
-
)
|
|
131
|
-
print(f"Beginning work on {sxs_system}")
|
|
132
|
-
|
|
133
|
-
# Find our list of files
|
|
134
|
-
files = sorted(
|
|
135
|
-
[f for f in directory.glob("Lev*/*") if f.name in allowed_files],
|
|
136
|
-
key=lambda f: f"{f.parent}/{allowed_files.index(f.name)}"
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
# Search for an existing record with this name
|
|
140
|
-
existing = login.search(f'"{sxs_system}"')
|
|
141
|
-
exists = existing.get("hits", {}).get("total", 0) > 0
|
|
142
|
-
|
|
143
|
-
if exists:
|
|
144
|
-
# Find the latest version
|
|
145
|
-
latest = max(
|
|
146
|
-
existing["hits"]["hits"],
|
|
147
|
-
key=lambda h: SimpleVersion(h["metadata"]["version"])
|
|
148
|
-
)
|
|
149
|
-
latest_link = latest["links"]["self"].replace("/api/", "/")
|
|
150
|
-
latest_doi = latest["metadata"]["doi"]
|
|
151
|
-
|
|
152
|
-
# Check to see if any files have changed since the latest version
|
|
153
|
-
utime = datetime.datetime.fromisoformat(latest["updated"])
|
|
154
|
-
files_to_upload = filter_files(files, utime)
|
|
155
|
-
if not files:
|
|
156
|
-
print(f"No changes to {latest_link}.")
|
|
157
|
-
return latest_link
|
|
158
|
-
|
|
159
|
-
# Update version, relatedIdentifiers, and updated date
|
|
160
|
-
metadata = latest["metadata"]
|
|
161
|
-
old_version = SimpleVersion(metadata["version"])
|
|
162
|
-
metadata["version"] = str(old_version.increment())
|
|
163
|
-
metadata["relatedIdentifiers"] =[
|
|
164
|
-
{
|
|
165
|
-
"relatedIdentifierRelation": "IsNewVersionOf",
|
|
166
|
-
"relatedIdentifier": latest_doi,
|
|
167
|
-
"relatedIdentifierScheme": "DOI"
|
|
168
|
-
}
|
|
169
|
-
]
|
|
170
|
-
metadata["relevantDates"] = [
|
|
171
|
-
{
|
|
172
|
-
"relevantDateType": "Updated",
|
|
173
|
-
"relevantDateValue": datetime.datetime.utcnow().strftime("%Y-%m-%d"),
|
|
174
|
-
}
|
|
175
|
-
]
|
|
176
|
-
|
|
177
|
-
# Upload files
|
|
178
|
-
raise NotImplementedError(
|
|
179
|
-
"Adding new files to an existing record is not yet supported. We will need some logic like this:\n" +
|
|
180
|
-
" https://github.com/caltechlibrary/caltechdata_api/blob/840a359a017d1257ac344b6af80038f591fd8a97/caltechdata_api/caltechdata_edit.py#L189-L233\n" +
|
|
181
|
-
"More specifically, if we want to create a new version, we will probably need to essentially copy\n" +
|
|
182
|
-
"the existing record, publish it, and then follow steps like the above to upload new files and\n" +
|
|
183
|
-
"delete the old ones. It is not clear to me if the deletion would destroy files being used by the\n" +
|
|
184
|
-
"older version, or just delete that entry in the new record."
|
|
185
|
-
)
|
|
186
|
-
existing_names = {
|
|
187
|
-
f["electronic_name"][0]: f["uniform_resource_identifier"].split("/")[-2]
|
|
188
|
-
for f in metadata["electronic_location_and_access"]
|
|
189
|
-
}
|
|
190
|
-
for f in files_to_upload:
|
|
191
|
-
fileinfo = login.send_s3(f, str(f.relative_to(directory)), verbose=True)
|
|
192
|
-
name = fileinfo["filename"]
|
|
193
|
-
if name in existing_names:
|
|
194
|
-
metadata["files"][existing_names.index(name)] = fileinfo
|
|
195
|
-
else:
|
|
196
|
-
metadata["files"].append(fileinfo)
|
|
197
|
-
|
|
198
|
-
else:
|
|
199
|
-
# Set up the metadata. Note that CaltechDATA internally uses an undocumented
|
|
200
|
-
# customized schema similar to — but different from — the standard Invenio
|
|
201
|
-
# schema. Fortunately, `caltechdata_api` includes a function to convert from
|
|
202
|
-
# DataCite 4.0 or 4.3 to their schema. So, we set ours up as DataCite 4.0 and
|
|
203
|
-
# convert it: <https://schema.datacite.org/meta/kernel-4.0/>
|
|
204
|
-
|
|
205
|
-
# Generate a little table of info to append to the description
|
|
206
|
-
highest_lev = sorted(set(f.relative_to(directory).parent for f in files))[-1]
|
|
207
|
-
sim_metadata = Metadata.from_file(directory / highest_lev / "metadata")
|
|
208
|
-
object_types = sim_metadata.get("object_types", "")
|
|
209
|
-
mass_ratio = sim_metadata.get("reference_mass_ratio", "Unknown")
|
|
210
|
-
if "reference_dimensionless_spin1" in sim_metadata:
|
|
211
|
-
chi1 = sim_metadata.reference_dimensionless_spin1
|
|
212
|
-
chi1 = f"[{chi1[0]:0.4f}, {chi1[1]:0.4f}, {chi1[2]:0.4f}]"
|
|
213
|
-
else:
|
|
214
|
-
chi1 = "N/A"
|
|
215
|
-
if "reference_dimensionless_spin2" in sim_metadata:
|
|
216
|
-
chi2 = sim_metadata.reference_dimensionless_spin2
|
|
217
|
-
chi2 = f"[{chi2[0]:0.4f}, {chi2[1]:0.4f}, {chi2[2]:0.4f}]"
|
|
218
|
-
else:
|
|
219
|
-
chi2 = "N/A"
|
|
220
|
-
n_orbits = sim_metadata.get("number_of_orbits", "Unknown")
|
|
221
|
-
reference_eccentricity = sim_metadata.get("reference_eccentricity", "Unknown")
|
|
222
|
-
description = f"""{description}
|
|
223
|
-
<br/>
|
|
224
|
-
<table>
|
|
225
|
-
<tbody>
|
|
226
|
-
<tr><td style="padding:0 15px;">Mass ratio</td><td>{mass_ratio:.4f}</td></tr>
|
|
227
|
-
<tr><td style="padding:0 15px;">Spin 1</td><td>{chi1}</td></tr>
|
|
228
|
-
<tr><td style="padding:0 15px;">Spin 2</td><td>{chi2}</td></tr>
|
|
229
|
-
<tr><td style="padding:0 15px;">Number of orbits</td><td>{n_orbits:.4f}</td></tr>
|
|
230
|
-
<tr><td style="padding:0 15px;">Eccentricity</td><td>{reference_eccentricity}</td></tr>
|
|
231
|
-
</tbody>
|
|
232
|
-
</table>
|
|
233
|
-
<br/>
|
|
234
|
-
Originally named "{original_name}"
|
|
235
|
-
"""
|
|
236
|
-
files_to_upload = files
|
|
237
|
-
|
|
238
|
-
metadata = {
|
|
239
|
-
"resourceType": {
|
|
240
|
-
"resourceTypeGeneral": "Dataset"
|
|
241
|
-
},
|
|
242
|
-
"titles": [
|
|
243
|
-
{"title": title},
|
|
244
|
-
],
|
|
245
|
-
"version": "2.0",
|
|
246
|
-
"creators": [{"creatorName": "SXS Collaboration"}],
|
|
247
|
-
"descriptions": [
|
|
248
|
-
{
|
|
249
|
-
"descriptionType": "Abstract",
|
|
250
|
-
"description": description,
|
|
251
|
-
}
|
|
252
|
-
],
|
|
253
|
-
"subjects": [
|
|
254
|
-
{"subject": "Astronomy"},
|
|
255
|
-
{"subject": "Astrophysics"},
|
|
256
|
-
{"subject": "Gravitational Waves"},
|
|
257
|
-
{"subject": "Numerical Relativity"},
|
|
258
|
-
],
|
|
259
|
-
"dates": [
|
|
260
|
-
{
|
|
261
|
-
"date": datetime.datetime.utcnow().strftime("%Y-%m-%d"),
|
|
262
|
-
"dateType": "Updated"
|
|
263
|
-
},
|
|
264
|
-
],
|
|
265
|
-
"rightsList": [
|
|
266
|
-
{
|
|
267
|
-
"rights": "Creative Commons Attribution 4.0 International License",
|
|
268
|
-
"rightsURI": "https://creativecommons.org/licenses/by/4.0/",
|
|
269
|
-
}
|
|
270
|
-
],
|
|
271
|
-
}
|
|
272
|
-
if "bh" in object_types.lower():
|
|
273
|
-
metadata["subjects"].append({"subject": "Black Holes"})
|
|
274
|
-
if "ns" in object_types.lower():
|
|
275
|
-
metadata["subjects"].append({"subject": "Neutron Stars"})
|
|
276
|
-
metadata = customize_schema(metadata, schema="40")
|
|
277
|
-
metadata["publicationDate"] = date or datetime.datetime.utcnow().strftime("%Y-%m-%d")
|
|
278
|
-
metadata["files"] = [login.send_s3(f, str(f.relative_to(directory)), verbose=True) for f in files]
|
|
279
|
-
|
|
280
|
-
metadata["titles"] = [
|
|
281
|
-
{"title": title},
|
|
282
|
-
{"title": f"{original_name}", "titleType": "AlternativeTitle"},
|
|
283
|
-
]
|
|
284
|
-
|
|
285
|
-
# if doi is None:
|
|
286
|
-
# # We want tind to generate the identifier
|
|
287
|
-
# metadata["final_actions"] = [
|
|
288
|
-
# {
|
|
289
|
-
# "type": "create_doi",
|
|
290
|
-
# "parameters": {"type": "records", "field": "doi"},
|
|
291
|
-
# }
|
|
292
|
-
# ]
|
|
293
|
-
# else:
|
|
294
|
-
metadata["doi"] = f"""{login.doi_prefix}/{sxs_system}v{metadata["version"]}"""
|
|
295
|
-
|
|
296
|
-
# Now tell CaltechDATA about it
|
|
297
|
-
recordurl = f"{login.base_url}submit/api/create/"
|
|
298
|
-
response = login.session.post(recordurl, data=json.dumps({"record": metadata}))
|
|
299
|
-
if response.status_code != 200:
|
|
300
|
-
print(f"An error occurred when trying to create a new record for '{directory}'.")
|
|
301
|
-
try:
|
|
302
|
-
print(response.text)
|
|
303
|
-
except:
|
|
304
|
-
pass
|
|
305
|
-
try:
|
|
306
|
-
print(response.json())
|
|
307
|
-
except:
|
|
308
|
-
pass
|
|
309
|
-
response.raise_for_status()
|
|
310
|
-
raise RuntimeError() # Will only happen if the response was not strictly an error
|
|
311
|
-
else:
|
|
312
|
-
print(f""" Publishing as "{title}".""")
|
|
313
|
-
print(f""" {response.text}""")
|
|
314
|
-
|
|
315
|
-
url = response.text[response.text.find(login.base_url):].rstrip().rstrip(".")
|
|
316
|
-
pid = url.rsplit("/", 1)[1]
|
|
317
|
-
|
|
318
|
-
# Create the DOI
|
|
319
|
-
print(" Creating/updating DOIs")
|
|
320
|
-
api_url = f"{login.base_url}api/record/{pid}"
|
|
321
|
-
for retry in range(20):
|
|
322
|
-
r = login.session.get(api_url)
|
|
323
|
-
if r.status_code == 200:
|
|
324
|
-
break
|
|
325
|
-
time.sleep(1.1) # Let things settle down at CaltechDATA, so we can get the metadata
|
|
326
|
-
if r.status_code != 200:
|
|
327
|
-
print(f"""An error occurred when trying to access "{api_url}".""")
|
|
328
|
-
try:
|
|
329
|
-
print(r.json())
|
|
330
|
-
except:
|
|
331
|
-
pass
|
|
332
|
-
r.raise_for_status()
|
|
333
|
-
raise RuntimeError() # Will only happen if the response was not strictly an error
|
|
334
|
-
output_metadata = r.json()
|
|
335
|
-
doi_metadata = decustomize_schema(output_metadata, schema="43")
|
|
336
|
-
if not exists:
|
|
337
|
-
doi = f"""{login.doi_prefix}/{sxs_system}"""
|
|
338
|
-
login.datacite.public_doi(doi_metadata, url, doi)
|
|
339
|
-
doi = f"""{login.doi_prefix}/{sxs_system}v{metadata["version"]}"""
|
|
340
|
-
login.datacite.public_doi(doi_metadata, url, doi)
|
|
341
|
-
|
|
342
|
-
return url
|