Skip to content

Commit 9684b82

Browse files
authored
add running molecule sims with fdmnes (#17)
1 parent 71ba4f2 commit 9684b82

30 files changed

+513
-201
lines changed

database/tables.sql

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ INSERT INTO "simulation_type" VALUES(2,'FDMNES');
2323
INSERT INTO "simulation_type" VALUES(3,'Quantum ESPRESSO');
2424

2525

26-
CREATE TYPE simulation_status_enum AS ENUM('requested', 'submitted', 'running', 'completed', 'failed', 'error');
26+
CREATE TYPE simulation_status_enum AS ENUM('requested', 'submitted', 'running', 'completed', 'failed', 'error', 'request_cancel', 'cancelled');
2727

2828
CREATE TABLE simulation (
2929
id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
@@ -68,7 +68,7 @@ CREATE TABLE molecular_structure (
6868
COMMENT ON TABLE molecular_structure IS 'Table to hold molecular structures';
6969

7070

71-
CREATE TYPE ibrav_enum AS ENUM('1', '2', '3','-3', '4', '5','-5', '6', '7', '8', '9','-9','91', '10', '11', '12','-12', '13','-13', '14');
71+
-- CREATE TYPE ibrav_enum AS ENUM('1', '2', '3','-3', '4', '5','-5', '6', '7', '8', '9','-9','91', '10', '11', '12','-12', '13','-13', '14');
7272

7373

7474
CREATE TABLE crystal_structure (
@@ -81,7 +81,6 @@ CREATE TABLE crystal_structure (
8181
alpha NUMERIC NOT NULL,
8282
beta NUMERIC NOT NULL,
8383
gamma NUMERIC NOT NULL,
84-
ibrav ibrav_enum NOT NULL,
8584
person_id INTEGER NOT NULL
8685
);
8786

@@ -129,17 +128,21 @@ CREATE TABLE orca_simulation_spectrum(
129128

130129
CREATE TYPE edge_enum AS ENUM('k', 'l1', 'l2', 'l3', 'm1', 'm2', 'm3', 'm4', 'm5');
131130

132-
CREATE TYPE structure_enum AS ENUM('crystal', 'molecule');
131+
-- MAKE JUST ONE FDMNES ENTRY
132+
133133

134134
CREATE TABLE fdmnes_simulation (
135135
simulation_id INTEGER PRIMARY KEY,
136136
simulation_type_id INTEGER GENERATED ALWAYS AS (2) STORED,
137-
crystal_structure_id INTEGER NOT NULL,
137+
crystal_structure_id INTEGER,
138+
molecular_structure_id INTEGER,
138139
element INTEGER NOT NULL,
139140
edge edge_enum NOT NULL,
140141
greens_approach BOOLEAN NOT NULL,
141-
structure_type structure_enum NOT NULL,
142142

143+
CONSTRAINT chk_only_one_is_not_null CHECK (num_nonnulls(crystal_structure_id, molecular_structure_id) = 1),
144+
145+
FOREIGN KEY(molecular_structure_id) REFERENCES molecular_structure (id),
143146
FOREIGN KEY(crystal_structure_id) REFERENCES crystal_structure (id),
144147
FOREIGN KEY(simulation_id, simulation_type_id) REFERENCES simulation (id,simulation_type_id)
145148
);
@@ -169,11 +172,11 @@ O 0.0000000 0.0000000 -0.1653507
169172
H -0.7493682 0.0000000 0.4424329');
170173

171174

172-
INSERT INTO crystal_structure(label, person_id,a,b,c,alpha,beta,gamma,ibrav,structure) VALUES('Silver',1,4.1043564,4.1043564,4.1043564,90,90,90,'2','Ag 0.0 0.0 0.0
175+
INSERT INTO crystal_structure(label, person_id,a,b,c,alpha,beta,gamma,structure) VALUES('Silver',1,4.1043564,4.1043564,4.1043564,90,90,90,'Ag 0.0 0.0 0.0
173176
Ag 0.5 0.5 0.0
174177
Ag 0.5 0.0 0.5
175178
Ag 0.0 0.5 0.5');
176179

177180

178-
INSERT INTO crystal_structure(label, person_id,a,b,c,alpha,beta,gamma,ibrav,structure) VALUES('KCl',1,6.28,6.28,6.28,90,90,90,'2','K 0.0 0.0 0.0
179-
Cl 0.5 0.0 0.0');
181+
INSERT INTO crystal_structure(label, person_id,a,b,c,alpha,beta,gamma,structure) VALUES('KCl',1,4.44,4.44,4.44,60,60,60,'K 0.0 0.0 0.0
182+
Cl 0.5 0.5 0.5');

web-conexs-api/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ dependencies = [
1919
"psycopg2",
2020
"numpy",
2121
"requests",
22+
"pymatgen"
2223
] # Add project dependencies here, e.g. ["click", "numpy"]
2324
dynamic = ["version"]
2425
license.file = "LICENSE"

web-conexs-api/src/slurm_submission_service/crud.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
build_fdmnes_inputfile,
77
build_orca_input_file,
88
build_qe_inputfile,
9+
fdmnes_molecule_to_crystal,
910
)
1011
from web_conexs_api.models.models import (
1112
CrystalStructure,
@@ -79,9 +80,22 @@ def get_crystal_structure(session, id):
7980

8081
def get_fdmnes_jobfile(session, id):
8182
fdmnes_simulation = get_fdmnes_simulation(session, id)
82-
structure = get_crystal_structure(session, fdmnes_simulation.crystal_structure_id)
8383

84-
return build_fdmnes_inputfile(fdmnes_simulation, structure)
84+
if fdmnes_simulation.crystal_structure_id is not None:
85+
structure = get_crystal_structure(
86+
session, fdmnes_simulation.crystal_structure_id
87+
)
88+
crystalIsMolecule = False
89+
else:
90+
molecule = get_molecular_structure(
91+
session, fdmnes_simulation.molecular_structure_id
92+
)
93+
structure = fdmnes_molecule_to_crystal(molecule)
94+
crystalIsMolecule = True
95+
96+
print(structure.structure)
97+
98+
return build_fdmnes_inputfile(fdmnes_simulation, structure, crystalIsMolecule)
8599

86100

87101
def get_submitted_simulations(session) -> List[Simulation]:
@@ -91,6 +105,13 @@ def get_submitted_simulations(session) -> List[Simulation]:
91105
return session.exec(statement).all()
92106

93107

108+
def get_request_cancelled_simulations(session) -> List[Simulation]:
109+
statement = select(Simulation).where(
110+
Simulation.status == SimulationStatus.request_cancel
111+
)
112+
return session.exec(statement).all()
113+
114+
94115
def update_simulation(session, simulation: Simulation):
95116
session.add(simulation)
96117
session.commit()

web-conexs-api/src/slurm_submission_service/submitter.py

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
get_fdmnes_jobfile,
2222
get_orca_jobfile_with_technique,
2323
get_qe_jobfile,
24+
get_request_cancelled_simulations,
2425
get_submitted_simulations,
2526
update_simulation,
2627
)
@@ -62,15 +63,13 @@ def get_token():
6263
return fh.read()
6364

6465

65-
def build_job_and_run(
66-
script, user_id, working_dir, job_name, cpus, memory, cluster_dir
67-
):
66+
def build_job_and_run(script, job_name, cpus, memory, cluster_dir, as_tasks):
6867
job_request = {
6968
"job": {
7069
"partition": SLURM_PARTITION,
7170
"name": job_name,
7271
"nodes": 1,
73-
"tasks": cpus,
72+
"tasks": 1 if as_tasks else cpus,
7473
"memory_per_node": int(memory * 1000),
7574
"time_limit": 30,
7675
"current_working_directory": str(cluster_dir),
@@ -83,6 +82,13 @@ def build_job_and_run(
8382
"script": script,
8483
}
8584

85+
if as_tasks:
86+
job_request["job"]["ntasks_per_node"] = 1
87+
job_request["job"]["cpus_per_task"] = cpus
88+
job_request["job"]["environment"]["OMP_NUM_THREADS"] = cpus
89+
90+
logger.debug(job_request)
91+
8692
url_submit = SLURM_API + "/job/submit"
8793

8894
slurm_token = get_token()
@@ -160,7 +166,7 @@ def submit_orca(session, sim: Simulation):
160166

161167
try:
162168
job_id = build_job_and_run(
163-
script, user, working_dir, job_name, sim.n_cores, sim.memory, cluster_dir
169+
script, job_name, sim.n_cores, sim.memory, cluster_dir, False
164170
)
165171
sim.job_id = job_id
166172
sim.working_directory = working_dir
@@ -171,6 +177,7 @@ def submit_orca(session, sim: Simulation):
171177
logger.exception("Error submitting orca job")
172178
sim.status = SimulationStatus.failed
173179
update_simulation(session, sim)
180+
logger.exception("Error submitting ORCA job")
174181

175182

176183
def submit_fdmnes(session, sim: Simulation):
@@ -200,12 +207,12 @@ def submit_fdmnes(session, sim: Simulation):
200207

201208
script = (
202209
"#!/bin/bash\n"
203-
+ f"singularity exec {fdmnes_sif} mpirun -np 4 fdmnes_mpi > fdmnes_result.txt"
210+
+ f"singularity exec {fdmnes_sif} mpirun -np 1 fdmnes_mpi > fdmnes_result.txt"
204211
)
205212

206213
try:
207214
job_id = build_job_and_run(
208-
script, user, working_dir, job_name, sim.n_cores, sim.memory, cluster_dir
215+
script, job_name, sim.n_cores, sim.memory, cluster_dir, True
209216
)
210217
sim.job_id = job_id
211218
sim.working_directory = working_dir
@@ -215,10 +222,41 @@ def submit_fdmnes(session, sim: Simulation):
215222
except Exception:
216223
sim.status = SimulationStatus.failed
217224
update_simulation(session, sim)
225+
logger.exception("Error submitting FDMNES job")
226+
227+
228+
def clean_request_cancelled(session):
229+
request_cancel = get_request_cancelled_simulations(session)
230+
231+
for sim in request_cancel:
232+
if sim.job_id is None:
233+
# No job id, hasn't been submitted, so just flag as cancelled
234+
sim.status = SimulationStatus.cancelled
235+
update_simulation(session, sim)
236+
else:
237+
url = SLURM_API + "/job/" + str(sim.job_id)
238+
slurm_token = get_token()
239+
240+
headers = {
241+
"X-SLURM-USER-NAME": SLURM_USER,
242+
"X-SLURM-USER-TOKEN": slurm_token,
243+
"Content-Type": "application/json",
244+
}
245+
246+
r = requests.delete(url, headers=headers)
247+
248+
if r.status_code != 200:
249+
logger.error(f"Job delete response not successful {r.status_code}")
250+
continue
251+
252+
sim.status = SimulationStatus.cancelled
253+
update_simulation(session, sim)
218254

219255

220256
def run_update():
221257
with contextmanager(get_session)() as session:
258+
clean_request_cancelled(session)
259+
222260
# sessions = get_session()
223261
# session = next(sessions)
224262
sims = get_submitted_simulations(session)
@@ -342,7 +380,7 @@ def submit_qe(session, sim: Simulation):
342380

343381
try:
344382
job_id = build_job_and_run(
345-
script, user, working_dir, job_name, sim.n_cores, sim.memory, cluster_dir
383+
script, job_name, sim.n_cores, sim.memory, cluster_dir, False
346384
)
347385
sim.job_id = job_id
348386
sim.working_directory = working_dir
@@ -352,14 +390,18 @@ def submit_qe(session, sim: Simulation):
352390
except Exception:
353391
sim.status = SimulationStatus.failed
354392
update_simulation(session, sim)
393+
logger.exception("Error submitting QE job")
355394

356395

357-
def test_read():
358-
with contextmanager(get_session)() as session:
359-
sims = get_submitted_simulations(session)
360-
for sim in sims:
361-
if sim.simulation_type_id == 1:
362-
jf, calc = get_orca_jobfile_with_technique(session, sim.id)
396+
# def test_read():
397+
# with contextmanager(get_session)() as session:
398+
# sims = get_submitted_simulations(session)
399+
# for sim in sims:
400+
# if sim.simulation_type_id == 1:
401+
# jf, calc = get_orca_jobfile_with_technique(session, sim.id)
402+
# elif sim.simulation_type_id == 2:
403+
# jobfile = get_fdmnes_jobfile(session, sim.id)
404+
# logger.error(jobfile)
363405

364406

365407
def main():
@@ -377,6 +419,8 @@ def main():
377419

378420
logger.info("Running main loop")
379421

422+
# test_read()
423+
380424
while True:
381425
try:
382426
run_update()

web-conexs-api/src/web_conexs_api/crud.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
QESimulation,
2828
QESimulationInput,
2929
Simulation,
30+
SimulationStatus,
3031
)
3132

3233

@@ -139,8 +140,12 @@ def get_simulations_page(session, user_id) -> CursorPage[Simulation]:
139140
return paginate(session, statement.order_by(Simulation.id.desc()))
140141

141142

142-
def get_simulation(session, id, user_id):
143-
statement = select(Simulation).join(Person).where(Simulation.id == id)
143+
def get_simulation(session, id, user_id) -> Simulation:
144+
statement = (
145+
select(Simulation)
146+
.join(Person)
147+
.where(and_(Person.identifier == user_id, Simulation.id == id))
148+
)
144149

145150
simulation = session.exec(statement).first()
146151

@@ -424,3 +429,19 @@ def get_qe_xas(session, id, user_id):
424429
output = {"energy": out[:, 0].tolist(), "xas": out[:, 1].tolist()}
425430

426431
return output
432+
433+
434+
def request_cancel_simulation(session, id, user_id):
435+
sim = get_simulation(session, id, user_id)
436+
437+
if (
438+
sim.status == SimulationStatus.running
439+
or sim.status == SimulationStatus.requested
440+
or sim.status == SimulationStatus.submitted
441+
):
442+
sim.status = SimulationStatus.request_cancel
443+
session.add(sim)
444+
session.commit()
445+
session.refresh(sim)
446+
447+
return sim

0 commit comments

Comments
 (0)