From a47473a539f5cef8651ae0e745d1f4efbafe3494 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Tue, 3 Sep 2024 15:29:41 +0200 Subject: [PATCH 01/13] Fix __all__ in __init__.py --- src/ess/dream/__init__.py | 3 +-- src/ess/powder/__init__.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ess/dream/__init__.py b/src/ess/dream/__init__.py index a6a8350..8958e7f 100644 --- a/src/ess/dream/__init__.py +++ b/src/ess/dream/__init__.py @@ -19,11 +19,10 @@ del importlib __all__ = [ + '__version__', 'DreamGeant4Workflow', 'default_parameters', - 'beamline', 'instrument_view', 'load_geant4_csv', 'nexus', - 'providers', ] diff --git a/src/ess/powder/__init__.py b/src/ess/powder/__init__.py index 3ce316e..577b71e 100644 --- a/src/ess/powder/__init__.py +++ b/src/ess/powder/__init__.py @@ -35,12 +35,12 @@ """Sciline providers for powder diffraction.""" __all__ = [ + "__version__", "conversion", "correction", "filtering", "grouping", "masking", - "nexus", "transform", "providers", "smoothing", From 3dd094c42829cc114e10011ac10a7428b8f81501 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Tue, 3 Sep 2024 15:50:35 +0200 Subject: [PATCH 02/13] Remove unused ficture --- tests/dream/geant4_reduction_test.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/dream/geant4_reduction_test.py b/tests/dream/geant4_reduction_test.py index 1cd15a4..a51d7d9 100644 --- a/tests/dream/geant4_reduction_test.py +++ b/tests/dream/geant4_reduction_test.py @@ -29,14 +29,6 @@ WavelengthMask, ) - -@pytest.fixture -def providers(): - from ess.dream.io.geant4 import providers as geant4_providers - - return [*powder.providers, *geant4_providers] - - sample = sc.DataGroup(position=sc.vector([0.0, 0.0, 0.0], unit='mm')) source = sc.DataGroup(position=sc.vector([-3.478, 0.0, -76550], unit='mm')) charge = sc.scalar(1.0, unit='µAh') From 882c8e4ac382e87a31deee87da3f7183491a60ae Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Tue, 3 Sep 2024 16:54:31 +0200 Subject: [PATCH 03/13] Begin CIF writer --- .../dream/dream-data-reduction.ipynb | 31 +++- src/ess/dream/io/__init__.py | 3 +- src/ess/dream/io/cif.py | 146 ++++++++++++++++++ src/ess/dream/workflow.py | 2 + tests/dream/geant4_reduction_test.py | 46 +++++- tests/dream/io/cif_test.py | 131 ++++++++++++++++ 6 files changed, 355 insertions(+), 4 deletions(-) create mode 100644 src/ess/dream/io/cif.py create mode 100644 tests/dream/io/cif_test.py diff --git a/docs/user-guide/dream/dream-data-reduction.ipynb b/docs/user-guide/dream/dream-data-reduction.ipynb index 9e4aada..b446090 100644 --- a/docs/user-guide/dream/dream-data-reduction.ipynb +++ b/docs/user-guide/dream/dream-data-reduction.ipynb @@ -25,6 +25,7 @@ "\n", "from ess import dream, powder\n", "import ess.dream.data # noqa: F401\n", + "from ess.dream.io.cif import CIFAuthor, CIFAuthors\n", "from ess.powder.types import *" ] }, @@ -83,6 +84,32 @@ "workflow = powder.with_pixel_mask_filenames(workflow, [])" ] }, + { + "cell_type": "markdown", + "id": "8072fe3de2527f0e", + "metadata": {}, + "source": [ + "We also need some parameters to configure the output file:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "502e77cc-0253-4e71-9d97-81ff560ef99d", + "metadata": {}, + "outputs": [], + "source": [ + "workflow[OutFilename] = \"reduced.cif\"\n", + "workflow[CIFAuthors] = CIFAuthors([\n", + " CIFAuthor(\n", + " name=\"Jane Doe\",\n", + " email=\"jane.doe@ess.eu\",\n", + " id_orcid=\"0000-0000-0000-0001\",\n", + " role=\"measurement\",\n", + " ),\n", + "])" + ] + }, { "cell_type": "markdown", "id": "6", @@ -108,7 +135,7 @@ "id": "8", "metadata": {}, "source": [ - "We then call `compute()` to compute the result:" + "We then compute the result and save it to disk:" ] }, { @@ -118,7 +145,7 @@ "metadata": {}, "outputs": [], "source": [ - "result = workflow.compute(IofDspacing)\n", + "result = workflow.bind_and_call(dream.io.save_reduced_dspacing)\n", "result" ] }, diff --git a/src/ess/dream/io/__init__.py b/src/ess/dream/io/__init__.py index 2224a07..95a49b8 100644 --- a/src/ess/dream/io/__init__.py +++ b/src/ess/dream/io/__init__.py @@ -5,5 +5,6 @@ from . import nexus from .geant4 import load_geant4_csv +from .cif import save_reduced_dspacing -__all__ = ["nexus", "load_geant4_csv"] +__all__ = ["nexus", "load_geant4_csv", "save_reduced_dspacing"] diff --git a/src/ess/dream/io/cif.py b/src/ess/dream/io/cif.py new file mode 100644 index 0000000..d808608 --- /dev/null +++ b/src/ess/dream/io/cif.py @@ -0,0 +1,146 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2023 Scipp contributors (https://github.com/scipp) + +"""CIF writer for DREAM.""" + +import uuid +from collections.abc import Sequence +from dataclasses import dataclass, field +from datetime import datetime, timezone + +import scipp as sc +from scippneutron.io import cif + +from ess.powder.types import IofDspacing, OutFilename + + +@dataclass(kw_only=True) +class CIFAuthor: + name: str + address: str | None = None + email: str | None = None + id_orcid: str | None = None + is_contact: bool = True + role: str | None = None + + +@dataclass() +class CIFAuthors: + authors: Sequence[CIFAuthor] = field(default_factory=list) + + +def save_reduced_dspacing( + da: IofDspacing, *, filename: OutFilename, authors: CIFAuthors +) -> IofDspacing: + to_save = da if da.bins is None else da.hist() + cif.save_cif(filename, _make_dspacing_block(to_save, authors=authors)) + return da + + +def _make_dspacing_block(da: sc.DataArray, authors: CIFAuthors) -> cif.Block: + block = cif.Block( + 'reduced_dspacing', + [ + _make_audit_chunk(), + _make_source_chunk(), + *_make_author_chunks(authors), + _make_dspacing_loop(da), + ], + ) + return block + + +def _make_dspacing_loop(da: sc.DataArray) -> cif.Loop: + return cif.Loop( + { + 'pd_proc.d_spacing': sc.midpoints(da.coords['dspacing']), + 'pd_proc.intensity_net': sc.values(da.data), + 'pd_proc.intensity_su': sc.stddevs(da.data), + }, + schema=cif.PD_SCHEMA, + ) + + +def _make_source_chunk() -> cif.Chunk: + return cif.Chunk( + { + # TODO diffrn_source.current once we have it + # TODO diffrn_source.power: can we deduce it? + 'diffrn_radiation.probe': 'neutron', + 'diffrn_source.beamline': 'DREAM', + 'diffrn_source.device': 'spallation', + 'diffrn_source.facility': 'ESS', + }, + schema=cif.CORE_SCHEMA, + ) + + +def _make_audit_chunk() -> cif.Chunk: + from ess.dream import __version__ + + return cif.Chunk( + { + 'audit.creation_date': datetime.now(timezone.utc).isoformat( + timespec='seconds' + ), + 'audit.creation_method': f'Written by ess.dream v{__version__}', + }, + schema=cif.CORE_SCHEMA, + ) + + +def _make_author_chunks(authors: CIFAuthors) -> list[cif.Chunk | cif.Loop]: + contact = [author for author in authors.authors if author.is_contact] + regular = [author for author in authors.authors if not author.is_contact] + + results = [] + roles = {} + for aut, cat in zip( + (contact, regular), ('audit_contact_author', 'audit_author'), strict=True + ): + if not aut: + continue + data, rols = _serialize_authors(aut, cat) + results.append(data) + roles.update(rols) + if roles: + results.append(_serialize_roles(roles)) + + return results + + +def _serialize_authors( + authors: list[CIFAuthor], category: str +) -> tuple[cif.Chunk | cif.Loop, dict[str, str]]: + fields = { + f'{category}.{key}': f + for key in ('name', 'email', 'address', 'id_orcid') + if any(f := [getattr(a, key) or '' for a in authors]) + } + + roles = {uuid.uuid4().hex: a.role for a in authors} + if any(roles.values()): + fields[f'{category}.id'] = list(roles.keys()) + roles = {key: val for key, val in roles.items() if val} + + if len(authors) == 1: + return cif.Chunk( + {key: val[0] for key, val in fields.items()}, + schema=cif.CORE_SCHEMA, + ), roles + return cif.Loop( + {key: sc.array(dims=['author'], values=val) for key, val in fields.items()}, + schema=cif.CORE_SCHEMA, + ), roles + + +def _serialize_roles(roles: dict[str, str]) -> cif.Loop: + return cif.Loop( + { + 'audit_author_role.id': sc.array(dims=['role'], values=list(roles)), + 'audit_author_role.role': sc.array( + dims=['role'], values=list(roles.values()) + ), + }, + schema=cif.CORE_SCHEMA, + ) diff --git a/src/ess/dream/workflow.py b/src/ess/dream/workflow.py index fc23813..2946212 100644 --- a/src/ess/dream/workflow.py +++ b/src/ess/dream/workflow.py @@ -13,6 +13,7 @@ VanadiumRun, ) +from .io.cif import CIFAuthors from .io.geant4 import LoadGeant4Workflow @@ -28,6 +29,7 @@ def default_parameters() -> dict: NeXusSource[VanadiumRun]: source, AccumulatedProtonCharge[SampleRun]: charge, AccumulatedProtonCharge[VanadiumRun]: charge, + CIFAuthors: CIFAuthors([]), } diff --git a/tests/dream/geant4_reduction_test.py b/tests/dream/geant4_reduction_test.py index a51d7d9..71c35cd 100644 --- a/tests/dream/geant4_reduction_test.py +++ b/tests/dream/geant4_reduction_test.py @@ -1,12 +1,16 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) +import io + import pytest import sciline import scipp as sc +import scipp.testing +from ess import dream, powder import ess.dream.data # noqa: F401 -from ess import dream, powder +from ess.dream.io.cif import CIFAuthor, CIFAuthors from ess.powder.types import ( AccumulatedProtonCharge, BackgroundRun, @@ -20,6 +24,7 @@ NeXusSample, NeXusSource, NormalizedByProtonCharge, + OutFilename, SampleRun, TofMask, TwoThetaBins, @@ -50,6 +55,13 @@ AccumulatedProtonCharge[VanadiumRun]: charge, TwoThetaMask: None, WavelengthMask: None, + CIFAuthors: CIFAuthors( + [ + CIFAuthor( + name="Jane Doe", email="jane.doe@ess.eu", id_orcid="0000-0000-0000-0001" + ), + ] + ), } @@ -144,3 +156,35 @@ def test_use_workflow_helper(workflow): result = workflow.compute(IofDspacing) assert result.sizes == {'dspacing': len(params[DspacingBins]) - 1} assert sc.identical(result.coords['dspacing'], params[DspacingBins]) + + +def test_pipeline_can_save_data(workflow): + def get_result(da: IofDspacing) -> IofDspacing: + return da + + buffer = io.StringIO() + workflow[OutFilename] = buffer + workflow = powder.with_pixel_mask_filenames(workflow, []) + + result, expected = workflow.bind_and_call( + [dream.io.save_reduced_dspacing, get_result] + ) + sc.testing.assert_identical(result, expected) + + buffer.seek(0) + content = buffer.read() + # print(content) + # assert False + + assert content.startswith(r'#\#CIF_1.1') + _assert_contains_source_info(content) + _assert_contains_author_info(content) + + +def _assert_contains_source_info(cif_content: str) -> None: + assert 'diffrn_source.beamline DREAM' in cif_content + + +def _assert_contains_author_info(cif_content: str) -> None: + assert "audit_contact_author.name 'Jane Doe'" in cif_content + assert 'audit_contact_author.email jane.doe@ess.eu' in cif_content diff --git a/tests/dream/io/cif_test.py b/tests/dream/io/cif_test.py new file mode 100644 index 0000000..6b03dac --- /dev/null +++ b/tests/dream/io/cif_test.py @@ -0,0 +1,131 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2023 Scipp contributors (https://github.com/scipp) + +import io +import re +from typing import Any + +import pytest +import scipp as sc + +import ess.dream.io.cif +from ess.dream.io.cif import CIFAuthor, CIFAuthors +from ess.powder.types import IofDspacing + +# TODO many more + + +@pytest.fixture() +def iofd() -> IofDspacing: + return IofDspacing( + sc.DataArray( + sc.array(dims=['dspacing'], values=[2.1, 3.2], variances=[0.3, 0.4]), + coords={'dspacing': sc.linspace('dspacing', 0.1, 1.2, 3, unit='angstrom')}, + ) + ) + + +def save_reduced_dspacing_to_str(*args: Any, **kwargs: Any) -> str: + buffer = io.StringIO() + ess.dream.io.cif.save_reduced_dspacing(*args, filename=buffer, **kwargs) + buffer.seek(0) + return buffer.read() + + +def test_save_reduced_dspacing_writes_contact_author(iofd: IofDspacing) -> None: + authors = CIFAuthors( + [ + CIFAuthor( + name='Jane Doe', + email='jane.doe@ess.eu', + address='Partikelgatan, Lund', + id_orcid='https://orcid.org/0000-0000-0000-0001', + ) + ] + ) + result = save_reduced_dspacing_to_str(iofd, authors=authors) + assert "_audit_contact_author.name 'Jane Doe'" in result + assert '_audit_contact_author.email jane.doe@ess.eu' in result + assert "_audit_contact_author.address 'Partikelgatan, Lund'" in result + assert ( + '_audit_contact_author.id_orcid https://orcid.org/0000-0000-0000-0001' in result + ) + + +def test_save_reduced_dspacing_writes_regular_author(iofd: IofDspacing) -> None: + authors = CIFAuthors( + [ + CIFAuthor( + name='Jane Doe', + email='jane.doe@ess.eu', + address='Partikelgatan, Lund', + id_orcid='https://orcid.org/0000-0000-0000-0001', + is_contact=False, + ) + ] + ) + result = save_reduced_dspacing_to_str(iofd, authors=authors) + assert "_audit_author.name 'Jane Doe'" in result + assert '_audit_author.email jane.doe@ess.eu' in result + assert "_audit_author.address 'Partikelgatan, Lund'" in result + assert '_audit_author.id_orcid https://orcid.org/0000-0000-0000-0001' in result + + +def test_save_reduced_dspacing_writes_multiple_regular_authors( + iofd: IofDspacing, +) -> None: + authors = CIFAuthors( + [ + CIFAuthor( + name='Jane Doe', + email='jane.doe@ess.eu', + address='Partikelgatan, Lund', + id_orcid='https://orcid.org/0000-0000-0000-0001', + is_contact=False, + ), + CIFAuthor( + name='Max Mustermann', + email='mm@scipp.eu', + id_orcid='https://orcid.org/0000-0000-0000-0002', + is_contact=False, + ), + ] + ) + result = save_reduced_dspacing_to_str(iofd, authors=authors) + # The missing address for Max is currently broken because of + # https://github.com/scipp/scippneutron/issues/547 + expected = """loop_ +_audit_author.name +_audit_author.email +_audit_author.address +_audit_author.id_orcid +'Jane Doe' jane.doe@ess.eu 'Partikelgatan, Lund' https://orcid.org/0000-0000-0000-0001 +'Max Mustermann' mm@scipp.eu https://orcid.org/0000-0000-0000-0002 +""" + assert expected in result + + +def test_save_reduced_dspacing_writes_regular_author_role(iofd: IofDspacing) -> None: + authors = CIFAuthors( + [ + CIFAuthor( + name='Jane Doe', + role='measurement', + is_contact=False, + ) + ] + ) + result = save_reduced_dspacing_to_str(iofd, authors=authors) + + author_pattern = r"""_audit_author.name 'Jane Doe' +_audit_author.id ([0-9a-f]+)""" + author_match = re.search(author_pattern, result) + assert author_match is not None + author_id = author_match.group(1) + + expected = rf"""loop_ +_audit_author_role.id +_audit_author_role.role +{author_id} measurement""" + + assert expected in result From 665ad91619368c9dd15de423dbe28ec1b9c6b148 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 5 Sep 2024 10:52:28 +0200 Subject: [PATCH 04/13] Use block.add_reduced_powder_data --- src/ess/dream/io/cif.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/ess/dream/io/cif.py b/src/ess/dream/io/cif.py index d808608..397bdf1 100644 --- a/src/ess/dream/io/cif.py +++ b/src/ess/dream/io/cif.py @@ -32,11 +32,17 @@ class CIFAuthors: def save_reduced_dspacing( da: IofDspacing, *, filename: OutFilename, authors: CIFAuthors ) -> IofDspacing: - to_save = da if da.bins is None else da.hist() + to_save = _prepare_data(da) cif.save_cif(filename, _make_dspacing_block(to_save, authors=authors)) return da +def _prepare_data(da: sc.DataArray) -> sc.DataArray: + hist = da.copy(deep=False) if da.bins is None else da.hist() + hist.coords[hist.dim] = sc.midpoints(hist.coords[hist.dim]) + return hist + + def _make_dspacing_block(da: sc.DataArray, authors: CIFAuthors) -> cif.Block: block = cif.Block( 'reduced_dspacing', @@ -44,23 +50,12 @@ def _make_dspacing_block(da: sc.DataArray, authors: CIFAuthors) -> cif.Block: _make_audit_chunk(), _make_source_chunk(), *_make_author_chunks(authors), - _make_dspacing_loop(da), ], ) + block.add_reduced_powder_data(da) return block -def _make_dspacing_loop(da: sc.DataArray) -> cif.Loop: - return cif.Loop( - { - 'pd_proc.d_spacing': sc.midpoints(da.coords['dspacing']), - 'pd_proc.intensity_net': sc.values(da.data), - 'pd_proc.intensity_su': sc.stddevs(da.data), - }, - schema=cif.PD_SCHEMA, - ) - - def _make_source_chunk() -> cif.Chunk: return cif.Chunk( { From 100f3906faa7a9252a91e140227d055970340e28 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 5 Sep 2024 16:22:46 +0200 Subject: [PATCH 05/13] Use new scippneutron cif builder --- .../dream/dream-data-reduction.ipynb | 24 ++- src/ess/dream/io/__init__.py | 6 +- src/ess/dream/io/cif.py | 147 ++++-------------- src/ess/dream/workflow.py | 8 +- src/ess/powder/types.py | 7 + tests/dream/io/cif_test.py | 117 +++----------- 6 files changed, 72 insertions(+), 237 deletions(-) diff --git a/docs/user-guide/dream/dream-data-reduction.ipynb b/docs/user-guide/dream/dream-data-reduction.ipynb index b446090..fcdd129 100644 --- a/docs/user-guide/dream/dream-data-reduction.ipynb +++ b/docs/user-guide/dream/dream-data-reduction.ipynb @@ -20,12 +20,10 @@ "outputs": [], "source": [ "import scipp as sc\n", - "import scippneutron as scn\n", - "import scippneutron.io\n", + "from scippneutron.io import cif\n", "\n", "from ess import dream, powder\n", "import ess.dream.data # noqa: F401\n", - "from ess.dream.io.cif import CIFAuthor, CIFAuthors\n", "from ess.powder.types import *" ] }, @@ -99,12 +97,11 @@ "metadata": {}, "outputs": [], "source": [ - "workflow[OutFilename] = \"reduced.cif\"\n", "workflow[CIFAuthors] = CIFAuthors([\n", - " CIFAuthor(\n", + " cif.Author(\n", " name=\"Jane Doe\",\n", " email=\"jane.doe@ess.eu\",\n", - " id_orcid=\"0000-0000-0000-0001\",\n", + " orcid=\"0000-0000-0000-0001\",\n", " role=\"measurement\",\n", " ),\n", "])" @@ -135,7 +132,8 @@ "id": "8", "metadata": {}, "source": [ - "We then compute the result and save it to disk:" + "We then call `compute()` to compute the result:\n", + "(The `cif` object will later be used to write the result to disk.)" ] }, { @@ -145,8 +143,9 @@ "metadata": {}, "outputs": [], "source": [ - "result = workflow.bind_and_call(dream.io.save_reduced_dspacing)\n", - "result" + "results = workflow.compute([IofDspacing, ReducedDspacingCIF])\n", + "result = results[IofDspacing]\n", + "cif = results[ReducedDspacingCIF]" ] }, { @@ -175,10 +174,7 @@ "metadata": {}, "outputs": [], "source": [ - "dspacing_histogram.coords[\"dspacing\"] = sc.midpoints(\n", - " dspacing_histogram.coords[\"dspacing\"]\n", - ")\n", - "scn.io.save_xye(\"dspacing.xye\", dspacing_histogram)" + "cif.save('dspacing.cif')" ] }, { @@ -302,7 +298,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.14" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/src/ess/dream/io/__init__.py b/src/ess/dream/io/__init__.py index 95a49b8..5a53ba3 100644 --- a/src/ess/dream/io/__init__.py +++ b/src/ess/dream/io/__init__.py @@ -5,6 +5,8 @@ from . import nexus from .geant4 import load_geant4_csv -from .cif import save_reduced_dspacing +from .cif import prepare_reduced_dspacing_cif -__all__ = ["nexus", "load_geant4_csv", "save_reduced_dspacing"] +providers = (prepare_reduced_dspacing_cif,) + +__all__ = ["nexus", "load_geant4_csv", "prepare_reduced_dspacing_cif", "providers"] diff --git a/src/ess/dream/io/cif.py b/src/ess/dream/io/cif.py index 397bdf1..136a066 100644 --- a/src/ess/dream/io/cif.py +++ b/src/ess/dream/io/cif.py @@ -3,139 +3,46 @@ """CIF writer for DREAM.""" -import uuid -from collections.abc import Sequence -from dataclasses import dataclass, field -from datetime import datetime, timezone - import scipp as sc from scippneutron.io import cif -from ess.powder.types import IofDspacing, OutFilename +from ess.powder.types import CIFAuthors, IofDspacing, ReducedDspacingCIF -@dataclass(kw_only=True) -class CIFAuthor: - name: str - address: str | None = None - email: str | None = None - id_orcid: str | None = None - is_contact: bool = True - role: str | None = None +def prepare_reduced_dspacing_cif( + da: IofDspacing, *, authors: CIFAuthors +) -> ReducedDspacingCIF: + """Construct a CIF builder with reduced data in d-spacing. + The object contains the d-spacing coordinate, intensities, + and a number of metadata. -@dataclass() -class CIFAuthors: - authors: Sequence[CIFAuthor] = field(default_factory=list) + Parameters + ---------- + da: + Reduced 1d data with a `'dspacing'` dimension and coordinate. + authors: + List of authors to write to the file. + Returns + ------- + : + An object that contains the reduced data and metadata. + Us its ``save`` method to write the CIF file. + """ + from .. import __version__ -def save_reduced_dspacing( - da: IofDspacing, *, filename: OutFilename, authors: CIFAuthors -) -> IofDspacing: to_save = _prepare_data(da) - cif.save_cif(filename, _make_dspacing_block(to_save, authors=authors)) - return da + return ( + cif.CIF('reduced_dspacing') + .with_reducers(f'ess.dream v{__version__}') + .with_authors(*authors) + .with_beamline(beamline='DREAM', facility='ESS') + .with_reduced_powder_data(to_save) + ) def _prepare_data(da: sc.DataArray) -> sc.DataArray: hist = da.copy(deep=False) if da.bins is None else da.hist() hist.coords[hist.dim] = sc.midpoints(hist.coords[hist.dim]) return hist - - -def _make_dspacing_block(da: sc.DataArray, authors: CIFAuthors) -> cif.Block: - block = cif.Block( - 'reduced_dspacing', - [ - _make_audit_chunk(), - _make_source_chunk(), - *_make_author_chunks(authors), - ], - ) - block.add_reduced_powder_data(da) - return block - - -def _make_source_chunk() -> cif.Chunk: - return cif.Chunk( - { - # TODO diffrn_source.current once we have it - # TODO diffrn_source.power: can we deduce it? - 'diffrn_radiation.probe': 'neutron', - 'diffrn_source.beamline': 'DREAM', - 'diffrn_source.device': 'spallation', - 'diffrn_source.facility': 'ESS', - }, - schema=cif.CORE_SCHEMA, - ) - - -def _make_audit_chunk() -> cif.Chunk: - from ess.dream import __version__ - - return cif.Chunk( - { - 'audit.creation_date': datetime.now(timezone.utc).isoformat( - timespec='seconds' - ), - 'audit.creation_method': f'Written by ess.dream v{__version__}', - }, - schema=cif.CORE_SCHEMA, - ) - - -def _make_author_chunks(authors: CIFAuthors) -> list[cif.Chunk | cif.Loop]: - contact = [author for author in authors.authors if author.is_contact] - regular = [author for author in authors.authors if not author.is_contact] - - results = [] - roles = {} - for aut, cat in zip( - (contact, regular), ('audit_contact_author', 'audit_author'), strict=True - ): - if not aut: - continue - data, rols = _serialize_authors(aut, cat) - results.append(data) - roles.update(rols) - if roles: - results.append(_serialize_roles(roles)) - - return results - - -def _serialize_authors( - authors: list[CIFAuthor], category: str -) -> tuple[cif.Chunk | cif.Loop, dict[str, str]]: - fields = { - f'{category}.{key}': f - for key in ('name', 'email', 'address', 'id_orcid') - if any(f := [getattr(a, key) or '' for a in authors]) - } - - roles = {uuid.uuid4().hex: a.role for a in authors} - if any(roles.values()): - fields[f'{category}.id'] = list(roles.keys()) - roles = {key: val for key, val in roles.items() if val} - - if len(authors) == 1: - return cif.Chunk( - {key: val[0] for key, val in fields.items()}, - schema=cif.CORE_SCHEMA, - ), roles - return cif.Loop( - {key: sc.array(dims=['author'], values=val) for key, val in fields.items()}, - schema=cif.CORE_SCHEMA, - ), roles - - -def _serialize_roles(roles: dict[str, str]) -> cif.Loop: - return cif.Loop( - { - 'audit_author_role.id': sc.array(dims=['role'], values=list(roles)), - 'audit_author_role.role': sc.array( - dims=['role'], values=list(roles.values()) - ), - }, - schema=cif.CORE_SCHEMA, - ) diff --git a/src/ess/dream/workflow.py b/src/ess/dream/workflow.py index 2946212..d959c9c 100644 --- a/src/ess/dream/workflow.py +++ b/src/ess/dream/workflow.py @@ -1,6 +1,8 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2024 Scipp contributors (https://github.com/scipp) +import itertools + import sciline import scipp as sc @@ -13,9 +15,11 @@ VanadiumRun, ) -from .io.cif import CIFAuthors +from .io.cif import CIFAuthors, prepare_reduced_dspacing_cif from .io.geant4 import LoadGeant4Workflow +_dream_providers = (prepare_reduced_dspacing_cif,) + def default_parameters() -> dict: # Quantities not available in the simulated data @@ -38,7 +42,7 @@ def DreamGeant4Workflow() -> sciline.Pipeline: Workflow with default parameters for the Dream Geant4 simulation. """ wf = LoadGeant4Workflow() - for provider in powder_providers: + for provider in itertools.chain(powder_providers, _dream_providers): wf.insert(provider) for key, value in default_parameters().items(): wf[key] = value diff --git a/src/ess/powder/types.py b/src/ess/powder/types.py index dc8d5d4..1752151 100644 --- a/src/ess/powder/types.py +++ b/src/ess/powder/types.py @@ -16,6 +16,7 @@ from ess.reduce.nexus import generic_types as reduce_gt from ess.reduce.nexus import types as reduce_t from ess.reduce.uncertainty import UncertaintyBroadcastMode as _UncertaintyBroadcastMode +from scippneutron.io import cif # 1 TypeVars used to parametrize the generic parts of the workflow @@ -165,4 +166,10 @@ class RawDataAndMetadata(sciline.Scope[RunType, sc.DataGroup], sc.DataGroup): """WavelengthMask is a callable that returns a mask for a given WavelengthData.""" +CIFAuthors = NewType('CIFAuthors', list[cif.Author]) +"""List of authors to save to output CIF files.""" + +ReducedDspacingCIF = NewType('ReducedDspacingCIF', cif.CIF) +"""Reduced data in d-spacing, ready to be saved to a CIF file.""" + del sc, sciline, NewType, TypeVar diff --git a/tests/dream/io/cif_test.py b/tests/dream/io/cif_test.py index 6b03dac..6bf9d3f 100644 --- a/tests/dream/io/cif_test.py +++ b/tests/dream/io/cif_test.py @@ -2,18 +2,15 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) import io -import re -from typing import Any import pytest import scipp as sc +from scippneutron.io import cif import ess.dream.io.cif -from ess.dream.io.cif import CIFAuthor, CIFAuthors +from ess.dream.io.cif import CIFAuthors from ess.powder.types import IofDspacing -# TODO many more - @pytest.fixture() def iofd() -> IofDspacing: @@ -25,107 +22,29 @@ def iofd() -> IofDspacing: ) -def save_reduced_dspacing_to_str(*args: Any, **kwargs: Any) -> str: +def save_reduced_dspacing_to_str(cif_: cif.CIF) -> str: buffer = io.StringIO() - ess.dream.io.cif.save_reduced_dspacing(*args, filename=buffer, **kwargs) + cif_.save(buffer) buffer.seek(0) return buffer.read() -def test_save_reduced_dspacing_writes_contact_author(iofd: IofDspacing) -> None: - authors = CIFAuthors( - [ - CIFAuthor( - name='Jane Doe', - email='jane.doe@ess.eu', - address='Partikelgatan, Lund', - id_orcid='https://orcid.org/0000-0000-0000-0001', - ) - ] - ) - result = save_reduced_dspacing_to_str(iofd, authors=authors) - assert "_audit_contact_author.name 'Jane Doe'" in result - assert '_audit_contact_author.email jane.doe@ess.eu' in result - assert "_audit_contact_author.address 'Partikelgatan, Lund'" in result - assert ( - '_audit_contact_author.id_orcid https://orcid.org/0000-0000-0000-0001' in result - ) - +def test_save_reduced_dspacing(iofd: IofDspacing) -> None: + from ess.dream import __version__ -def test_save_reduced_dspacing_writes_regular_author(iofd: IofDspacing) -> None: - authors = CIFAuthors( - [ - CIFAuthor( - name='Jane Doe', - email='jane.doe@ess.eu', - address='Partikelgatan, Lund', - id_orcid='https://orcid.org/0000-0000-0000-0001', - is_contact=False, - ) - ] + author = cif.Author(name='John Doe') + cif_ = ess.dream.io.cif.prepare_reduced_dspacing_cif( + iofd, authors=CIFAuthors([author]) ) - result = save_reduced_dspacing_to_str(iofd, authors=authors) - assert "_audit_author.name 'Jane Doe'" in result - assert '_audit_author.email jane.doe@ess.eu' in result - assert "_audit_author.address 'Partikelgatan, Lund'" in result - assert '_audit_author.id_orcid https://orcid.org/0000-0000-0000-0001' in result + result = save_reduced_dspacing_to_str(cif_) + assert "_audit_contact_author.name 'John Doe'" in result + assert f"_computing.diffrn_reduction 'ess.dream v{__version__}'" in result + assert '_diffrn_source.beamline DREAM' in result -def test_save_reduced_dspacing_writes_multiple_regular_authors( - iofd: IofDspacing, -) -> None: - authors = CIFAuthors( - [ - CIFAuthor( - name='Jane Doe', - email='jane.doe@ess.eu', - address='Partikelgatan, Lund', - id_orcid='https://orcid.org/0000-0000-0000-0001', - is_contact=False, - ), - CIFAuthor( - name='Max Mustermann', - email='mm@scipp.eu', - id_orcid='https://orcid.org/0000-0000-0000-0002', - is_contact=False, - ), - ] - ) - result = save_reduced_dspacing_to_str(iofd, authors=authors) - # The missing address for Max is currently broken because of - # https://github.com/scipp/scippneutron/issues/547 - expected = """loop_ -_audit_author.name -_audit_author.email -_audit_author.address -_audit_author.id_orcid -'Jane Doe' jane.doe@ess.eu 'Partikelgatan, Lund' https://orcid.org/0000-0000-0000-0001 -'Max Mustermann' mm@scipp.eu https://orcid.org/0000-0000-0000-0002 + loop_header = """loop_ +_pd_proc.d_spacing +_pd_proc.intensity_net +_pd_proc.intensity_net_su """ - assert expected in result - - -def test_save_reduced_dspacing_writes_regular_author_role(iofd: IofDspacing) -> None: - authors = CIFAuthors( - [ - CIFAuthor( - name='Jane Doe', - role='measurement', - is_contact=False, - ) - ] - ) - result = save_reduced_dspacing_to_str(iofd, authors=authors) - - author_pattern = r"""_audit_author.name 'Jane Doe' -_audit_author.id ([0-9a-f]+)""" - author_match = re.search(author_pattern, result) - assert author_match is not None - author_id = author_match.group(1) - - expected = rf"""loop_ -_audit_author_role.id -_audit_author_role.role -{author_id} measurement""" - - assert expected in result + assert loop_header in result From ed07543e6e9929487d741bd3af89d891ee67ca84 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 19 Sep 2024 09:08:49 +0200 Subject: [PATCH 06/13] Require scippneutron>=24.9.0 Needed for new CIF builder --- pyproject.toml | 4 ++-- requirements/base.in | 2 +- requirements/base.txt | 2 +- requirements/ci.txt | 4 ++-- requirements/docs.txt | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index cf7825a..fc6d00a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,8 +37,8 @@ dependencies = [ "plopp", "pythreejs", "sciline>=24.06.0", - "scipp>=24.09.1", # Fixed new hist/bin API - "scippneutron>=24.5.0", + "scipp>=24.09.1", + "scippneutron>=24.9.0", "scippnexus>=23.12.0", ] diff --git a/requirements/base.in b/requirements/base.in index 5f380cc..a0365d0 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -10,5 +10,5 @@ plopp pythreejs sciline>=24.06.0 scipp>=24.09.1 -scippneutron>=24.5.0 +scippneutron>=24.9.0 scippnexus>=23.12.0 diff --git a/requirements/base.txt b/requirements/base.txt index 1e91667..638a29f 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,4 +1,4 @@ -# SHA1:6ce1bbccfc85ced70dedc62a2266b339f1e7c814 +# SHA1:2cad3df672e12033fa21254667278ceafae15e09 # # This file is autogenerated by pip-compile-multi # To update, run: diff --git a/requirements/ci.txt b/requirements/ci.txt index 28ed239..af1677b 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -38,7 +38,7 @@ platformdirs==4.3.6 # virtualenv pluggy==1.5.0 # via tox -pyproject-api==1.7.2 +pyproject-api==1.8.0 # via tox requests==2.32.3 # via -r ci.in @@ -48,7 +48,7 @@ tomli==2.0.1 # via # pyproject-api # tox -tox==4.19.0 +tox==4.20.0 # via -r ci.in urllib3==2.2.3 # via requests diff --git a/requirements/docs.txt b/requirements/docs.txt index 026f58a..3bea4bd 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -160,7 +160,7 @@ sphinx==8.0.2 # sphinx-copybutton # sphinx-design # sphinxcontrib-bibtex -sphinx-autodoc-typehints==2.4.3 +sphinx-autodoc-typehints==2.4.4 # via -r docs.in sphinx-copybutton==0.5.2 # via -r docs.in From 89cf198a7d3b29c7312d7c3daa6e494bdc170ac7 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 19 Sep 2024 09:19:58 +0200 Subject: [PATCH 07/13] Add a comment to the saved file --- .../dream/dream-data-reduction.ipynb | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/docs/user-guide/dream/dream-data-reduction.ipynb b/docs/user-guide/dream/dream-data-reduction.ipynb index fcdd129..00f6bd1 100644 --- a/docs/user-guide/dream/dream-data-reduction.ipynb +++ b/docs/user-guide/dream/dream-data-reduction.ipynb @@ -84,7 +84,7 @@ }, { "cell_type": "markdown", - "id": "8072fe3de2527f0e", + "id": "6", "metadata": {}, "source": [ "We also need some parameters to configure the output file:" @@ -93,7 +93,7 @@ { "cell_type": "code", "execution_count": null, - "id": "502e77cc-0253-4e71-9d97-81ff560ef99d", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -109,7 +109,7 @@ }, { "cell_type": "markdown", - "id": "6", + "id": "8", "metadata": {}, "source": [ "## Use the workflow\n", @@ -120,7 +120,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -129,7 +129,7 @@ }, { "cell_type": "markdown", - "id": "8", + "id": "10", "metadata": {}, "source": [ "We then call `compute()` to compute the result:\n", @@ -139,19 +139,19 @@ { "cell_type": "code", "execution_count": null, - "id": "9", + "id": "11", "metadata": {}, "outputs": [], "source": [ "results = workflow.compute([IofDspacing, ReducedDspacingCIF])\n", "result = results[IofDspacing]\n", - "cif = results[ReducedDspacingCIF]" + "cif_data = results[ReducedDspacingCIF]" ] }, { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "12", "metadata": {}, "outputs": [], "source": [ @@ -161,25 +161,30 @@ }, { "cell_type": "markdown", - "id": "11", + "id": "13", "metadata": {}, "source": [ - "We can now save the result to disk:" + "We can now save the result to disk:\n", + "(The comment is optional but helps to identify the file later.)" ] }, { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "14", "metadata": {}, "outputs": [], "source": [ - "cif.save('dspacing.cif')" + "cif_data.comment = \"\"\"This file was generated with the DREAM data reduction user guide\n", + "in the documentation of ESSdiffraction.\n", + "See https://scipp.github.io/essdiffraction/\n", + "\"\"\"\n", + "cif_data.save('dspacing.cif')" ] }, { "cell_type": "markdown", - "id": "13", + "id": "15", "metadata": {}, "source": [ "## Compute intermediate results\n", @@ -192,7 +197,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "16", "metadata": {}, "outputs": [], "source": [ @@ -209,7 +214,7 @@ { "cell_type": "code", "execution_count": null, - "id": "15", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -221,7 +226,7 @@ }, { "cell_type": "markdown", - "id": "16", + "id": "18", "metadata": {}, "source": [ "## Grouping by scattering angle\n", @@ -233,7 +238,7 @@ { "cell_type": "code", "execution_count": null, - "id": "17", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -245,7 +250,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -256,7 +261,7 @@ { "cell_type": "code", "execution_count": null, - "id": "19", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -274,7 +279,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "22", "metadata": {}, "outputs": [], "source": [ From 35b993731c502fc1edf1d338897f038a134723be Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 19 Sep 2024 09:20:38 +0200 Subject: [PATCH 08/13] Use correct return type --- src/ess/dream/io/cif.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ess/dream/io/cif.py b/src/ess/dream/io/cif.py index 136a066..c99d635 100644 --- a/src/ess/dream/io/cif.py +++ b/src/ess/dream/io/cif.py @@ -15,7 +15,7 @@ def prepare_reduced_dspacing_cif( """Construct a CIF builder with reduced data in d-spacing. The object contains the d-spacing coordinate, intensities, - and a number of metadata. + and some metadata. Parameters ---------- @@ -33,7 +33,7 @@ def prepare_reduced_dspacing_cif( from .. import __version__ to_save = _prepare_data(da) - return ( + return ReducedDspacingCIF( cif.CIF('reduced_dspacing') .with_reducers(f'ess.dream v{__version__}') .with_authors(*authors) From 3fbdc654b6454e17fb8de51dff5c13a029ab388e Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 19 Sep 2024 09:20:48 +0200 Subject: [PATCH 09/13] Fix package version --- src/ess/dream/__init__.py | 2 +- src/ess/powder/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ess/dream/__init__.py b/src/ess/dream/__init__.py index 8958e7f..68aae7b 100644 --- a/src/ess/dream/__init__.py +++ b/src/ess/dream/__init__.py @@ -12,7 +12,7 @@ from .workflow import DreamGeant4Workflow, default_parameters try: - __version__ = importlib.metadata.version(__package__ or __name__) + __version__ = importlib.metadata.version("essdiffraction") except importlib.metadata.PackageNotFoundError: __version__ = "0.0.0" diff --git a/src/ess/powder/__init__.py b/src/ess/powder/__init__.py index 577b71e..9ff2327 100644 --- a/src/ess/powder/__init__.py +++ b/src/ess/powder/__init__.py @@ -18,7 +18,7 @@ from .masking import with_pixel_mask_filenames try: - __version__ = importlib.metadata.version(__package__ or __name__) + __version__ = importlib.metadata.version("essdiffraction") except importlib.metadata.PackageNotFoundError: __version__ = "0.0.0" From 0a4f9693b544aa40f6477b2a2dec4c073dbbb995 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 19 Sep 2024 09:22:11 +0200 Subject: [PATCH 10/13] Apply ruff fixed --- src/ess/powder/types.py | 2 +- tests/dream/geant4_reduction_test.py | 2 +- tests/dream/io/cif_test.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ess/powder/types.py b/src/ess/powder/types.py index 1752151..c86fd4d 100644 --- a/src/ess/powder/types.py +++ b/src/ess/powder/types.py @@ -12,11 +12,11 @@ import sciline import scipp as sc +from scippneutron.io import cif from ess.reduce.nexus import generic_types as reduce_gt from ess.reduce.nexus import types as reduce_t from ess.reduce.uncertainty import UncertaintyBroadcastMode as _UncertaintyBroadcastMode -from scippneutron.io import cif # 1 TypeVars used to parametrize the generic parts of the workflow diff --git a/tests/dream/geant4_reduction_test.py b/tests/dream/geant4_reduction_test.py index 71c35cd..ff7c2df 100644 --- a/tests/dream/geant4_reduction_test.py +++ b/tests/dream/geant4_reduction_test.py @@ -7,9 +7,9 @@ import sciline import scipp as sc import scipp.testing -from ess import dream, powder import ess.dream.data # noqa: F401 +from ess import dream, powder from ess.dream.io.cif import CIFAuthor, CIFAuthors from ess.powder.types import ( AccumulatedProtonCharge, diff --git a/tests/dream/io/cif_test.py b/tests/dream/io/cif_test.py index 6bf9d3f..c97c797 100644 --- a/tests/dream/io/cif_test.py +++ b/tests/dream/io/cif_test.py @@ -12,7 +12,7 @@ from ess.powder.types import IofDspacing -@pytest.fixture() +@pytest.fixture def iofd() -> IofDspacing: return IofDspacing( sc.DataArray( From ff2186ec65c3a67e2fa66e63a7a1e9cee620dd4b Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 19 Sep 2024 09:31:00 +0200 Subject: [PATCH 11/13] Import from correct module --- tests/dream/io/cif_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/dream/io/cif_test.py b/tests/dream/io/cif_test.py index c97c797..bced1ee 100644 --- a/tests/dream/io/cif_test.py +++ b/tests/dream/io/cif_test.py @@ -8,8 +8,7 @@ from scippneutron.io import cif import ess.dream.io.cif -from ess.dream.io.cif import CIFAuthors -from ess.powder.types import IofDspacing +from ess.powder.types import CIFAuthors, IofDspacing @pytest.fixture From 055045796649bf28fe9d5b6245940cfcc8f4ad57 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 19 Sep 2024 09:44:39 +0200 Subject: [PATCH 12/13] Fix tests to use new CIF interface --- tests/dream/geant4_reduction_test.py | 37 ++++++++++++++++------------ 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/tests/dream/geant4_reduction_test.py b/tests/dream/geant4_reduction_test.py index ff7c2df..f642bdd 100644 --- a/tests/dream/geant4_reduction_test.py +++ b/tests/dream/geant4_reduction_test.py @@ -7,14 +7,15 @@ import sciline import scipp as sc import scipp.testing +from scippneutron.io.cif import Author import ess.dream.data # noqa: F401 from ess import dream, powder -from ess.dream.io.cif import CIFAuthor, CIFAuthors from ess.powder.types import ( AccumulatedProtonCharge, BackgroundRun, CalibrationFilename, + CIFAuthors, DspacingBins, Filename, IofDspacing, @@ -24,7 +25,7 @@ NeXusSample, NeXusSource, NormalizedByProtonCharge, - OutFilename, + ReducedDspacingCIF, SampleRun, TofMask, TwoThetaBins, @@ -57,8 +58,8 @@ WavelengthMask: None, CIFAuthors: CIFAuthors( [ - CIFAuthor( - name="Jane Doe", email="jane.doe@ess.eu", id_orcid="0000-0000-0000-0001" + Author( + name="Jane Doe", email="jane.doe@ess.eu", orcid="0000-0000-0000-0001" ), ] ), @@ -159,26 +160,19 @@ def test_use_workflow_helper(workflow): def test_pipeline_can_save_data(workflow): - def get_result(da: IofDspacing) -> IofDspacing: - return da - - buffer = io.StringIO() - workflow[OutFilename] = buffer workflow = powder.with_pixel_mask_filenames(workflow, []) + result = workflow.compute(ReducedDspacingCIF) - result, expected = workflow.bind_and_call( - [dream.io.save_reduced_dspacing, get_result] - ) - sc.testing.assert_identical(result, expected) - + buffer = io.StringIO() + result.save(buffer) buffer.seek(0) content = buffer.read() - # print(content) - # assert False assert content.startswith(r'#\#CIF_1.1') _assert_contains_source_info(content) _assert_contains_author_info(content) + _assert_contains_beamline_info(content) + _assert_contains_dspacing_data(content) def _assert_contains_source_info(cif_content: str) -> None: @@ -188,3 +182,14 @@ def _assert_contains_source_info(cif_content: str) -> None: def _assert_contains_author_info(cif_content: str) -> None: assert "audit_contact_author.name 'Jane Doe'" in cif_content assert 'audit_contact_author.email jane.doe@ess.eu' in cif_content + + +def _assert_contains_beamline_info(cif_content: str) -> None: + assert 'diffrn_source.beamline DREAM' in cif_content + assert 'diffrn_source.facility ESS' in cif_content + + +def _assert_contains_dspacing_data(cif_content: str) -> None: + assert 'pd_proc.d_spacing' in cif_content + assert 'pd_proc.intensity_net' in cif_content + assert 'pd_proc.intensity_net_su' in cif_content From 8380d2741dc8f16c3764ec1ac2cefba7a029613f Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 19 Sep 2024 11:09:40 +0200 Subject: [PATCH 13/13] Check orcid id in cif --- tests/dream/geant4_reduction_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/dream/geant4_reduction_test.py b/tests/dream/geant4_reduction_test.py index f642bdd..980094c 100644 --- a/tests/dream/geant4_reduction_test.py +++ b/tests/dream/geant4_reduction_test.py @@ -182,6 +182,7 @@ def _assert_contains_source_info(cif_content: str) -> None: def _assert_contains_author_info(cif_content: str) -> None: assert "audit_contact_author.name 'Jane Doe'" in cif_content assert 'audit_contact_author.email jane.doe@ess.eu' in cif_content + assert 'audit_contact_author.id_orcid 0000-0000-0000-0001' in cif_content def _assert_contains_beamline_info(cif_content: str) -> None: