Skip to content

Commit b106fa0

Browse files
committed
Initial public release v1.1.0
Coupled thermohygro-electrochemical CUI simulator with DFOS-informed inverse problem. Three-PDE physics-first scaffold (Fourier + Philip-de Vries + Butler-Volmer) solved by Strang operator splitting, with Monte Carlo / GBR surrogate / API 579-1 Level 2 FAD / SHA-256 audit chain. 154 tests, 5 analytical benchmarks, full GitHub Actions CI/CD.
0 parents  commit b106fa0

45 files changed

Lines changed: 4663 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: Bug report
2+
description: Report a defect — wrong physics, failing test, broken pipeline.
3+
title: "[bug] "
4+
labels: ["bug", "needs-triage"]
5+
body:
6+
- type: markdown
7+
attributes:
8+
value: |
9+
Thanks for taking the time to file a bug. Physics correctness and
10+
reproducibility matter — please be specific.
11+
12+
- type: textarea
13+
id: summary
14+
attributes:
15+
label: Summary
16+
description: One or two sentences. What did you expect, what happened?
17+
placeholder: "run_all.py [6/9] reports recovery error of 80% instead of <1%"
18+
validations:
19+
required: true
20+
21+
- type: textarea
22+
id: reproduce
23+
attributes:
24+
label: Reproduction
25+
description: Exact commands to trigger the bug. Paste full output if relevant.
26+
render: bash
27+
validations:
28+
required: true
29+
30+
- type: textarea
31+
id: expected
32+
attributes:
33+
label: Expected behaviour
34+
description: What should have happened? Cite README equation or test if applicable.
35+
validations:
36+
required: true
37+
38+
- type: input
39+
id: python
40+
attributes:
41+
label: Python version
42+
placeholder: "3.12.3"
43+
validations:
44+
required: true
45+
46+
- type: input
47+
id: os
48+
attributes:
49+
label: Operating system
50+
placeholder: "Ubuntu 24.04 / macOS 14.5 / Windows 11"
51+
validations:
52+
required: true
53+
54+
- type: textarea
55+
id: env
56+
attributes:
57+
label: Package versions
58+
description: Output of `pip freeze | grep -E "numpy|scipy|matplotlib|scikit-learn"`.
59+
render: text
60+
61+
- type: checkboxes
62+
id: checks
63+
attributes:
64+
label: Pre-flight
65+
options:
66+
- label: I ran `pytest tests/` and the failure is reproducible.
67+
- label: I checked that this is not already reported.

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
blank_issues_enabled: false
2+
contact_links:
3+
- name: Security vulnerability (private)
4+
url: https://github.com/felipearocha/integrity-code-series-week9-cui/security/advisories/new
5+
about: Report a vulnerability that could mislead an integrity decision. Use private advisory rather than a public issue.
6+
- name: Operational fitness-for-service questions
7+
url: https://www.api.org/products-and-services/standards
8+
about: This software is for research and education only. For real fitness-for-service decisions, consult API 579-1 / API RP 583 and a qualified engineer.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Feature request
2+
description: Propose a new physics, numerics, or API capability.
3+
title: "[feat] "
4+
labels: ["enhancement", "needs-discussion"]
5+
body:
6+
- type: markdown
7+
attributes:
8+
value: |
9+
Explain the **industrial use case first**, then the proposed API.
10+
Features that don't trace back to a fitness-for-service or inspection
11+
decision are unlikely to be merged.
12+
13+
- type: textarea
14+
id: use_case
15+
attributes:
16+
label: Use case
17+
description: What integrity decision does this enable that today is impossible or ad-hoc?
18+
validations:
19+
required: true
20+
21+
- type: textarea
22+
id: proposal
23+
attributes:
24+
label: Proposed change
25+
description: API surface, equations, parameters. Be concrete.
26+
validations:
27+
required: true
28+
29+
- type: textarea
30+
id: alternatives
31+
attributes:
32+
label: Alternatives considered
33+
description: Existing workarounds, related features, why they fall short.
34+
35+
- type: textarea
36+
id: refs
37+
attributes:
38+
label: References
39+
description: API codes, papers, regulations, prior incidents.
40+
41+
- type: checkboxes
42+
id: scope
43+
attributes:
44+
label: Scope
45+
options:
46+
- label: This is consistent with the LICENSE (research/educational use).
47+
- label: I am willing to draft the PR or co-author it.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Physics question
2+
description: Question about a governing equation, BC, parameter, or numerical method.
3+
title: "[physics] "
4+
labels: ["question", "physics"]
5+
body:
6+
- type: markdown
7+
attributes:
8+
value: |
9+
Cite the equation number from the README, the API code clause if
10+
relevant, and the parameter values that triggered the question.
11+
12+
- type: input
13+
id: equation
14+
attributes:
15+
label: Equation reference
16+
placeholder: "Eq. (2c) — partial-holiday Dirichlet"
17+
validations:
18+
required: true
19+
20+
- type: textarea
21+
id: question
22+
attributes:
23+
label: The question
24+
description: What is unclear or appears incorrect? What would you expect instead?
25+
validations:
26+
required: true
27+
28+
- type: textarea
29+
id: context
30+
attributes:
31+
label: Context (parameter values, mesh, timesteps)
32+
33+
- type: textarea
34+
id: refs
35+
attributes:
36+
label: Supporting references
37+
description: Papers, code clauses, textbooks. Page/equation numbers please.

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
## Summary
2+
3+
<!-- 1-3 sentences. What problem does this solve? -->
4+
5+
## Changes
6+
7+
- Physics / equations:
8+
- Numerics / solvers:
9+
- API surface:
10+
- Tests / benchmarks:
11+
12+
## Validation
13+
14+
- [ ] `pytest tests/ -v` — all 151+ tests pass locally
15+
- [ ] `python validation/benchmarks.py` — all 5 benchmarks pass
16+
- [ ] `python run_all.py` — pipeline completes; figures regenerate cleanly
17+
- [ ] `ruff check .` and `ruff format --check .` clean
18+
- [ ] `pre-commit run --all-files` clean
19+
20+
## Baseline check
21+
22+
- [ ] `wl(10yr) = 0.1360 mm` for the deterministic baseline (unchanged)
23+
- [ ] If changed, the new value is justified and documented in CHANGELOG
24+
25+
## Documentation
26+
27+
- [ ] Updated README equations / table if the change is physics-visible
28+
- [ ] Updated `[ASSUMED]` parameter table if a new constant was introduced
29+
- [ ] Added/updated CHANGELOG entry under the Unreleased section
30+
- [ ] Updated docstrings on touched public functions
31+
32+
## Linked issues
33+
34+
<!-- Closes #123 / Refs #456 -->
35+
36+
## Notes for reviewers
37+
38+
<!-- Anything non-obvious about the approach, alternatives considered,
39+
limits of the implementation, follow-up work. -->

.github/dependabot.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "pip"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
day: "monday"
8+
time: "06:00"
9+
timezone: "Etc/UTC"
10+
open-pull-requests-limit: 5
11+
labels: ["dependencies", "python"]
12+
commit-message:
13+
prefix: "deps"
14+
include: "scope"
15+
groups:
16+
scientific-python:
17+
patterns:
18+
- "numpy"
19+
- "scipy"
20+
- "matplotlib"
21+
- "scikit-learn"
22+
- "Pillow"
23+
dev-tooling:
24+
patterns:
25+
- "pytest*"
26+
- "ruff"
27+
- "pre-commit"
28+
- "build"
29+
30+
- package-ecosystem: "github-actions"
31+
directory: "/"
32+
schedule:
33+
interval: "weekly"
34+
day: "monday"
35+
labels: ["dependencies", "ci"]
36+
commit-message:
37+
prefix: "ci"

.github/workflows/ci.yml

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
name: 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: ${{ github.workflow }}-${{ github.ref }}
15+
cancel-in-progress: true
16+
17+
jobs:
18+
lint:
19+
name: Lint (ruff + pre-commit)
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@v4
23+
- uses: actions/setup-python@v5
24+
with:
25+
python-version: "3.12"
26+
cache: "pip"
27+
- name: Install dev tooling
28+
run: |
29+
python -m pip install --upgrade pip
30+
pip install -e ".[dev]"
31+
- name: Ruff lint
32+
run: ruff check .
33+
- name: Ruff format check
34+
run: ruff format --check .
35+
- name: Pre-commit hooks
36+
run: pre-commit run --all-files --show-diff-on-failure
37+
38+
test:
39+
name: Tests (py${{ matrix.python }} on ${{ matrix.os }})
40+
runs-on: ${{ matrix.os }}
41+
needs: lint
42+
strategy:
43+
fail-fast: false
44+
matrix:
45+
os: [ubuntu-latest, macos-latest, windows-latest]
46+
python: ["3.11", "3.12", "3.13"]
47+
steps:
48+
- uses: actions/checkout@v4
49+
- uses: actions/setup-python@v5
50+
with:
51+
python-version: ${{ matrix.python }}
52+
cache: "pip"
53+
- name: Install package
54+
run: |
55+
python -m pip install --upgrade pip
56+
pip install -e ".[dev]"
57+
- name: Run pytest with coverage
58+
run: pytest --cov=src --cov-report=xml --cov-report=term -q
59+
- name: Upload coverage to Codecov
60+
if: matrix.os == 'ubuntu-latest' && matrix.python == '3.12'
61+
uses: codecov/codecov-action@v4
62+
with:
63+
files: coverage.xml
64+
fail_ci_if_error: false
65+
env:
66+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
67+
68+
benchmarks:
69+
name: Analytical benchmarks
70+
runs-on: ubuntu-latest
71+
needs: lint
72+
steps:
73+
- uses: actions/checkout@v4
74+
- uses: actions/setup-python@v5
75+
with:
76+
python-version: "3.12"
77+
cache: "pip"
78+
- name: Install package
79+
run: |
80+
python -m pip install --upgrade pip
81+
pip install -e ".[dev]"
82+
- name: Run benchmarks
83+
run: python validation/benchmarks.py
84+
85+
pipeline-smoke:
86+
name: Full pipeline smoke test
87+
runs-on: ubuntu-latest
88+
needs: [test, benchmarks]
89+
steps:
90+
- uses: actions/checkout@v4
91+
- uses: actions/setup-python@v5
92+
with:
93+
python-version: "3.12"
94+
cache: "pip"
95+
- name: Install package
96+
run: |
97+
python -m pip install --upgrade pip
98+
pip install -e ".[dev]"
99+
- name: Run pipeline (run_all.py)
100+
run: python run_all.py
101+
- name: Verify assets generated
102+
run: |
103+
test -f assets/figures/panel_ab_fields.png
104+
test -f assets/figures/panel_c_mc_distribution.png
105+
test -f assets/figures/panel_d_sensitivity.png
106+
test -f assets/figures/panel_e_surrogate.png
107+
test -f assets/figures/panel_f_iso_risk.png
108+
test -f assets/figures/panel_g_fad.png
109+
test -f assets/figures/panel_h_inverse.png
110+
test -f assets/animations/cui_moisture_front.gif
111+
test -f assets/audit_chain.json
112+
- name: Verify audit chain integrity
113+
run: |
114+
python -c "
115+
import json
116+
with open('assets/audit_chain.json') as f:
117+
entries = json.load(f)
118+
assert len(entries) >= 2, f'Expected >=2 entries, got {len(entries)}'
119+
assert entries[0]['prev_hash'] == '0' * 64
120+
assert all(e['entry_hash'] for e in entries)
121+
print(f'Audit chain OK: {len(entries)} entries')
122+
"
123+
- name: Upload pipeline artifacts
124+
uses: actions/upload-artifact@v4
125+
with:
126+
name: pipeline-outputs-${{ github.sha }}
127+
path: |
128+
assets/figures/*.png
129+
assets/animations/*.gif
130+
assets/audit_chain.json
131+
retention-days: 30
132+
133+
security:
134+
name: Security scan (pip-audit)
135+
runs-on: ubuntu-latest
136+
needs: lint
137+
steps:
138+
- uses: actions/checkout@v4
139+
- uses: actions/setup-python@v5
140+
with:
141+
python-version: "3.12"
142+
cache: "pip"
143+
- name: Install package + pip-audit
144+
run: |
145+
python -m pip install --upgrade pip
146+
pip install -e .
147+
pip install pip-audit
148+
- name: Audit dependencies
149+
run: pip-audit --strict
150+
continue-on-error: true
151+
152+
ci-pass:
153+
name: All checks passed
154+
runs-on: ubuntu-latest
155+
needs: [lint, test, benchmarks, pipeline-smoke, security]
156+
steps:
157+
- run: echo "All CI jobs succeeded."

0 commit comments

Comments
 (0)