operandomerge 0.1.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.
- operandomerge-0.1.1/.github/workflows/ci.yml +82 -0
- operandomerge-0.1.1/.github/workflows/release.yml +73 -0
- operandomerge-0.1.1/.gitignore +14 -0
- operandomerge-0.1.1/CHANGELOG.md +29 -0
- operandomerge-0.1.1/CITATION.cff +10 -0
- operandomerge-0.1.1/CONTRIBUTING.md +20 -0
- operandomerge-0.1.1/LICENSE +22 -0
- operandomerge-0.1.1/PKG-INFO +244 -0
- operandomerge-0.1.1/README.md +203 -0
- operandomerge-0.1.1/docs/configuration.md +28 -0
- operandomerge-0.1.1/docs/dependency-licenses.md +19 -0
- operandomerge-0.1.1/docs/images/example-alignment.png +0 -0
- operandomerge-0.1.1/docs/images/showcase-before-after.png +0 -0
- operandomerge-0.1.1/docs/images/social-preview.png +0 -0
- operandomerge-0.1.1/docs/interchange-draft.md +61 -0
- operandomerge-0.1.1/docs/scientific-validation.md +43 -0
- operandomerge-0.1.1/examples/example-config.json +47 -0
- operandomerge-0.1.1/examples/gc.csv +4 -0
- operandomerge-0.1.1/examples/ms.csv +6 -0
- operandomerge-0.1.1/examples/reactor_logger.csv +6 -0
- operandomerge-0.1.1/examples/showcase/README.md +46 -0
- operandomerge-0.1.1/examples/showcase/config.json +134 -0
- operandomerge-0.1.1/examples/showcase/gas_chromatograph.csv +4 -0
- operandomerge-0.1.1/examples/showcase/generate_showcase.py +342 -0
- operandomerge-0.1.1/examples/showcase/mass_spectrometer.csv +302 -0
- operandomerge-0.1.1/examples/showcase/mfc_controller.csv +31 -0
- operandomerge-0.1.1/examples/showcase/reactor_logger.csv +62 -0
- operandomerge-0.1.1/examples/showcase/xrd_scans.csv +12 -0
- operandomerge-0.1.1/pyproject.toml +83 -0
- operandomerge-0.1.1/src/operandomerge/__init__.py +26 -0
- operandomerge-0.1.1/src/operandomerge/cli.py +84 -0
- operandomerge-0.1.1/src/operandomerge/config.py +94 -0
- operandomerge-0.1.1/src/operandomerge/controller.py +63 -0
- operandomerge-0.1.1/src/operandomerge/export.py +66 -0
- operandomerge-0.1.1/src/operandomerge/gui.py +506 -0
- operandomerge-0.1.1/src/operandomerge/io.py +27 -0
- operandomerge-0.1.1/src/operandomerge/merge.py +252 -0
- operandomerge-0.1.1/src/operandomerge/models.py +194 -0
- operandomerge-0.1.1/src/operandomerge/py.typed +1 -0
- operandomerge-0.1.1/src/operandomerge/qc.py +73 -0
- operandomerge-0.1.1/src/operandomerge/service.py +20 -0
- operandomerge-0.1.1/src/operandomerge/timeline.py +141 -0
- operandomerge-0.1.1/tests/conftest.py +21 -0
- operandomerge-0.1.1/tests/integration/test_cli_gui.py +111 -0
- operandomerge-0.1.1/tests/integration/test_io_config_export.py +107 -0
- operandomerge-0.1.1/tests/scientific/test_known_offsets.py +22 -0
- operandomerge-0.1.1/tests/scientific/test_type_aware_merge.py +185 -0
- operandomerge-0.1.1/tests/showcase/test_operando_showcase.py +145 -0
- operandomerge-0.1.1/tests/unit/test_models.py +100 -0
- operandomerge-0.1.1/tests/unit/test_qc.py +20 -0
- operandomerge-0.1.1/tests/unit/test_release_workflow.py +15 -0
- operandomerge-0.1.1/tests/unit/test_timeline.py +88 -0
- operandomerge-0.1.1/tests/unit/test_version_metadata.py +29 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: true
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
quality:
|
|
16
|
+
name: Lint and type check
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
20
|
+
with:
|
|
21
|
+
persist-credentials: false
|
|
22
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.12"
|
|
25
|
+
cache: pip
|
|
26
|
+
- run: python -m pip install -e '.[dev]'
|
|
27
|
+
- run: ruff check .
|
|
28
|
+
- run: mypy src
|
|
29
|
+
|
|
30
|
+
test:
|
|
31
|
+
name: Test Python ${{ matrix.python-version }}
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
strategy:
|
|
34
|
+
matrix:
|
|
35
|
+
python-version: ["3.10", "3.12"]
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
38
|
+
with:
|
|
39
|
+
persist-credentials: false
|
|
40
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
|
|
41
|
+
with:
|
|
42
|
+
python-version: ${{ matrix.python-version }}
|
|
43
|
+
cache: pip
|
|
44
|
+
- run: python -m pip install -e '.[dev]'
|
|
45
|
+
- run: pytest
|
|
46
|
+
- run: operandomerge inspect examples/reactor_logger.csv
|
|
47
|
+
- run: operandomerge merge examples/example-config.json --excel /tmp/report.xlsx --plot /tmp/alignment.png
|
|
48
|
+
- run: test -s /tmp/report.xlsx && test -s /tmp/alignment.png
|
|
49
|
+
- if: matrix.python-version == '3.12'
|
|
50
|
+
run: >-
|
|
51
|
+
python examples/showcase/generate_showcase.py
|
|
52
|
+
--output-dir /tmp/operandomerge-showcase
|
|
53
|
+
- if: matrix.python-version == '3.12'
|
|
54
|
+
run: >-
|
|
55
|
+
test -s /tmp/operandomerge-showcase/operandomerge-showcase.xlsx &&
|
|
56
|
+
test -s /tmp/operandomerge-showcase/before-after.png &&
|
|
57
|
+
test -s docs/images/showcase-before-after.png &&
|
|
58
|
+
test -s docs/images/social-preview.png
|
|
59
|
+
- if: matrix.python-version == '3.12'
|
|
60
|
+
run: sudo apt-get update && sudo apt-get install -y python3-tk xvfb
|
|
61
|
+
- if: matrix.python-version == '3.12'
|
|
62
|
+
run: >-
|
|
63
|
+
xvfb-run -a python -c
|
|
64
|
+
"from operandomerge.gui import create_app;
|
|
65
|
+
root, app = create_app(); root.update(); root.destroy()"
|
|
66
|
+
|
|
67
|
+
package:
|
|
68
|
+
name: Build and clean-install package
|
|
69
|
+
runs-on: ubuntu-latest
|
|
70
|
+
steps:
|
|
71
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
72
|
+
with:
|
|
73
|
+
persist-credentials: false
|
|
74
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
|
|
75
|
+
with:
|
|
76
|
+
python-version: "3.12"
|
|
77
|
+
cache: pip
|
|
78
|
+
- run: python -m pip install build
|
|
79
|
+
- run: python -m build
|
|
80
|
+
- run: python -m venv /tmp/operandomerge-clean
|
|
81
|
+
- run: /tmp/operandomerge-clean/bin/pip install dist/*.whl
|
|
82
|
+
- run: /tmp/operandomerge-clean/bin/operandomerge --version
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
name: Publish released package
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
concurrency:
|
|
11
|
+
group: release-${{ github.event.release.id }}
|
|
12
|
+
cancel-in-progress: false
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
build:
|
|
16
|
+
name: Build and verify release artifacts
|
|
17
|
+
if: github.event.release.prerelease == false
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
21
|
+
with:
|
|
22
|
+
persist-credentials: false
|
|
23
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
|
|
24
|
+
with:
|
|
25
|
+
python-version: "3.12"
|
|
26
|
+
- run: python -m pip install build twine
|
|
27
|
+
- run: python -m build
|
|
28
|
+
- run: python -m twine check dist/*
|
|
29
|
+
- run: python -m venv /tmp/operandomerge-release
|
|
30
|
+
- run: /tmp/operandomerge-release/bin/pip install dist/*.whl
|
|
31
|
+
- run: /tmp/operandomerge-release/bin/python -m pip check
|
|
32
|
+
- run: >-
|
|
33
|
+
/tmp/operandomerge-release/bin/python -c
|
|
34
|
+
"import operandomerge; print(operandomerge.__version__)"
|
|
35
|
+
- name: Verify release tag matches installed package
|
|
36
|
+
env:
|
|
37
|
+
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
38
|
+
run: |
|
|
39
|
+
INSTALLED_VERSION=$(/tmp/operandomerge-release/bin/python -c "import operandomerge; print(operandomerge.__version__)")
|
|
40
|
+
test "${RELEASE_TAG}" = "v${INSTALLED_VERSION}"
|
|
41
|
+
- run: /tmp/operandomerge-release/bin/operandomerge --help
|
|
42
|
+
- run: >-
|
|
43
|
+
/tmp/operandomerge-release/bin/operandomerge merge
|
|
44
|
+
examples/showcase/config.json
|
|
45
|
+
--excel /tmp/release-showcase.xlsx
|
|
46
|
+
--plot /tmp/release-showcase.png
|
|
47
|
+
- run: test -s /tmp/release-showcase.xlsx && test -s /tmp/release-showcase.png
|
|
48
|
+
- run: sudo apt-get update && sudo apt-get install -y python3-tk xvfb
|
|
49
|
+
- run: >-
|
|
50
|
+
xvfb-run -a /tmp/operandomerge-release/bin/python -c
|
|
51
|
+
"from operandomerge.gui import create_app;
|
|
52
|
+
root, app = create_app(); root.update(); root.destroy()"
|
|
53
|
+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
54
|
+
with:
|
|
55
|
+
name: python-package
|
|
56
|
+
path: dist/
|
|
57
|
+
if-no-files-found: error
|
|
58
|
+
|
|
59
|
+
publish:
|
|
60
|
+
name: Publish to PyPI with trusted publishing
|
|
61
|
+
needs: build
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
environment:
|
|
64
|
+
name: pypi
|
|
65
|
+
url: https://pypi.org/p/operandomerge
|
|
66
|
+
permissions:
|
|
67
|
+
id-token: write # Required for PyPI trusted publishing; no API token is stored.
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
70
|
+
with:
|
|
71
|
+
name: python-package
|
|
72
|
+
path: dist/
|
|
73
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes follow [Keep a Changelog](https://keepachangelog.com/) and
|
|
4
|
+
the project uses [Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## [0.1.1] - Unreleased
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- Five-instrument operando showcase with reactor, MFC, MS, GC, and XRD clocks.
|
|
11
|
+
- Actual before/after and social-preview images generated from `MergeService` results.
|
|
12
|
+
- Showcase regressions for known delays, boundary semantics, provenance, and GC non-interpolation.
|
|
13
|
+
- Experimental interchange concepts for channels, units, metadata, provenance, QC, and sources.
|
|
14
|
+
- Release-triggered trusted-publishing workflow with isolated build and publish jobs.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Expanded project metadata, README quickstart, assumptions, limitations, and related-tool links.
|
|
19
|
+
- CI now regenerates and verifies the full showcase on Python 3.12.
|
|
20
|
+
|
|
21
|
+
## [0.1.0] - 2026-08-23
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- Lossless time normalization for absolute, injection, elapsed, and local clocks.
|
|
26
|
+
- Manual/reference-event alignment and explicit physical delay components.
|
|
27
|
+
- Data-type-aware merge without discrete/event interpolation.
|
|
28
|
+
- Value provenance, QC, plots, CSV/Excel export, CLI, GUI, and public API.
|
|
29
|
+
- Synthetic scientific regression suite and reproducible example workflow.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use OperandoMerge in research, please cite this software."
|
|
3
|
+
title: "OperandoMerge"
|
|
4
|
+
type: software
|
|
5
|
+
version: 0.1.1
|
|
6
|
+
authors:
|
|
7
|
+
- family-names: "Kim"
|
|
8
|
+
given-names: "Hyun Dong"
|
|
9
|
+
repository-code: "https://github.com/hdkim99/OperandoMerge"
|
|
10
|
+
license: MIT
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Please open an issue before changing scientific definitions. A contribution must
|
|
4
|
+
preserve raw values, document clock/delay semantics, include a hand-checkable or
|
|
5
|
+
synthetic regression case, and keep CLI/GUI calculations in `MergeService`/core.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
python -m venv .venv
|
|
9
|
+
. .venv/bin/activate
|
|
10
|
+
python -m pip install -e '.[dev]'
|
|
11
|
+
ruff check .
|
|
12
|
+
mypy src
|
|
13
|
+
pytest
|
|
14
|
+
python -m build
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Use focused commits. Do not weaken tolerances merely to pass a noisy test. Report
|
|
18
|
+
whether a failure is an implementation, test, scientific-definition, unit,
|
|
19
|
+
data-model, or environment problem.
|
|
20
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OperandoMerge contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: operandomerge
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Synchronize heterogeneous experimental data onto one reproducible timeline.
|
|
5
|
+
Project-URL: Homepage, https://github.com/hdkim99/OperandoMerge
|
|
6
|
+
Project-URL: Documentation, https://github.com/hdkim99/OperandoMerge#readme
|
|
7
|
+
Project-URL: Issues, https://github.com/hdkim99/OperandoMerge/issues
|
|
8
|
+
Project-URL: Source, https://github.com/hdkim99/OperandoMerge
|
|
9
|
+
Project-URL: Changelog, https://github.com/hdkim99/OperandoMerge/blob/main/CHANGELOG.md
|
|
10
|
+
Author: Hyun Dong Kim
|
|
11
|
+
Maintainer: Hyun Dong Kim
|
|
12
|
+
License-Expression: MIT
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Keywords: catalysis,chemical-engineering,operando,scientific-data,synchronization,time-series
|
|
15
|
+
Classifier: Development Status :: 3 - Alpha
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
|
+
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
26
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
27
|
+
Classifier: Typing :: Typed
|
|
28
|
+
Requires-Python: >=3.10
|
|
29
|
+
Requires-Dist: matplotlib<4,>=3.7
|
|
30
|
+
Requires-Dist: numpy<3,>=1.24
|
|
31
|
+
Requires-Dist: openpyxl<4,>=3.1
|
|
32
|
+
Requires-Dist: pandas<3,>=2.0
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
35
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
36
|
+
Requires-Dist: pandas-stubs>=2.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: pytest-cov>=5; extra == 'dev'
|
|
38
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
39
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
# OperandoMerge
|
|
43
|
+
|
|
44
|
+
> Heterogeneous instruments. One reproducible experiment timeline.
|
|
45
|
+
|
|
46
|
+
[](https://github.com/hdkim99/OperandoMerge/actions/workflows/ci.yml)
|
|
47
|
+
[](https://www.python.org/)
|
|
48
|
+
[](LICENSE)
|
|
49
|
+
|
|
50
|
+
OperandoMerge aligns reactor loggers, MFCs, high-frequency MS, sparse GC, XRD,
|
|
51
|
+
Raman, FTIR, and other CSV/XLSX logs without hiding where values came from. It
|
|
52
|
+
uses channel semantics to interpolate continuous measurements, hold stepwise
|
|
53
|
+
setpoints causally, and keep event/discrete samples strictly discrete.
|
|
54
|
+
|
|
55
|
+

|
|
56
|
+
|
|
57
|
+
The figure is generated from the repository's real five-instrument synthetic
|
|
58
|
+
workflow. Purple GC values exist only at 120, 300, and 480 s: the other 298
|
|
59
|
+
canonical rows remain missing rather than receiving invented chromatograms.
|
|
60
|
+
|
|
61
|
+
## Install
|
|
62
|
+
|
|
63
|
+
Python 3.10 or newer is required. PyPI publication is prepared but is not yet
|
|
64
|
+
available, so install from the public source repository:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
python -m pip install "operandomerge @ git+https://github.com/hdkim99/OperandoMerge.git"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
For development:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
git clone https://github.com/hdkim99/OperandoMerge.git
|
|
74
|
+
cd OperandoMerge
|
|
75
|
+
python -m pip install -e '.[dev]'
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## 30-second showcase
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
mkdir -p showcase-output
|
|
82
|
+
|
|
83
|
+
operandomerge inspect examples/showcase/reactor_logger.csv
|
|
84
|
+
|
|
85
|
+
operandomerge merge examples/showcase/config.json \
|
|
86
|
+
--excel showcase-output/operandomerge-showcase.xlsx \
|
|
87
|
+
--plot showcase-output/alignment-cli.png
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Expected CLI summary:
|
|
91
|
+
|
|
92
|
+
```text
|
|
93
|
+
Merged 5 dataset(s), 301 timeline row(s); QC: 0 error(s), 0 warning(s)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The Excel report contains complete `merged`, `metadata`, `provenance`, `qc`, and
|
|
97
|
+
`configuration` sheets. To regenerate the source CSVs and showcase figures from
|
|
98
|
+
their deterministic equations:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
python examples/showcase/generate_showcase.py --output-dir showcase-output
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Launch the same workflow through the desktop UI with:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
operandomerge-gui
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Python's Tk bindings are included with python.org installers. Some distro or
|
|
111
|
+
Homebrew Python builds require their matching optional Tk package, such as
|
|
112
|
+
`python3-tk` on Debian/Ubuntu.
|
|
113
|
+
|
|
114
|
+
## What is being aligned?
|
|
115
|
+
|
|
116
|
+
The showcase represents one 600 s catalyst experiment with deliberately
|
|
117
|
+
different clocks and sampling intervals:
|
|
118
|
+
|
|
119
|
+
| Instrument | Raw sampling | Alignment evidence | Result semantics |
|
|
120
|
+
|---|---:|---|---|
|
|
121
|
+
| Reactor logger | 10 s | absolute UTC experiment origin | temperature/pressure, continuous |
|
|
122
|
+
| MFC controller | 20 s | local event at 100 s = experiment event at 120 s | H₂/Ar flow, stepwise |
|
|
123
|
+
| MS | 2 s | known 8 s transport delay | m/z 44/28, continuous |
|
|
124
|
+
| GC | three injections | 12 s sampling + 18 s analysis delay | compositions, discrete samples |
|
|
125
|
+
| XRD | 60 s | −5 s clock offset + 15 s analysis delay | phase stepwise; lattice discrete |
|
|
126
|
+
|
|
127
|
+
The raw clocks and applied corrections remain in metadata/provenance. See the
|
|
128
|
+
[showcase definition](examples/showcase/README.md) for hand-checkable invariants.
|
|
129
|
+
|
|
130
|
+
## Scientific rules
|
|
131
|
+
|
|
132
|
+
The canonical coordinate is `experiment_time_s`:
|
|
133
|
+
|
|
134
|
+
```text
|
|
135
|
+
experiment_time_s = source_time_s + alignment_offset_s - total_delay_s
|
|
136
|
+
total_delay_s = manual + sampling + transport + dead_volume + analysis
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
A positive delay means a reported value corresponds to an earlier physical event,
|
|
140
|
+
so it is subtracted. Reference-event alignment uses
|
|
141
|
+
`target_event_time_s - source_event_time_s`. Absolute timestamps use an explicit
|
|
142
|
+
ISO-8601 experiment origin when provided; otherwise the earliest absolute record
|
|
143
|
+
becomes zero.
|
|
144
|
+
|
|
145
|
+
| Channel semantic | Available policy | Scientific constraint |
|
|
146
|
+
|---|---|---|
|
|
147
|
+
| `continuous` | linear, nearest, none | bounded by measured range; no extrapolation |
|
|
148
|
+
| `stepwise` | previous, none | causal hold; never takes a future setpoint |
|
|
149
|
+
| `event` | exact timestamp only | never interpolated |
|
|
150
|
+
| `discrete_sample` | exact timestamp only | never interpolated |
|
|
151
|
+
|
|
152
|
+
For every emitted value, provenance identifies the source file, column, row,
|
|
153
|
+
original timestamp, offset, delay, and interpolation method. Linear values retain
|
|
154
|
+
both bracketing source rows/timestamps.
|
|
155
|
+
|
|
156
|
+
## GUI and Python API
|
|
157
|
+
|
|
158
|
+
The GUI workflow is: add files → map clocks/channels → assign channel semantics →
|
|
159
|
+
enter offsets/delays/events → choose the timeline → preview → inspect values/QC →
|
|
160
|
+
export. Controls are converted to the same configuration models used by the CLI;
|
|
161
|
+
the GUI contains no independent scientific formulas.
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from pathlib import Path
|
|
165
|
+
|
|
166
|
+
from operandomerge.config import load_config
|
|
167
|
+
from operandomerge.export import export_excel
|
|
168
|
+
from operandomerge.service import MergeService
|
|
169
|
+
|
|
170
|
+
datasets, policy = load_config(Path("examples/showcase/config.json"))
|
|
171
|
+
result = MergeService().run(datasets, policy)
|
|
172
|
+
export_excel(result, Path("operandomerge-showcase.xlsx"))
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Supported, experimental, planned
|
|
176
|
+
|
|
177
|
+
Supported in 0.1.1:
|
|
178
|
+
|
|
179
|
+
- multiple CSV/XLSX inputs and one selected worksheet per dataset;
|
|
180
|
+
- absolute/injection timestamps, elapsed seconds/minutes, and midnight-wrapping
|
|
181
|
+
instrument-local clocks;
|
|
182
|
+
- absolute, elapsed, manual-offset, and reference-event alignment;
|
|
183
|
+
- explicit manual/sampling/transport/dead-volume/analysis delays;
|
|
184
|
+
- union or named-reference timeline, type-aware merging, QC, provenance, figures,
|
|
185
|
+
CSV bundle, Excel, CLI, Tk GUI, and public Python API; and
|
|
186
|
+
- Python 3.10+ packaging with scientific/unit/integration/showcase regressions.
|
|
187
|
+
|
|
188
|
+
Experimental:
|
|
189
|
+
|
|
190
|
+
- automatic GUI time-column guesses, which must be reviewed;
|
|
191
|
+
- robust-MAD possible-outlier warnings; and
|
|
192
|
+
- the [interchange draft](docs/interchange-draft.md), which documents concepts
|
|
193
|
+
but is not a stable cross-project contract.
|
|
194
|
+
|
|
195
|
+
Planned, not implemented:
|
|
196
|
+
|
|
197
|
+
- cross-correlation alignment. It will not be added until candidate offsets have
|
|
198
|
+
quantitative confidence, multi-channel agreement, a visual approval step, and
|
|
199
|
+
complete provenance;
|
|
200
|
+
- vendor-native binary adapters;
|
|
201
|
+
- automatic dead-volume calculation from apparatus geometry; and
|
|
202
|
+
- configurable regular target grids.
|
|
203
|
+
|
|
204
|
+
## Assumptions and limitations
|
|
205
|
+
|
|
206
|
+
- OperandoMerge cannot prove that two clock events represent the same physical
|
|
207
|
+
event. Users must justify every offset and delay.
|
|
208
|
+
- Signal units are preserved as source metadata/names but are not converted or
|
|
209
|
+
dimensionally validated in this release.
|
|
210
|
+
- Numeric channels are required for resampling. Categorical phase labels should be
|
|
211
|
+
encoded as documented numeric states or retained outside the merged value table.
|
|
212
|
+
- On a named reference timeline, off-grid event/discrete measurements remain
|
|
213
|
+
absent rather than being snapped or interpolated.
|
|
214
|
+
- Duplicate times are reported by QC; numeric merging deterministically uses the
|
|
215
|
+
final row at that time while raw files remain untouched.
|
|
216
|
+
- GUI tables preview up to 500 rows; exports always contain the complete result.
|
|
217
|
+
- Synthetic curves demonstrate synchronization behavior, not validated reactor
|
|
218
|
+
kinetics, mass balances, or diffraction physics.
|
|
219
|
+
|
|
220
|
+
Validation details are in [scientific validation](docs/scientific-validation.md),
|
|
221
|
+
and every JSON setting is described in the
|
|
222
|
+
[configuration reference](docs/configuration.md).
|
|
223
|
+
|
|
224
|
+
## Related tools
|
|
225
|
+
|
|
226
|
+
These are independent repositories. Direct interoperability is planned, not
|
|
227
|
+
currently claimed:
|
|
228
|
+
|
|
229
|
+
- [Ordifile](https://github.com/hdkim99/ordifile) — chromatographic file conversion
|
|
230
|
+
- [ReactorCheck](https://github.com/hdkim99/ReactorCheck) — catalytic reactor calculation and QC
|
|
231
|
+
- [TPxLab](https://github.com/hdkim99/TPxLab) — temperature-programmed characterization analysis
|
|
232
|
+
|
|
233
|
+
## Development and citation
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
ruff check .
|
|
237
|
+
mypy src
|
|
238
|
+
pytest
|
|
239
|
+
python -m build
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Contributions are welcome under [CONTRIBUTING.md](CONTRIBUTING.md). Cite the
|
|
243
|
+
software using [CITATION.cff](CITATION.cff). The project is MIT-licensed; the
|
|
244
|
+
[dependency license review](docs/dependency-licenses.md) records compatibility.
|