Skip to content

Commit 38b6af5

Browse files
Merge pull request #234 from alchem0x2A/master
2 parents 54fe2a8 + d013645 commit 38b6af5

11 files changed

+342
-84
lines changed

.conda/README.md

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
# Build conda recipe for sparc
2+
3+
**Note** the official conda-forge package for SPARC can be found at
4+
[`sparc-x`](https://github.com/conda-forge/sparc-x-feedstock). This
5+
recipe is maintained for CI purpose only.
6+
27
1. Install `conda-build` and (optionally) `boa`
38
```bash
49
conda install -c conda-forge "conda-build>=3.20" colorama pip ruamel ruamel.yaml rich mamba jsonschema
@@ -22,16 +27,9 @@ anaconda login
2227
anaconda upload $CONDA_PREFIX/conda-bld/linux-64/sparc-<YYYY>.<MM>.<DD>-<i>.bz2
2328
```
2429

25-
If the SPARC package is finally in production, we need to merge it to `conda-forge` channel (perhaps using a different name `sparc-dft`?)
26-
2730

2831
4. Using the package
2932
```bash
3033
conda install -c <your-channel> sparc
3134
```
3235
This will automatically install `sparc` with `openmpi` + `scalapack` + `openblas` support. No compilation requires afterwards.
33-
34-
5. TODOs
35-
- [ ] Configure the mpi-aware fftw package
36-
- [ ] Include mkl-variant?
37-
- [ ] Complete conda-forge merge once in upstream main

.github/workflows/build-test.yml

+30-2
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,41 @@ on:
1010
workflow_dispatch:
1111

1212
jobs:
13+
# Check if initialization.c is up-to-date with Changelog
14+
package-date-check:
15+
runs-on: ubuntu-latest
16+
defaults:
17+
run:
18+
shell: bash -l {0}
19+
steps:
20+
- uses: actions/checkout@v4
21+
- uses: conda-incubator/setup-miniconda@v3
22+
with:
23+
python-version: "3.11"
24+
activate-environment: sparc-test
25+
conda-build-version: "24.9.0"
26+
miniforge-version: latest # Fix according to https://github.com/conda-incubator/setup-miniconda?tab=readme-ov-file#example-10-miniforge
27+
channels: conda-forge,defaults
28+
channel-priority: true
29+
- name: Install SPARC-X-API stable version for docparser
30+
run: |
31+
mamba install -c conda-forge pip setuptools
32+
pip install git+https://github.com/SPARC-X/[email protected]
33+
- name: Convert parameters.json
34+
run: |
35+
python -m sparc.docparser --include-subdirs doc/.LaTeX
36+
- name: Check package version and ChangeLog date
37+
run: |
38+
# Usage:
39+
# python test-outdated-package.py <parameters.json> <changelog>
40+
python .github/workflows/test-outdated-package.py \
41+
./parameters.json ChangeLog
1342
build-linux:
1443
runs-on: ubuntu-latest
1544
defaults:
1645
run:
1746
shell: bash -l {0}
18-
strategy:
19-
max-parallel: 5
47+
needs: package-date-check
2048

2149
steps:
2250
- uses: actions/checkout@v4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
"""Test script to check parameters coverage in examples
2+
"""
3+
import json
4+
import os
5+
from pathlib import Path
6+
from sparc.io import _read_inpt
7+
8+
def load_parameters_json(json_path):
9+
"""
10+
Load the parameters from the parameters.json file.
11+
"""
12+
with open(json_path, 'r') as f:
13+
parameters = json.load(f)
14+
if "parameters" not in parameters:
15+
raise KeyError("The 'parameters' field is missing in parameters.json")
16+
return parameters["parameters"]
17+
18+
def check_missing_parameters(test_dir, parameters_json_path):
19+
"""
20+
Check for missing parameters in the documentation.
21+
test_dir must be structured in <name>/standard/<name>.inpt
22+
"""
23+
test_dir = Path(test_dir)
24+
documented_parameters = load_parameters_json(parameters_json_path)
25+
26+
# Iterate through the .inpt files and check for missing parameters
27+
report = {}
28+
for match_file in test_dir.glob("*/standard/*.inpt"):
29+
test_name = match_file.stem
30+
try:
31+
inpt_data = _read_inpt(match_file)
32+
params_in_file = inpt_data["inpt"]["params"]
33+
except Exception:
34+
# Something could be buggy with SPARC-X-API?
35+
pass
36+
37+
# Check missing or typo parameters
38+
missing_params = [
39+
param for param in params_in_file
40+
if (param.upper() not in documented_parameters)
41+
# TODO: Obsolete BOUNDARY_CONDITION keyword
42+
and (param.upper() != "BOUNDARY_CONDITION")
43+
]
44+
if missing_params:
45+
report[test_name] = missing_params
46+
47+
# Generate report and return error if missing parameters are found
48+
if report:
49+
print("Missing / Incorrect Parameters Report:")
50+
print("-" * 60)
51+
for file_path, missing_params in report.items():
52+
print(f"Test name: {file_path}")
53+
print(f"Missing Parameters: {', '.join(missing_params)}")
54+
print("-" * 60)
55+
return False
56+
else:
57+
print("All parameters are documented correctly.")
58+
return True
59+
60+
61+
def main():
62+
import argparse
63+
parser = argparse.ArgumentParser(
64+
description="Check for missing / incorrect parameters in SPARC examples."
65+
)
66+
parser.add_argument(
67+
"test_directory",
68+
type=str,
69+
help="Path to the directory containing test .inpt files."
70+
)
71+
parser.add_argument(
72+
"parameters_json",
73+
type=str,
74+
help="Path to the parameters.json file."
75+
)
76+
77+
args = parser.parse_args()
78+
79+
# Run the check
80+
success = check_missing_parameters(args.test_directory,
81+
args.parameters_json)
82+
if not success:
83+
exit(1)
84+
else:
85+
exit(0)
86+
if __name__ == "__main__":
87+
main()
+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
"""Test script to check if SPARC package version is older than
2+
the latest Changelog entry
3+
4+
We generally do not check the other way around since sometimes a trivial bump of SPARC version may be necessary
5+
"""
6+
import re
7+
import json
8+
from datetime import datetime
9+
from pathlib import Path
10+
11+
12+
def load_parameters_json(json_path):
13+
"""
14+
Load the parameters from the parameters.json file.
15+
"""
16+
with open(json_path, 'r') as f:
17+
parameters = json.load(f)
18+
if "sparc_version" not in parameters:
19+
raise KeyError("The 'sparc_version' field is missing in parameters.json")
20+
return parameters["sparc_version"]
21+
22+
23+
def extract_latest_date_from_changelog(changelog_path):
24+
"""
25+
Extracts the latest date from the changelog file.
26+
"""
27+
date_patterns = [
28+
r"(?P<date>\b(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{1,2}, \d{4})",
29+
r"(?P<date>\b(?:January|February|March|April|May|June|July|August|September|October|November|December) \d{1,2}, \d{4})",
30+
]
31+
32+
latest_date = None
33+
changelog_path = Path(changelog_path)
34+
35+
with changelog_path.open("r") as f:
36+
content = f.read()
37+
38+
for pattern in date_patterns:
39+
matches = re.findall(pattern, content)
40+
for match in matches:
41+
try:
42+
# Convert matched date to datetime object
43+
parsed_date = datetime.strptime(match, "%b %d, %Y") if "," in match else datetime.strptime(match, "%B %d, %Y")
44+
if latest_date is None or parsed_date > latest_date:
45+
latest_date = parsed_date
46+
except ValueError:
47+
continue # Skip invalid date formats
48+
49+
if latest_date is None:
50+
raise ValueError("No valid date found in the changelog.")
51+
return latest_date
52+
53+
54+
def check_version_against_changelog(parameters_json_path, changelog_path):
55+
"""
56+
Check if the package version in parameters.json is older than the latest changelog date.
57+
"""
58+
# Load sparc_version from parameters.json
59+
sparc_version = load_parameters_json(parameters_json_path)
60+
version_date = datetime.strptime(sparc_version, "%Y.%m.%d")
61+
62+
# Extract the latest date from the changelog
63+
latest_changelog_date = extract_latest_date_from_changelog(changelog_path)
64+
65+
if version_date < latest_changelog_date:
66+
print("Version Check Report:")
67+
print("-" * 60)
68+
print(f"ERROR: SPARC version ({version_date.strftime('%Y.%m.%d')}) "
69+
f"is older than the latest changelog date ({latest_changelog_date.strftime('%Y.%m.%d')}).")
70+
print("Please update initialization.c!")
71+
print("-" * 60)
72+
return False
73+
else:
74+
print("Version Check Report:")
75+
print("-" * 60)
76+
print("SUCCESS:")
77+
print("-" * 60)
78+
return True
79+
80+
81+
def main():
82+
import argparse
83+
parser = argparse.ArgumentParser(
84+
description="Check if package version is up-to-date with the changelog."
85+
)
86+
parser.add_argument(
87+
"parameters_json",
88+
type=str,
89+
help="Path to the parameters.json file."
90+
)
91+
parser.add_argument(
92+
"changelog",
93+
type=str,
94+
help="Path to the changelog file."
95+
)
96+
97+
args = parser.parse_args()
98+
99+
# Run the version check
100+
success = check_version_against_changelog(args.parameters_json, args.changelog)
101+
if not success:
102+
exit(1)
103+
else:
104+
exit(0)
105+
106+
107+
if __name__ == "__main__":
108+
main()

.github/workflows/update-doc-pdf.yml

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
name: Check and render LaTeX doc into pdf
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
paths:
8+
- doc/**
9+
- .github/workflows/update-doc-pdf.yml
10+
pull_request:
11+
branches:
12+
- master
13+
paths:
14+
- doc/**
15+
- .github/workflows/update-doc-pdf.yml
16+
workflow_dispatch:
17+
18+
jobs:
19+
check-parameters:
20+
runs-on: ubuntu-latest
21+
defaults:
22+
run:
23+
shell: bash -l {0}
24+
steps:
25+
- uses: actions/checkout@v4
26+
- uses: conda-incubator/setup-miniconda@v3
27+
with:
28+
python-version: "3.11"
29+
activate-environment: sparc-test
30+
conda-build-version: "24.9.0"
31+
miniforge-version: latest # Fix according to https://github.com/conda-incubator/setup-miniconda?tab=readme-ov-file#example-10-miniforge
32+
channels: conda-forge,defaults
33+
channel-priority: true
34+
- name: Install SPARC-X-API stable version for docparser
35+
run: |
36+
mamba install -c conda-forge pip setuptools
37+
pip install git+https://github.com/SPARC-X/[email protected]
38+
- name: Convert parameters.json
39+
run: |
40+
python -m sparc.docparser --include-subdirs doc/.LaTeX
41+
- name: Check missing parameters in test examples
42+
run: |
43+
# Usage:
44+
# python test-missing-parameters.py <test-dir> <parameters.json>
45+
# If test fails, a list of missing / typo params will
46+
# be written in output
47+
python .github/workflows/test-missing-parameters.py \
48+
tests/ ./parameters.json
49+
50+
render-pdf-linux:
51+
runs-on: ubuntu-latest
52+
defaults:
53+
run:
54+
shell: bash -l {0}
55+
needs: check-parameters
56+
steps:
57+
- uses: actions/checkout@v4
58+
- uses: conda-incubator/setup-miniconda@v3
59+
with:
60+
python-version: "3.11"
61+
activate-environment: sparc-test
62+
conda-build-version: "24.9.0"
63+
miniforge-version: latest # Fix according to https://github.com/conda-incubator/setup-miniconda?tab=readme-ov-file#example-10-miniforge
64+
channels: conda-forge,defaults
65+
channel-priority: true
66+
- name: Install tectonic as latex rendering engine
67+
run: |
68+
mamba install -c conda-forge tectonic
69+
- name: Make temp build dir
70+
run: |
71+
mkdir -p doc/_build
72+
- name: Render main manual
73+
run: |
74+
tectonic -X compile doc/.LaTeX/Manual.tex \
75+
--outdir doc/_build
76+
ls -al doc/_build
77+
- name: Render subdir manuals
78+
run: |
79+
for dir in doc/.LaTeX/*; do
80+
if [ -d "$dir" ]; then
81+
manual=$(find "$dir" -maxdepth 1 -name "*Manual.tex" | head -n 1)
82+
if [ -n "$manual" ]; then
83+
tectonic -X compile "$manual" \
84+
--outdir doc/_build
85+
echo "Rendered: $manual"
86+
fi
87+
fi
88+
done
89+
ls -al doc/_build
90+

ChangeLog

+9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
-Date
33
-Name
44
-changes
5+
--------------
6+
Nov 23, 2024
7+
Name: Tian Tian
8+
Changes: (doc, CI workflow)
9+
1. Fix typo in SQ LaTeX doc
10+
2. Add CI workflow to check missing parameters
11+
3. Add CI workflow to validate and render LaTeX doc
12+
4. Add CI workflow to check outdated initialization.c (SPARC version) if older than current Changelog
13+
514
--------------
615
Nov 18, 2024
716
Name: Tian Tian, Lucas Timmerman

doc/.LaTeX/Introduction.tex

+10
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
\begin{itemize}
4747
\item \textbf{Benjamin Comer}: Code testing, Initial testing framework
4848
\item \textbf{Sushree Jagriti Sahoo}: Code testing
49+
\item \textbf{Tian Tian}: Socket communication layer, code testing, Python API
50+
\item \textbf{Lucas R Timmerman}: Socket communication layer, code testing, Python API
4951
\end{itemize}
5052
\end{itemize}
5153

@@ -416,6 +418,14 @@
416418
\begin{block}{Orbital Free DFT}
417419
\hyperlink{OFDFT_FLAG}{\texttt{OFDFT\_FLAG}} $\vert$ \hyperlink{TOL_OFDFT}{\texttt{TOL\_OFDFT}} $\vert$ \hyperlink{OFDFT_LAMBDA}{\texttt{OFDFT\_LAMBDA}}
418420
\end{block}
421+
422+
\begin{block}{Socket communication}
423+
\hyperlink{SOCKET_FLAG}{\texttt{SOCKET\_FLAG}} $\vert$
424+
\hyperlink{SOCKET_HOST}{\texttt{SOCKET\_HOST}} $\vert$
425+
\hyperlink{SOCKET_PORT}{\texttt{SOCKET\_PORT}} $\vert$
426+
\hyperlink{SOCKET_INET}{\texttt{SOCKET\_INET}} $\vert$
427+
\hyperlink{SOCKET_MAX_NITER}{\texttt{SOCKET\_MAX\_NITER}} $\vert$
428+
\end{block}
419429

420430
\end{frame}
421431

0 commit comments

Comments
 (0)