Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions calphy/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,27 +96,27 @@ def _extract_elements_from_pair_coeff(pair_coeff_string):
"""
Extract element symbols from pair_coeff string.
Returns None if pair_coeff doesn't contain element specifications.

Parameters
----------
pair_coeff_string : str
The pair_coeff command string (e.g., "* * potential.eam.fs Cu Zr")

Returns
-------
list or None
List of element symbols in order, or None if no elements found
"""
if pair_coeff_string is None:
return None

pcsplit = pair_coeff_string.strip().split()
elements = []

# Start collecting after we find element symbols
# Elements are typically after the potential filename
started = False

for p in pcsplit:
# Check if this looks like an element symbol
# Element symbols are 1-2 characters, start with uppercase
Expand All @@ -131,7 +131,7 @@ def _extract_elements_from_pair_coeff(pair_coeff_string):
if started:
# We already started collecting elements and hit a non-element
break

return elements if len(elements) > 0 else None


Expand Down Expand Up @@ -208,7 +208,6 @@ class Queue(BaseModel, title="Options for configuring queue"):
memory: Annotated[str, Field(default="3GB")]
commands: Annotated[List, Field(default=[])]
options: Annotated[List, Field(default=[])]
modules: Annotated[List, Field(default=[])]


class Tolerance(BaseModel, title="Tolerance settings for convergence"):
Expand Down Expand Up @@ -356,13 +355,17 @@ def _validate_all(self) -> "Input":
raise ValueError("mass and elements should have same length")

self.n_elements = len(self.element)

# Validate element/mass/pair_coeff ordering consistency
# This is critical for multi-element systems where LAMMPS type numbers
# are assigned based on element order: element[0]=Type1, element[1]=Type2, etc.
if len(self.element) > 1 and self.pair_coeff is not None and len(self.pair_coeff) > 0:
if (
len(self.element) > 1
and self.pair_coeff is not None
and len(self.pair_coeff) > 0
):
extracted_elements = _extract_elements_from_pair_coeff(self.pair_coeff[0])

if extracted_elements is not None:
# pair_coeff specifies elements - check ordering
if set(extracted_elements) != set(self.element):
Expand All @@ -372,7 +375,7 @@ def _validate_all(self) -> "Input":
f" pair_coeff: {extracted_elements}\n"
f"The elements specified must be the same."
)

if list(extracted_elements) != list(self.element):
raise ValueError(
f"Element ordering mismatch detected!\n\n"
Expand Down
205 changes: 100 additions & 105 deletions calphy/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
energy calculations.

Copyright 2021 (c) Sarath Menon^1, Yury Lysogorskiy^2, Ralf Drautz^2
^1: Max Planck Institut für Eisenforschung, Dusseldorf, Germany
^1: Max Planck Institut für Eisenforschung, Dusseldorf, Germany
^2: Ruhr-University Bochum, Bochum, Germany

calphy is published and distributed under the Academic Software License v1.0 (ASL).
calphy is distributed in the hope that it will be useful for non-commercial academic research,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
calphy is published and distributed under the Academic Software License v1.0 (ASL).
calphy is distributed in the hope that it will be useful for non-commercial academic research,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
calphy API is published and distributed under the BSD 3-Clause "New" or "Revised" License
See the LICENSE FILE for more details.
See the LICENSE FILE for more details.

More information about the program can be found in:
Menon, Sarath, Yury Lysogorskiy, Jutta Rogal, and Ralf Drautz.
Expand All @@ -25,25 +25,26 @@
import os
import stat


class Local:
"""
Local submission script
"""

def __init__(self, options, cores=1, directory=os.getcwd()):
self.queueoptions = {"scheduler": "local",
"jobname": "tis",
"queuename": None,
"memory": None,
"cores": cores,
"hint": None,
"directory": directory,
"options": [],
"commands": [],
"modules": [],
"header": "#!/bin/bash"

}
for (key, val) in options.items():
self.queueoptions = {
"scheduler": "local",
"jobname": "tis",
"queuename": None,
"memory": None,
"cores": cores,
"hint": None,
"directory": directory,
"options": [],
"commands": [],
"header": "#!/bin/bash",
}
for key, val in options.items():
if key in self.queueoptions.keys():
if val is not None:
self.queueoptions[key] = val
Expand All @@ -60,14 +61,10 @@ def write_script(self, outfile):
fout.write(self.queueoptions["header"])
fout.write("\n")

#now write modules
for module in self.queueoptions["modules"]:
fout.write("module load %s\n" %module)

#now finally commands
# now finally commands
for command in self.queueoptions["commands"]:
fout.write("%s\n" %command)
fout.write("%s > %s 2> %s\n" %(self.maincommand, jobout, joberr))
fout.write("%s\n" % command)
fout.write("%s > %s 2> %s\n" % (self.maincommand, jobout, joberr))
self.script = outfile

def submit(self):
Expand All @@ -77,41 +74,42 @@ def submit(self):
st = os.stat(self.script)
os.chmod(self.script, st.st_mode | stat.S_IEXEC)
cmd = [self.script]
proc = sub.Popen(cmd, stdin=sub.PIPE,stdout=sub.PIPE,stderr=sub.PIPE)
proc = sub.Popen(cmd, stdin=sub.PIPE, stdout=sub.PIPE, stderr=sub.PIPE)
return proc


class SLURM:
"""
Slurm class for writing submission script
"""

def __init__(self, options, cores=1, directory=os.getcwd()):
"""
Create class
"""
self.queueoptions = {"scheduler": "slurm",
"jobname": "tis",
"queuename": None,
"walltime": "23:59:00",
"memory": "3GB",
"cores": cores,
"hint": "nomultithread",
"directory": directory,
"options": [],
"commands": [ "uss=$(whoami)",
"find /dev/shm/ -user $uss -type f -mmin +30 -delete",
],
"modules": [],
"header": "#!/bin/bash"

}
for (key, val) in options.items():
self.queueoptions = {
"scheduler": "slurm",
"jobname": "tis",
"queuename": None,
"walltime": "23:59:00",
"memory": "3GB",
"cores": cores,
"hint": "nomultithread",
"directory": directory,
"options": [],
"commands": [
"uss=$(whoami)",
"find /dev/shm/ -user $uss -type f -mmin +30 -delete",
],
"header": "#!/bin/bash",
}
for key, val in options.items():
if key in self.queueoptions.keys():
if val is not None:
if val != "":
self.queueoptions[key] = val
self.maincommand = ""


def write_script(self, outfile):
"""
Write the script file
Expand All @@ -123,69 +121,66 @@ def write_script(self, outfile):
fout.write(self.queueoptions["header"])
fout.write("\n")

#write the main header options
fout.write("#SBATCH --job-name=%s\n" %self.queueoptions["jobname"])
fout.write("#SBATCH --time=%s\n" %self.queueoptions["walltime"])
# write the main header options
fout.write("#SBATCH --job-name=%s\n" % self.queueoptions["jobname"])
fout.write("#SBATCH --time=%s\n" % self.queueoptions["walltime"])
if self.queueoptions["queuename"] is not None:
fout.write("#SBATCH --partition=%s\n"%self.queueoptions["queuename"])
fout.write("#SBATCH --ntasks=%s\n" %str(self.queueoptions["cores"]))
fout.write("#SBATCH --mem-per-cpu=%s\n"%self.queueoptions["memory"])
fout.write("#SBATCH --hint=%s\n" %self.queueoptions["hint"])
fout.write("#SBATCH --chdir=%s\n" %self.queueoptions["directory"])
fout.write("#SBATCH --partition=%s\n" % self.queueoptions["queuename"])
fout.write("#SBATCH --ntasks=%s\n" % str(self.queueoptions["cores"]))
fout.write("#SBATCH --mem-per-cpu=%s\n" % self.queueoptions["memory"])
fout.write("#SBATCH --hint=%s\n" % self.queueoptions["hint"])
fout.write("#SBATCH --chdir=%s\n" % self.queueoptions["directory"])

#now write extra options
# now write extra options
for option in self.queueoptions["options"]:
fout.write("#SBATCH %s\n" %option)
fout.write("#SBATCH %s\n" % option)

#now write modules
for module in self.queueoptions["modules"]:
fout.write("module load %s\n" %module)

#now finally commands
# now finally commands
for command in self.queueoptions["commands"]:
fout.write("%s\n" %command)
fout.write("%s > %s 2> %s\n" %(self.maincommand, jobout, joberr))
fout.write("%s\n" % command)
fout.write("%s > %s 2> %s\n" % (self.maincommand, jobout, joberr))

self.script = outfile

def submit(self):
"""
Submit the job
"""
cmd = ['sbatch', self.script]
proc = sub.Popen(cmd, stdin=sub.PIPE,stdout=sub.PIPE,stderr=sub.PIPE)
cmd = ["sbatch", self.script]
proc = sub.Popen(cmd, stdin=sub.PIPE, stdout=sub.PIPE, stderr=sub.PIPE)
print(f'submitting {self.queueoptions["jobname"]}')
proc.communicate()
return proc



class SGE:
"""
Slurm class for writing submission script
"""

def __init__(self, options, cores=1, directory=os.getcwd()):
"""
Create class
"""
self.queueoptions = {"scheduler": "sge",
"jobname": "tis",
"walltime": "23:59:00",
"queuename": None,
"memory": "3GB",
"system": "smp",
"commands": [],
"modules": [],
"options": ["-j y",
"-R y",
"-P ams.p",
],
"cores": cores,
"hint": None,
"directory": directory,
"header": "#!/bin/bash"
}
for (key, val) in options.items():
self.queueoptions = {
"scheduler": "sge",
"jobname": "tis",
"walltime": "23:59:00",
"queuename": None,
"memory": "3GB",
"system": "smp",
"commands": [],
"options": [
"-j y",
"-R y",
"-P ams.p",
],
"cores": cores,
"hint": None,
"directory": directory,
"header": "#!/bin/bash",
}
for key, val in options.items():
if key in self.queueoptions.keys():
if val is not None:
self.queueoptions[key] = val
Expand All @@ -195,40 +190,40 @@ def write_script(self, outfile):
"""
Write the script file
"""
jobout = ".".join([outfile, "out"])
joberr = ".".join([outfile, "err"])

with open(outfile, "w") as fout:
fout.write(self.queueoptions["header"])
fout.write("\n")

#write the main header options
fout.write("#$ -N %s\n" %self.queueoptions["jobname"])
fout.write("#$ -l h_rt=%s\n" %self.queueoptions["walltime"])
fout.write("#$ -l qname=%s\n"%self.queueoptions["queuename"])
fout.write("#$ -pe %s %s\n" %( self.queueoptions["system"], str(self.queueoptions["cores"])))
fout.write("#$ -l h_vmem=%s\n"%self.queueoptions["memory"])
fout.write("#$ -cwd %s\n" %self.queueoptions["directory"])

#now write extra options
# write the main header options
fout.write("#$ -N %s\n" % self.queueoptions["jobname"])
fout.write("#$ -l h_rt=%s\n" % self.queueoptions["walltime"])
fout.write("#$ -l qname=%s\n" % self.queueoptions["queuename"])
fout.write(
"#$ -pe %s %s\n"
% (self.queueoptions["system"], str(self.queueoptions["cores"]))
)
fout.write("#$ -l h_vmem=%s\n" % self.queueoptions["memory"])
fout.write("#$ -cwd %s\n" % self.queueoptions["directory"])

# now write extra options
for option in self.queueoptions["options"]:
fout.write("#$ %s\n" %option)

#now write modules
for module in self.queueoptions["modules"]:
fout.write("module load %s\n" %module)
fout.write("#$ %s\n" % option)

#now finally commands
# now finally commands
for command in self.queueoptions["commands"]:
fout.write("%s\n" %command)
fout.write("%s\n" % command)

fout.write("%s > %s 2> %s\n" %(self.maincommand, jobout, joberr))

self.script = outfile
fout.write("%s > %s 2> %s\n" % (self.maincommand, jobout, joberr))

self.script = outfile

def submit(self):
"""
Submit the job
"""
cmd = ['qsub', self.script]
proc = sub.Popen(cmd, stdin=sub.PIPE,stdout=sub.PIPE,stderr=sub.PIPE)
cmd = ["qsub", self.script]
proc = sub.Popen(cmd, stdin=sub.PIPE, stdout=sub.PIPE, stderr=sub.PIPE)
return proc

Loading
Loading