ftproductlab 0.1.0__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.
Files changed (51) hide show
  1. ftproductlab-0.1.0/.github/ISSUE_TEMPLATE/bug.yml +20 -0
  2. ftproductlab-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  3. ftproductlab-0.1.0/.github/ISSUE_TEMPLATE/dataset.yml +24 -0
  4. ftproductlab-0.1.0/.github/ISSUE_TEMPLATE/feature.yml +17 -0
  5. ftproductlab-0.1.0/.github/ISSUE_TEMPLATE/macos-gui.yml +36 -0
  6. ftproductlab-0.1.0/.github/ISSUE_TEMPLATE/scientific-result.yml +20 -0
  7. ftproductlab-0.1.0/.github/actionlint.yaml +3 -0
  8. ftproductlab-0.1.0/.github/dependabot.yml +10 -0
  9. ftproductlab-0.1.0/.github/workflows/ci.yml +98 -0
  10. ftproductlab-0.1.0/.github/workflows/macos.yml +74 -0
  11. ftproductlab-0.1.0/.github/workflows/release.yml +53 -0
  12. ftproductlab-0.1.0/.gitignore +11 -0
  13. ftproductlab-0.1.0/CHANGELOG.md +9 -0
  14. ftproductlab-0.1.0/CITATION.cff +26 -0
  15. ftproductlab-0.1.0/CONTRIBUTING.md +26 -0
  16. ftproductlab-0.1.0/LICENSE +28 -0
  17. ftproductlab-0.1.0/PKG-INFO +198 -0
  18. ftproductlab-0.1.0/README.md +158 -0
  19. ftproductlab-0.1.0/assets/social-preview.png +0 -0
  20. ftproductlab-0.1.0/docs/macos.md +35 -0
  21. ftproductlab-0.1.0/docs/naming-audit.md +52 -0
  22. ftproductlab-0.1.0/docs/scientific-basis.md +71 -0
  23. ftproductlab-0.1.0/docs/validation.md +30 -0
  24. ftproductlab-0.1.0/examples/sample_distribution.csv +32 -0
  25. ftproductlab-0.1.0/pyproject.toml +100 -0
  26. ftproductlab-0.1.0/scripts/run_example.py +26 -0
  27. ftproductlab-0.1.0/src/ftproductlab/__init__.py +32 -0
  28. ftproductlab-0.1.0/src/ftproductlab/__main__.py +5 -0
  29. ftproductlab-0.1.0/src/ftproductlab/application/__init__.py +17 -0
  30. ftproductlab-0.1.0/src/ftproductlab/application/service.py +85 -0
  31. ftproductlab-0.1.0/src/ftproductlab/cli/__init__.py +5 -0
  32. ftproductlab-0.1.0/src/ftproductlab/cli/main.py +96 -0
  33. ftproductlab-0.1.0/src/ftproductlab/core/__init__.py +41 -0
  34. ftproductlab-0.1.0/src/ftproductlab/core/asf.py +325 -0
  35. ftproductlab-0.1.0/src/ftproductlab/core/models.py +180 -0
  36. ftproductlab-0.1.0/src/ftproductlab/gui/__init__.py +3 -0
  37. ftproductlab-0.1.0/src/ftproductlab/gui/__main__.py +26 -0
  38. ftproductlab-0.1.0/src/ftproductlab/gui/app.py +190 -0
  39. ftproductlab-0.1.0/src/ftproductlab/io/__init__.py +6 -0
  40. ftproductlab-0.1.0/src/ftproductlab/io/csv.py +71 -0
  41. ftproductlab-0.1.0/src/ftproductlab/io/export.py +81 -0
  42. ftproductlab-0.1.0/src/ftproductlab/plotting/__init__.py +5 -0
  43. ftproductlab-0.1.0/src/ftproductlab/plotting/figures.py +165 -0
  44. ftproductlab-0.1.0/tests/gui/test_workflow.py +31 -0
  45. ftproductlab-0.1.0/tests/integration/test_cli.py +54 -0
  46. ftproductlab-0.1.0/tests/integration/test_import_isolation.py +15 -0
  47. ftproductlab-0.1.0/tests/integration/test_plotting.py +20 -0
  48. ftproductlab-0.1.0/tests/macos/test_macos_lifecycle.py +18 -0
  49. ftproductlab-0.1.0/tests/unit/test_aggregation.py +54 -0
  50. ftproductlab-0.1.0/tests/unit/test_asf.py +73 -0
  51. ftproductlab-0.1.0/tests/unit/test_csv_io.py +28 -0
@@ -0,0 +1,20 @@
1
+ name: Bug report
2
+ description: Report reproducible software behavior that appears incorrect.
3
+ title: "[Bug]: "
4
+ labels: [bug]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: Do not upload unpublished, confidential, proprietary, or identifying research data.
9
+ - type: textarea
10
+ id: description
11
+ attributes: {label: What happened?, description: Include the command and expected behavior.}
12
+ validations: {required: true}
13
+ - type: input
14
+ id: version
15
+ attributes: {label: FTProductLab version}
16
+ validations: {required: true}
17
+ - type: textarea
18
+ id: reproducer
19
+ attributes: {label: Minimal public or synthetic reproducer}
20
+ validations: {required: true}
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security report
4
+ url: https://github.com/hdkim99/FTProductLab/security/advisories/new
5
+ about: Privately report a security vulnerability.
@@ -0,0 +1,24 @@
1
+ name: Real dataset compatibility
2
+ description: Propose a public dataset or report a documented import limitation.
3
+ title: "[Dataset]: "
4
+ labels: [dataset]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: Only public, redistributable data may be linked. Do not attach confidential research data.
9
+ - type: input
10
+ id: doi
11
+ attributes: {label: DOI or stable repository URL}
12
+ validations: {required: true}
13
+ - type: input
14
+ id: license
15
+ attributes: {label: Dataset license}
16
+ validations: {required: true}
17
+ - type: textarea
18
+ id: schema
19
+ attributes: {label: Files, checksum, and column definitions}
20
+ validations: {required: true}
21
+ - type: textarea
22
+ id: scope
23
+ attributes: {label: Proposed validation scope}
24
+ validations: {required: true}
@@ -0,0 +1,17 @@
1
+ name: Feature request
2
+ description: Propose one evidence-backed research workflow.
3
+ title: "[Feature]: "
4
+ labels: [enhancement]
5
+ body:
6
+ - type: textarea
7
+ id: workflow
8
+ attributes: {label: Researcher workflow and decision supported}
9
+ validations: {required: true}
10
+ - type: textarea
11
+ id: science
12
+ attributes: {label: Scientific definition, assumptions, and references}
13
+ validations: {required: true}
14
+ - type: textarea
15
+ id: exclusions
16
+ attributes: {label: Explicit non-goals and validity limits}
17
+ validations: {required: true}
@@ -0,0 +1,36 @@
1
+ name: macOS/GUI issue
2
+ description: Report installation, Tk/backend, window lifecycle, or export failures.
3
+ title: "[macOS GUI]: "
4
+ labels: [macos, gui]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: Remove secrets and confidential paths/data before posting the full traceback.
9
+ - type: input
10
+ id: macos
11
+ attributes: {label: macOS version}
12
+ validations: {required: true}
13
+ - type: dropdown
14
+ id: architecture
15
+ attributes: {label: Architecture, options: [Apple Silicon, Intel]}
16
+ validations: {required: true}
17
+ - type: input
18
+ id: python
19
+ attributes: {label: Python version}
20
+ validations: {required: true}
21
+ - type: input
22
+ id: package
23
+ attributes: {label: FTProductLab version}
24
+ validations: {required: true}
25
+ - type: input
26
+ id: framework
27
+ attributes: {label: Tk/Tcl version, description: Run `python -c "import tkinter; print(tkinter.TkVersion)"`.}
28
+ validations: {required: true}
29
+ - type: input
30
+ id: install
31
+ attributes: {label: Installation command or method}
32
+ validations: {required: true}
33
+ - type: textarea
34
+ id: traceback
35
+ attributes: {label: Full sanitized traceback}
36
+ validations: {required: true}
@@ -0,0 +1,20 @@
1
+ name: Scientific result question
2
+ description: Ask about an equation, basis, fit convention, or numerical result.
3
+ title: "[Scientific result]: "
4
+ labels: [scientific-result]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: Do not post confidential or unpublished datasets. Reduce the case to synthetic or public data.
9
+ - type: textarea
10
+ id: definition
11
+ attributes: {label: Equation or definition, description: State input basis, fit range, and weighting.}
12
+ validations: {required: true}
13
+ - type: textarea
14
+ id: expected
15
+ attributes: {label: Independent calculation or reference, description: Provide DOI and exact convention where possible.}
16
+ validations: {required: true}
17
+ - type: input
18
+ id: version
19
+ attributes: {label: FTProductLab version}
20
+ validations: {required: true}
@@ -0,0 +1,3 @@
1
+ self-hosted-runner:
2
+ labels:
3
+ - dgx-spark
@@ -0,0 +1,10 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: pip
4
+ directory: "/"
5
+ schedule:
6
+ interval: monthly
7
+ - package-ecosystem: github-actions
8
+ directory: "/"
9
+ schedule:
10
+ interval: monthly
@@ -0,0 +1,98 @@
1
+ name: DGX CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ concurrency:
14
+ group: ftproductlab-dgx-${{ github.event.pull_request.number || github.ref }}
15
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
16
+
17
+ jobs:
18
+ required:
19
+ name: DGX / required
20
+ # Persistent research hardware never executes an external fork's code.
21
+ if: >-
22
+ github.event_name != 'pull_request' ||
23
+ (github.actor == github.repository_owner &&
24
+ github.event.pull_request.head.repo.full_name == github.repository)
25
+ runs-on: [self-hosted, Linux, ARM64, dgx-spark]
26
+ timeout-minutes: 45
27
+ env:
28
+ PIP_NO_CACHE_DIR: "1"
29
+ MPLBACKEND: Agg
30
+ steps:
31
+ - name: Check out source
32
+ uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
33
+ with:
34
+ clean: true
35
+ persist-credentials: false
36
+ - name: Set up Python
37
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
38
+ with:
39
+ python-version: "3.14"
40
+ - name: Configure established Tk and Xvfb runtime
41
+ env:
42
+ FTPRODUCTLAB_GUI_RUNTIME: /opt/catalysttwin-actions/shared-gui-runtime
43
+ run: |
44
+ set -eu
45
+ runtime="$FTPRODUCTLAB_GUI_RUNTIME"
46
+ bin_dir="$runtime/usr/bin"
47
+ lib_dir="$runtime/usr/lib/aarch64-linux-gnu"
48
+ tk_dir="$runtime/usr/share/tcltk/tk8.6"
49
+ test -d "$bin_dir"
50
+ test -d "$lib_dir"
51
+ test -d "$tk_dir"
52
+ printf '%s\n' "$bin_dir" >> "$GITHUB_PATH"
53
+ {
54
+ printf 'LD_LIBRARY_PATH=%s\n' "$lib_dir${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
55
+ printf 'TK_LIBRARY=%s\n' "$tk_dir"
56
+ } >> "$GITHUB_ENV"
57
+ export PATH="$bin_dir:$PATH"
58
+ export LD_LIBRARY_PATH="$lib_dir${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
59
+ export TK_LIBRARY="$tk_dir"
60
+ command -v Xvfb
61
+ command -v xvfb-run
62
+ python -c 'import tkinter; print(tkinter.TkVersion)'
63
+ - name: Create isolated environment
64
+ run: python -m venv .ci-venv
65
+ - name: Install project
66
+ run: |
67
+ .ci-venv/bin/python -m pip install --upgrade pip
68
+ .ci-venv/bin/python -m pip install -e ".[dev]"
69
+ - name: Format check
70
+ run: .ci-venv/bin/python -m ruff format --check .
71
+ - name: Lint
72
+ run: .ci-venv/bin/python -m ruff check .
73
+ - name: Strict type check
74
+ run: .ci-venv/bin/python -m mypy
75
+ - name: Scientific and integration tests
76
+ run: .ci-venv/bin/python -m pytest tests/unit tests/integration
77
+ - name: GUI workflow under Xvfb
78
+ run: xvfb-run -a .ci-venv/bin/python -m pytest tests/gui
79
+ - name: CLI and example smoke
80
+ run: |
81
+ .ci-venv/bin/ftproductlab validate
82
+ .ci-venv/bin/python scripts/run_example.py --output "$RUNNER_TEMP/ftproductlab-example"
83
+ - name: Build and metadata check
84
+ run: |
85
+ .ci-venv/bin/python -m build
86
+ .ci-venv/bin/python -m twine check dist/*
87
+ - name: Clean-wheel install and GUI-free CLI
88
+ run: |
89
+ python -m venv "$RUNNER_TEMP/ftproductlab-wheel"
90
+ "$RUNNER_TEMP/ftproductlab-wheel/bin/python" -m pip install --no-cache-dir dist/*.whl
91
+ "$RUNNER_TEMP/ftproductlab-wheel/bin/python" -m pip check
92
+ "$RUNNER_TEMP/ftproductlab-wheel/bin/ftproductlab" validate
93
+ "$RUNNER_TEMP/ftproductlab-wheel/bin/python" -c "import ftproductlab,sys; assert 'tkinter' not in sys.modules; assert 'matplotlib' not in sys.modules"
94
+ - name: Dependency audit
95
+ run: .ci-venv/bin/python -m pip_audit
96
+ - name: Remove isolated environment
97
+ if: always()
98
+ run: rm -rf .ci-venv
@@ -0,0 +1,74 @@
1
+ name: macOS GUI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ concurrency:
14
+ group: ftproductlab-macos-${{ github.event.pull_request.number || github.ref }}
15
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
16
+
17
+ jobs:
18
+ gui:
19
+ name: macOS 15 / ${{ matrix.architecture }} / Python ${{ matrix.python }}
20
+ # The hosted runner has no repository secrets; still reject external fork execution.
21
+ if: >-
22
+ github.event_name != 'pull_request' ||
23
+ (github.actor == github.repository_owner &&
24
+ github.event.pull_request.head.repo.full_name == github.repository)
25
+ strategy:
26
+ fail-fast: false
27
+ matrix:
28
+ include:
29
+ - runner: macos-15
30
+ architecture: arm64
31
+ python: "3.10"
32
+ - runner: macos-15
33
+ architecture: arm64
34
+ python: "3.14"
35
+ - runner: macos-15-intel
36
+ architecture: x86_64
37
+ # setup-python 3.10 on this image links Tk 8.5 headers to the
38
+ # image's Tk 8.6 runtime. Python 3.13 is the verified Intel pair.
39
+ python: "3.13"
40
+ runs-on: ${{ matrix.runner }}
41
+ timeout-minutes: 30
42
+ env:
43
+ MPLBACKEND: Agg
44
+ steps:
45
+ - name: Check out source
46
+ uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
47
+ with:
48
+ persist-credentials: false
49
+ - name: Set up Python
50
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
51
+ with:
52
+ python-version: ${{ matrix.python }}
53
+ - name: Record platform and Tk
54
+ run: |
55
+ python -c "import platform; print(platform.platform(), platform.machine())"
56
+ python -c "import tkinter; print('Tk', tkinter.TkVersion)"
57
+ - name: Install source with GUI extras
58
+ run: python -m pip install -e ".[gui,dev]"
59
+ - name: Core, CLI, and import-isolation tests
60
+ run: |
61
+ python -m pytest tests/unit tests/integration/test_cli.py tests/integration/test_import_isolation.py
62
+ ftproductlab validate
63
+ - name: Real window workflow, export, close, and exit
64
+ run: python -m pytest tests/gui tests/macos
65
+ - name: Build and clean wheel
66
+ run: |
67
+ python -m build
68
+ python -m venv "$RUNNER_TEMP/wheel-env"
69
+ "$RUNNER_TEMP/wheel-env/bin/python" -m pip install "ftproductlab[gui] @ file://$PWD/$(ls dist/*.whl)"
70
+ "$RUNNER_TEMP/wheel-env/bin/python" -m pip check
71
+ "$RUNNER_TEMP/wheel-env/bin/ftproductlab" validate
72
+ - name: Clean-wheel GUI lifecycle
73
+ run: |
74
+ "$RUNNER_TEMP/wheel-env/bin/python" -c "import tkinter as tk; from ftproductlab.gui.app import MainWindow; root=tk.Tk(); window=MainWindow(root); root.update(); assert window.winfo_exists(); root.destroy()"
@@ -0,0 +1,53 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - name: Check out source
15
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
16
+ with:
17
+ persist-credentials: false
18
+ - name: Set up Python
19
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
20
+ with:
21
+ python-version: "3.14"
22
+ - name: Build distributions
23
+ env:
24
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
25
+ run: |
26
+ python -m pip install build==1.5.0 twine==6.2.0
27
+ version="$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')"
28
+ test "$RELEASE_TAG" = "v$version"
29
+ python -m build
30
+ python -m twine check dist/*
31
+ - name: Upload distributions
32
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
33
+ with:
34
+ name: pypi-distributions
35
+ path: dist/
36
+ if-no-files-found: error
37
+
38
+ publish:
39
+ needs: build
40
+ runs-on: ubuntu-latest
41
+ environment:
42
+ name: pypi
43
+ url: https://pypi.org/p/ftproductlab
44
+ permissions:
45
+ id-token: write
46
+ steps:
47
+ - name: Download distributions
48
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
49
+ with:
50
+ name: pypi-distributions
51
+ path: dist/
52
+ - name: Publish with Trusted Publishing
53
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
@@ -0,0 +1,11 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .coverage
5
+ .mypy_cache/
6
+ .pytest_cache/
7
+ .ruff_cache/
8
+ .venv/
9
+ build/
10
+ dist/
11
+ ftproductlab-output/
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 - Unreleased
4
+
5
+ - Initial species-preserving carbon-number aggregation.
6
+ - Explicit molar, mass, and carbon input bases.
7
+ - User-ranged single-alpha ASF fitting with uniform or amount weighting.
8
+ - C1/C2 and per-carbon residual diagnostics, user-defined cuts, and O/P states.
9
+ - Shared Python API, CLI, Tkinter GUI, deterministic tables, and PNG/SVG/PDF figures.
@@ -0,0 +1,26 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use FTProductLab, please cite the software and the scientific sources for the ASF convention."
3
+ title: "FTProductLab"
4
+ type: software
5
+ version: 0.1.0
6
+ date-released: 2026-08-23
7
+ authors:
8
+ - family-names: "Kim"
9
+ given-names: "Peter"
10
+ repository-code: "https://github.com/hdkim99/FTProductLab"
11
+ url: "https://github.com/hdkim99/FTProductLab"
12
+ license: BSD-3-Clause
13
+ keywords:
14
+ - Fischer-Tropsch
15
+ - Anderson-Schulz-Flory
16
+ - catalysis
17
+ - product distribution
18
+ references:
19
+ - type: article
20
+ title: "Molecular Size Distribution in Linear Condensation Polymers"
21
+ authors:
22
+ - family-names: "Flory"
23
+ given-names: "Paul J."
24
+ journal: "Journal of the American Chemical Society"
25
+ year: 1936
26
+ doi: "10.1021/ja01301a016"
@@ -0,0 +1,26 @@
1
+ # Contributing
2
+
3
+ Use a focused issue or pull request and do not upload unpublished, confidential, export-
4
+ controlled, or personally identifiable research data to a public issue.
5
+
6
+ Scientific-core changes must state the equation or definition, units/basis, assumptions,
7
+ validity range, authoritative reference, independent numerical validation, and regression
8
+ test. A higher R² alone does not justify a new model. Do not add coefficients or thresholds
9
+ without a traceable source or derivation.
10
+
11
+ GUI changes must additionally record supported platforms, dependency changes, backend
12
+ impact, macOS smoke results, and CLI/core import isolation. PyQt and PySide must never be
13
+ mixed; introducing Qt requires a separate architecture decision and the compatibility tests
14
+ listed in the issue template. Tk code must create one root and must not update widgets from a
15
+ background thread.
16
+
17
+ Run before submitting:
18
+
19
+ ```bash
20
+ python -m ruff format --check .
21
+ python -m ruff check .
22
+ python -m mypy
23
+ python -m pytest
24
+ python -m build
25
+ python -m twine check dist/*
26
+ ```
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, Peter Kim
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,198 @@
1
+ Metadata-Version: 2.4
2
+ Name: ftproductlab
3
+ Version: 0.1.0
4
+ Summary: Reproducible Fischer-Tropsch product-distribution and ASF analysis
5
+ Project-URL: Homepage, https://github.com/hdkim99/FTProductLab
6
+ Project-URL: Documentation, https://github.com/hdkim99/FTProductLab#readme
7
+ Project-URL: Issues, https://github.com/hdkim99/FTProductLab/issues
8
+ Project-URL: Repository, https://github.com/hdkim99/FTProductLab
9
+ Author: Peter Kim
10
+ License-Expression: BSD-3-Clause
11
+ License-File: LICENSE
12
+ Keywords: anderson-schulz-flory,catalysis,fischer-tropsch,product-distribution
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: BSD License
17
+ Classifier: Operating System :: MacOS
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Programming Language :: Python :: 3 :: Only
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
+ Requires-Python: <3.15,>=3.10
27
+ Provides-Extra: dev
28
+ Requires-Dist: build==1.5.0; extra == 'dev'
29
+ Requires-Dist: matplotlib<4,>=3.8; extra == 'dev'
30
+ Requires-Dist: mypy<2,>=1.15; extra == 'dev'
31
+ Requires-Dist: pip-audit<3,>=2.9; extra == 'dev'
32
+ Requires-Dist: pytest<10,>=8.3; extra == 'dev'
33
+ Requires-Dist: ruff<0.18,>=0.11; extra == 'dev'
34
+ Requires-Dist: twine<7,>=6.1; extra == 'dev'
35
+ Provides-Extra: gui
36
+ Requires-Dist: matplotlib<4,>=3.8; extra == 'gui'
37
+ Provides-Extra: plot
38
+ Requires-Dist: matplotlib<4,>=3.8; extra == 'plot'
39
+ Description-Content-Type: text/markdown
40
+
41
+ # FTProductLab
42
+
43
+ [![DGX CI](https://github.com/hdkim99/FTProductLab/actions/workflows/ci.yml/badge.svg)](https://github.com/hdkim99/FTProductLab/actions/workflows/ci.yml)
44
+ [![macOS GUI](https://github.com/hdkim99/FTProductLab/actions/workflows/macos.yml/badge.svg)](https://github.com/hdkim99/FTProductLab/actions/workflows/macos.yml)
45
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-3776ab)](https://www.python.org/)
46
+
47
+ Reproducible Fischer–Tropsch carbon-number distribution, single-alpha ASF, product-cut,
48
+ deviation, and olefin/paraffin analysis.
49
+
50
+ ![Observed FT product distribution, fitted ASF line, and residuals](assets/social-preview.png)
51
+
52
+ ## Why
53
+
54
+ FTProductLab keeps carbon-number definitions, input basis, fit range, regression weighting,
55
+ and truncation conventions visible. It does not turn a high R² into a claim that an ideal ASF
56
+ mechanism is valid. Species remain category-resolved while totals are aggregated by carbon
57
+ number for analysis.
58
+
59
+ ## Install
60
+
61
+ ```bash
62
+ python -m pip install ftproductlab
63
+ ```
64
+
65
+ The base package contains the scientific core and CLI and has no GUI, Qt, or plotting
66
+ dependency. For figures and the Tk interface:
67
+
68
+ ```bash
69
+ python -m pip install "ftproductlab[gui]"
70
+ ```
71
+
72
+ Tk itself is supplied by Python, not PyPI. Homebrew Python users may need the matching
73
+ formula, for example `brew install python-tk@3.14`.
74
+
75
+ ## 30-second example
76
+
77
+ ```bash
78
+ ftproductlab analyze examples/sample_distribution.csv \
79
+ --basis molar --fit-min 5 --fit-max 20 \
80
+ --cut C1:1:1 --cut C2-C4:2:4 --cut C5+:5 \
81
+ --output ftproductlab-output --plots
82
+ ```
83
+
84
+ The command writes a machine-readable `analysis.json`, point/cut/O-P CSV tables, and
85
+ PNG/SVG/PDF figures. Run the built-in hand-checkable regression with:
86
+
87
+ ```bash
88
+ ftproductlab validate
89
+ ```
90
+
91
+ Python uses the same core:
92
+
93
+ ```python
94
+ from ftproductlab import FitConfig, InputBasis, ProductRecord, analyze_distribution
95
+
96
+ records = [ProductRecord(n, 0.2 * 0.8 ** (n - 1)) for n in range(1, 21)]
97
+ result = analyze_distribution(records, InputBasis.MOLAR, FitConfig(3, 20))
98
+ assert abs(result.fit.alpha - 0.8) < 1e-12
99
+ ```
100
+
101
+ ## GUI
102
+
103
+ ```bash
104
+ python -m ftproductlab.gui
105
+ ```
106
+
107
+ The GUI is deliberately Tkinter/ttk rather than Qt. It creates one `Tk()` root, calls the
108
+ same application service as the CLI, exports the same tables, and closes the event loop
109
+ normally. Plot exports explicitly select Matplotlib `Agg`; the core and CLI do not import
110
+ Tkinter, Matplotlib, PyQt, or PySide.
111
+
112
+ ## CSV schema and basis
113
+
114
+ Required columns are `carbon_number` and `amount`. Optional columns are `category`,
115
+ `species`, `molecular_weight_g_mol`, and `below_detection`.
116
+
117
+ - `molar`: amount is proportional to moles of product molecules.
118
+ - `carbon`: amount is proportional to carbon moles; it is divided by carbon number before
119
+ fitting.
120
+ - `mass`: each record must provide molecular weight. FTProductLab never approximates all
121
+ paraffins, olefins, and oxygenates as `CH2`.
122
+
123
+ Amounts may use any consistent scale. Zero measurements remain in output but cannot enter a
124
+ logarithmic fit. Below-detection records remain visible and are excluded from fitting by
125
+ default. Repeat `--cut LABEL:MIN[:MAX]` to define CLI cuts; the GUI exposes the same cut
126
+ specification, and the Python API accepts `CutDefinition` objects directly.
127
+
128
+ ## Scientific basis
129
+
130
+ For molecular amount at carbon number `n`, the ideal single-alpha model is
131
+
132
+ ```text
133
+ x_n = (1 - alpha) alpha^(n - 1)
134
+ ```
135
+
136
+ and the corresponding carbon fraction is
137
+
138
+ ```text
139
+ w_n = n (1 - alpha)^2 alpha^(n - 1).
140
+ ```
141
+
142
+ FTProductLab estimates the slope of `ln(molar-equivalent amount)` against `n` over the
143
+ user-specified range; `alpha = exp(slope)`. The intercept is free because experimental
144
+ datasets may be scaled or truncated. Uniform and amount-weighted regressions are explicit
145
+ choices. No fit range is selected automatically, and C1/C2 are not silently removed.
146
+
147
+ The primary/statistical foundation is Flory's chain-length distribution
148
+ ([JACS 1936, DOI 10.1021/ja01301a016](https://doi.org/10.1021/ja01301a016)); its early FT
149
+ application includes Friedel and Anderson
150
+ ([JACS 1950, DOI 10.1021/ja01159a039](https://doi.org/10.1021/ja01159a039)). A modern
151
+ discussion of ideal ASF and structured deviations is
152
+ [Vervloet et al., Catalysis Science & Technology 2013](https://doi.org/10.1039/C3CY00080J).
153
+ See [the scientific-basis document](docs/scientific-basis.md) for conventions and equations.
154
+
155
+ ## Validation
156
+
157
+ - Exact synthetic geometric distributions recover alpha to floating-point precision.
158
+ - Infinite molecular/carbon normalization and analytical carbon-cut sums have independent
159
+ direct-summation tests.
160
+ - Species aggregation, mass-to-mole conversion, C1/C2 deviations, product-cut closure,
161
+ O/P zero denominators, detection flags, CSV, CLI, GUI export, plotting, and import
162
+ isolation are tested.
163
+ - The open-access Partington et al. Co/TiO2 study reports alpha=0.92 for C10–C40 and provides
164
+ a useful external target, but repository-level numerical reproduction remains pending
165
+ because a redistributable tabular C10–C40 fixture has not yet been extracted. Synthetic
166
+ fixtures are never labeled real data.
167
+
168
+ Details: [validation record](docs/validation.md).
169
+
170
+ ## Supported platforms
171
+
172
+ - Python 3.10–3.14 for the core and CLI
173
+ - Linux scientific core/CLI and Xvfb GUI checks on the project DGX runner
174
+ - macOS GUI workflow on GitHub-hosted macOS plus local Apple Silicon smoke testing
175
+ - Tk 8.6 or newer; no Qt binding is used or installed
176
+
177
+ The hosted GUI matrix covers Apple Silicon on Python 3.10 and 3.14 and Intel on Python
178
+ 3.13. The `setup-python` 3.10 build on the `macos-15-intel` image is not a supported GUI
179
+ combination because its Tk 8.5 build metadata conflicts with the image's Tk 8.6 runtime.
180
+ See [macOS notes](docs/macos.md).
181
+
182
+ ## Limitations
183
+
184
+ - Version 0.1 implements an ideal, single-alpha descriptive fit only. Dual-alpha and
185
+ modified ASF models are intentionally unsupported.
186
+ - Missing products, detector response, phase collection, recycle, and analytical recovery
187
+ can structure residuals; the software does not correct them without supplied data.
188
+ - Observed product-cut fractions close over the supplied dataset. They are not an estimate
189
+ of an unmeasured heavy tail.
190
+ - Category names such as “gasoline”, “diesel”, and “wax” are not assigned automatically;
191
+ carbon-number cut definitions are shown explicitly.
192
+ - This is product-distribution decision support, not a reactor or kinetic mechanism model.
193
+
194
+ ## Development and citation
195
+
196
+ See [CONTRIBUTING.md](CONTRIBUTING.md) before changing an equation or GUI dependency and
197
+ use [CITATION.cff](CITATION.cff) when citing the software. The name and competitive audit is
198
+ recorded in [docs/naming-audit.md](docs/naming-audit.md).