-
Notifications
You must be signed in to change notification settings - Fork 38
Expand file tree
/
Copy pathjob.py
More file actions
189 lines (145 loc) · 5.77 KB
/
Copy pathjob.py
File metadata and controls
189 lines (145 loc) · 5.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import typing as T
import os
import logging
import subprocess
import shutil
from pathlib import Path
import functools
from .mpi import get_mpi_count
from .config import read_config, get_config_filename
from .hpc import hpc_batch_detect, hpc_batch_create
from .model_setup import model_setup
Pathlike = T.Union[str, Path]
def runner(pr: T.Dict[str, T.Any]) -> int:
config_file = get_config_filename(pr["config_file"])
# load configuration to know what directories to check
p = read_config(config_file)
for k in ("indat_size", "indat_grid", "indat_file"):
f = p[k].expanduser().resolve()
if pr["force"] or not f.is_file():
model_setup(p["nml"], pr["out_dir"])
if not f.is_file():
raise FileNotFoundError(f"\ntried to initialize simulation but missing expected output file {f}")
break
if p.get("flagE0file") == 1:
E0dir = p["E0dir"].expanduser().resolve()
if not E0dir.is_dir():
model_setup(p["nml"], pr["out_dir"])
if not E0dir.is_dir():
raise FileNotFoundError(E0dir)
if p.get("flagprecfile") == 1:
precdir = p["precdir"].expanduser().resolve()
if not precdir.is_dir():
model_setup(p["nml"], pr["out_dir"])
if not precdir.is_dir():
raise FileNotFoundError(precdir)
# build checks
mpiexec = check_mpiexec(pr["mpiexec"])
logging.info(f"Detected mpiexec: {' '.join(mpiexec)}")
gemexe = check_gemini_exe(pr["gemexe"])
logging.info(f"using gemini executable: {gemexe}")
out_dir = check_outdir(pr["out_dir"])
Nmpi = get_mpi_count(config_file)
cmd = mpiexec + ["-n", str(Nmpi), str(gemexe), str(config_file), str(out_dir)]
if pr["out_format"]:
cmd += ["-out_format", pr["out_format"]]
print(" ".join(cmd), "\n")
batcher = hpc_batch_detect()
if batcher:
job_file = hpc_batch_create(batcher, out_dir, cmd) # noqa: F841
# hpc_submit_job(job_file)
print("Please examine batch file", job_file, "and when ready submit the job as usual.")
ret = 0
else:
ret = subprocess.run(cmd).returncode
return ret
@functools.lru_cache()
def wsl_available() -> bool:
"""
heuristic to detect if Windows Subsystem for Linux is available.
Uses presence of /etc/os-release in the WSL image to say Linux is there.
This is a de facto file standard across Linux distros.
"""
has_wsl = False
if os.name == "nt" and shutil.which("wsl"):
has_wsl = wsl_file_exist("/etc/os-release")
return has_wsl
def wsl_file_exist(file: Pathlike) -> bool:
"""
path is specified as if in WSL
NOT //wsl$/Ubuntu/etc/os-release
but /etc/os-release
"""
if os.name != "nt":
return False
try:
return subprocess.run(["wsl", "test", "-f", str(file)], timeout=10).returncode == 0
except subprocess.TimeoutExpired:
return False
def check_compiler():
fc = os.environ.get("FC")
fc = shutil.which(fc) if fc else shutil.which("gfortran")
if not fc:
raise EnvironmentError("Cannot find Fortran compiler e.g. Gfortran")
def check_mpiexec(mpiexec: Pathlike) -> T.List[str]:
""" check that specified mpiexec exists on this system """
if not mpiexec:
mpiexec = "mpiexec"
mpi_root = os.getenv("MPI_ROOT")
if mpi_root:
mpi_root += "/bin"
mpiexec = shutil.which(mpiexec, path=mpi_root)
if mpiexec:
mpi_exec = [mpiexec]
else:
msg = "Need mpiexec to run simulations"
if os.name == "nt":
msg += "\n\n Typically Windows users use Windows Subsystem for Linux (WSL)"
if wsl_available():
msg += "\n 😊 WSL appears to be already installed on your PC, look in the Start menu for Ubuntu or see:"
mpi_exec = ["wsl", "mpiexec"]
ret = subprocess.run(mpi_exec + ["--version"])
if ret.returncode != 0:
mpi_exec = []
msg += "\n 📖 WSL install guide: https://docs.microsoft.com/en-us/windows/wsl/install-win10"
if not mpi_exec:
raise EnvironmentError(msg)
return mpi_exec
def check_gemini_exe(gemexe: Pathlike) -> str:
"""
check that Gemini exectuable can run on this system
If not given a specific full path to gemini.bin, looks for gemini.bin under:
build
build / Release
build / Debug
"""
if gemexe:
gemexe = Path(gemexe).expanduser()
if not gemexe.is_file():
raise EnvironmentError(f"Cannot find gemini.bin in {gemexe}")
else:
build_dir = Path(__file__).resolve().parents[1] / "build"
if not build_dir.is_dir():
raise EnvironmentError(f"Build directory missing: {build_dir}")
for d in (build_dir, build_dir / "Release", build_dir / "Debug"):
gemexe = shutil.which("gemini.bin", path=str(d))
if gemexe:
break
if not gemexe:
raise EnvironmentError(f"\nCannot find gemini.bin under {build_dir}")
gemexe = str(Path(gemexe).resolve())
ret = subprocess.run(gemexe, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, universal_newlines=True)
if ret.returncode != 77:
raise RuntimeError(
f"\n{gemexe} was not runnable on your platform. Try recompiling on this computer type."
"E.g. different HPC nodes may not have the CPU feature sets."
f"{ret.stderr}"
)
return gemexe
def check_outdir(out_dir: Pathlike) -> Path:
out_dir = Path(out_dir).expanduser().resolve()
if out_dir.is_file():
raise NotADirectoryError(f"please specify output DIRECTORY, you specified {out_dir}")
if not out_dir.is_dir():
out_dir.mkdir(parents=True, exist_ok=True)
return out_dir