11name : interface
22
3- # 仅支持手动触发,不自动运行
43on :
54 workflow_dispatch :
65
@@ -48,129 +47,130 @@ jobs:
4847 echo "OK: no wannier90.x (dryrun mode)"
4948
5049 # ================================================================
51- # Shared mock + patch (covers all three scripts)
50+ # Shared mock + patch
51+ # NOTE: env: MUST be a sibling of run: (same indent level).
52+ # run: uses block scalar literal (|) so the heredoc inside
53+ # is passed to bash with YAML indentation stripped.
5254 # ================================================================
5355 - name : Create mock data & patch script
54- run : python3 << 'PYEOF'
55- import os, re, textwrap
56-
57- script = os.environ["SCRIPT"]
58- prefix = os.environ["PREFIX"]
59-
60- # ── 1. Patch the example script ────────────────────────────
61- with open(script) as f :
62- src = f.read()
63-
64- # Enable dry run
65- src = src.replace("DRY_RUN = False", "DRY_RUN = True")
66-
67- # Skip step0 — requires ABACUS binary
68- src = re.sub(
69- r"\s*job\.step0_run_scf\([^)]*\)",
70- " # [CI:skip] step0_run_scf — no ABACUS in this environment" ,
71- src,
72- flags=re.DOTALL,
73- )
74-
75- # Skip step1 — requires wannier90.x binary
76- src = src.replace(
77- " job.step1_generate_wannier_win()" ,
78- " # [CI:skip] step1_generate_wannier_win — no wannier90.x in this environment" ,
79- )
80-
81- with open(script, "w") as f :
82- f.write(src)
83- print(f"[patch] {script}")
84-
85- # ── 2. Create work directories ─────────────────────────────
86- for d in [f"{prefix}/scf", f"{prefix}/wannier"] :
87- os.makedirs(d, exist_ok=True)
88-
89- # ── 3. Mock STRU (scf/ + wannier/) ────────────────────────
90- stru = textwrap.dedent("""\
91- ATOMIC_SPECIES
92- Bi 208.980 Bi.upf
93- Se 78.960 Se.upf
94-
95- LATTICE_CONSTANT
96- 1.0
97-
98- LATTICE_VECTORS
99- -2.069 -3.583614 0.0
100- 2.069 -3.583614 0.0
101- 0.000 2.389075 9.546667
102-
103- ATOMIC_POSITIONS
104- Direct
105-
106- Bi
107- 0.399 0.399 0.697 1 1 1
108- 0.601 0.601 0.303 1 1 1
109-
110- Se
111- 0.000 0.000 0.500 1 1 1
112- 0.206 0.206 0.118 1 1 1
113- 0.794 0.794 0.882 1 1 1
114- " " " )
115- for d in [f" {prefix}/scf", f"{prefix}/wannier"]:
116- p = os.path.join(d, "STRU")
117- with open(p, "w") as f :
118- f.write(stru)
119- print(f"[mock] {p}")
120-
121- # ── 4. Mock wannier90.nnkp ────────────────────────────────
122- nbands = 20
123- nk = 64 # 4 × 4 × 4
124- nntot = 14
125-
126- lines = [
127- f" {nbands}", "! num_bands",
128- f" {nk}", "! num_kpts",
129- " 4 4 4" , "! mp_grid",
130- ]
131- for ix in range(4) :
132- for iy in range(4) :
133- for iz in range(4) :
134- lines.append(f" {ix/4:.15f} {iy/4:.15f} {iz/4:.15f}")
135-
136- lines.append(f" {nntot}")
137- lines.append("! nntot")
138- for ik in range(nk) :
139- lines.append(f" {nntot}")
140- for ib in range(nntot) :
141- lines.append(f" {(ik + ib) % nk + 1}")
142- lines.append(f" {nntot}")
143- for ib in range(nntot) :
144- lines.append(" 0 0 0")
145-
146- lines += [
147- f" {nbands}", "! num_exclude_bands",
148- " 30" , "! num_wann",
149- " 6" , "! num_proj",
150- ]
151- for proj in ["Bi : pz","Bi : px","Bi : py",
152- " Se : pz" ,"Se : px","Se : py"]:
153- lines.append(f" {proj}")
154-
155- nnkp = os.path.join(prefix, "wannier", "wannier90.nnkp")
156- with open(nnkp, "w") as f :
157- f.write("\n".join(lines) + "\n")
158- print(f"[mock] {nnkp} ({len(lines)} lines)")
159-
160- # ── 5. Mock PP & ORB files (unified path for all 3 scripts) ──
161- orb_dir = "tests/PP_ORB/for_interface/Wannier90_interface"
162- os.makedirs(orb_dir, exist_ok=True)
163- for name in ["Bi.upf", "Se.upf", "Bi.orb", "Se.orb"] :
164- p = os.path.join(orb_dir, name)
165- with open(p, "w") as f :
166- f.write("# mock for CI dryrun\n")
167- print(f"[mock] {p}")
168-
169- print("\n[done] all mocks ready")
170- PYEOF
17156 env :
17257 SCRIPT : ${{ matrix.script }}
17358 PREFIX : ${{ matrix.prefix }}
59+ run : |
60+ python3 << 'PYEOF'
61+ import os, re, textwrap
62+
63+ script = os.environ["SCRIPT"]
64+ prefix = os.environ["PREFIX"]
65+
66+ # ── 1. Patch the example script ────────────────────────
67+ with open(script) as f:
68+ src = f.read()
69+
70+ src = src.replace("DRY_RUN = False", "DRY_RUN = True")
71+
72+ src = re.sub(
73+ r"\s*job\.step0_run_scf\([^)]*\)",
74+ " # [CI:skip] step0_run_scf — no ABACUS in this environment",
75+ src,
76+ flags=re.DOTALL,
77+ )
78+
79+ src = src.replace(
80+ "job.step1_generate_wannier_win()",
81+ "# [CI:skip] step1_generate_wannier_win — no wannier90.x in this environment",
82+ )
83+
84+ with open(script, "w") as f:
85+ f.write(src)
86+ print(f"[patch] {script}")
87+
88+ # ── 2. Create work directories ─────────────────────────
89+ for d in [f"{prefix}/scf", f"{prefix}/wannier"]:
90+ os.makedirs(d, exist_ok=True)
91+
92+ # ── 3. Mock STRU (scf/ + wannier/) ────────────────────
93+ stru = textwrap.dedent("""\
94+ ATOMIC_SPECIES
95+ Bi 208.980 Bi.upf
96+ Se 78.960 Se.upf
97+
98+ LATTICE_CONSTANT
99+ 1.0
100+
101+ LATTICE_VECTORS
102+ -2.069 -3.583614 0.0
103+ 2.069 -3.583614 0.0
104+ 0.000 2.389075 9.546667
105+
106+ ATOMIC_POSITIONS
107+ Direct
108+
109+ Bi
110+ 0.399 0.399 0.697 1 1 1
111+ 0.601 0.601 0.303 1 1 1
112+
113+ Se
114+ 0.000 0.000 0.500 1 1 1
115+ 0.206 0.206 0.118 1 1 1
116+ 0.794 0.794 0.882 1 1 1
117+ """)
118+ for d in [f"{prefix}/scf", f"{prefix}/wannier"]:
119+ p = os.path.join(d, "STRU")
120+ with open(p, "w") as f:
121+ f.write(stru)
122+ print(f"[mock] {p}")
123+
124+ # ── 4. Mock wannier90.nnkp ────────────────────────────
125+ nbands = 20
126+ nk = 64 # 4 × 4 × 4
127+ nntot = 14
128+
129+ lines = [
130+ f" {nbands}", "! num_bands",
131+ f" {nk}", "! num_kpts",
132+ " 4 4 4", "! mp_grid",
133+ ]
134+ for ix in range(4):
135+ for iy in range(4):
136+ for iz in range(4):
137+ lines.append(f" {ix/4:.15f} {iy/4:.15f} {iz/4:.15f}")
138+
139+ lines.append(f" {nntot}")
140+ lines.append("! nntot")
141+ for ik in range(nk):
142+ lines.append(f" {nntot}")
143+ for ib in range(nntot):
144+ lines.append(f" {(ik + ib) % nk + 1}")
145+ lines.append(f" {nntot}")
146+ for ib in range(nntot):
147+ lines.append(" 0 0 0")
148+
149+ lines += [
150+ f" {nbands}", "! num_exclude_bands",
151+ " 30", "! num_wann",
152+ " 6", "! num_proj",
153+ ]
154+ for proj in ["Bi : pz","Bi : px","Bi : py",
155+ "Se : pz","Se : px","Se : py"]:
156+ lines.append(f" {proj}")
157+
158+ nnkp = os.path.join(prefix, "wannier", "wannier90.nnkp")
159+ with open(nnkp, "w") as f:
160+ f.write("\n".join(lines) + "\n")
161+ print(f"[mock] {nnkp} ({len(lines)} lines)")
162+
163+ # ── 5. Mock PP & ORB files ─────────────────────────────
164+ orb_dir = "tests/PP_ORB/for_interface/Wannier90_interface"
165+ os.makedirs(orb_dir, exist_ok=True)
166+ for name in ["Bi.upf", "Se.upf", "Bi.orb", "Se.orb"]:
167+ p = os.path.join(orb_dir, name)
168+ with open(p, "w") as f:
169+ f.write("# mock for CI dryrun\n")
170+ print(f"[mock] {p}")
171+
172+ print("\n[done] all mocks ready")
173+ PYEOF
174174
175175 # ================================================================
176176 # Run
@@ -211,11 +211,9 @@ jobs:
211211 check "$W/KPT"
212212 check "$W/STRU"
213213
214- # ── INPUT content checks ──────────────────────
215214 if [ -f "$W/INPUT" ]; then
216215 echo ""
217216 echo "--- INPUT keyword checks ---"
218-
219217 for key in "calculation" "towannier90" "nspin"; do
220218 if grep -qi "$key" "$W/INPUT"; then
221219 echo " [OK] INPUT contains '$key'"
@@ -224,8 +222,6 @@ jobs:
224222 ERR=1
225223 fi
226224 done
227-
228- # gamma_only is FORBIDDEN
229225 if grep -qi "gamma_only" "$W/INPUT"; then
230226 echo " [FAIL] INPUT contains 'gamma_only' — forbidden!"
231227 ERR=1
@@ -234,10 +230,8 @@ jobs:
234230 fi
235231 fi
236232
237- # ── Basis-specific checks ─────────────────────
238233 echo ""
239234 echo "--- Basis-specific checks (${{ matrix.basis }}) ---"
240-
241235 if [ "${{ matrix.basis }}" = "pw" ]; then
242236 if grep -qi "orbital_file\|orbital_dir" "$W/INPUT"; then
243237 echo " [FAIL] PW INPUT contains orbital_file/orbital_dir"
@@ -253,7 +247,6 @@ jobs:
253247 fi
254248 fi
255249
256- # ── KPT sanity ────────────────────────────────
257250 if [ -f "$W/KPT" ]; then
258251 echo ""
259252 klines=$(wc -l < "$W/KPT")
@@ -298,4 +291,3 @@ jobs:
298291 - name : List all generated files
299292 if : always()
300293 run : find ${{ matrix.prefix }} -type f | sort
301-
0 commit comments