Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nexus: Quantum Package interface #1093

Merged
merged 15 commits into from
Oct 15, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
nexus: enable cis and fci workflows for quantum package
  • Loading branch information
jtkrogel committed Oct 11, 2018
commit 9c4dd09ae836cd78e9e5d561851c55bae2f3d91f
18 changes: 12 additions & 6 deletions nexus/library/machines.py
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,13 @@ def total_days(self):
#end def total_days


def clone(self):
job = self.copy()
job.set_id()
return job
#end def clone


def split_nodes(self,n):
run_options = self.run_options
if not isinstance(n,int):
Expand All @@ -652,10 +659,8 @@ def split_nodes(self,n):
if m.app_launcher=='srun':
self.error('splitting jobs by nodes is not currently supported on machine "{0}" (SLURM)'.format(m.name))
#end if
job1 = self.copy()
job2 = self.copy()
job1.set_id()
job2.set_id()
job1 = self.clone()
job2 = self.clone()
job1.nodes = n
job2.nodes = self.nodes - n
m.process_job(job1)
Expand Down Expand Up @@ -2257,10 +2262,11 @@ def process_job_extra(self,job):
# self.error('threads must be 1,2,3,4,6, or 12 on Cooley\nyou provided: {0}'.format(job.threads))
##end if

job.run_options.add(
#job.run_options.add(
#f = '-f $COBALT_NODEFILE',
#ppn = '-ppn {0}'.format(job.processes_per_node),
)
#)
return
#end def process_job_extra

def write_job_header(self,job):
Expand Down
92 changes: 86 additions & 6 deletions nexus/library/quantum_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class QuantumPackage(Simulation):
application_properties = set(['serial','mpi'])
application_results = set([])

allow_overlapping_files = True

qprc = None

slave_partners = obj(
Expand All @@ -60,6 +62,11 @@ def restore_default_settings():
QuantumPackage.qprc = None
#end def restore_default_settings

def pre_init(self):
prefix = self.input.run_control.prefix
self.infile = prefix + self.infile_extension
#end def pre_init


def post_init(self):
qprc = QuantumPackage.qprc
Expand All @@ -70,6 +77,20 @@ def post_init(self):
#end def post_init


def write_prep(self):
# write an ascii represenation of the input changes
infile = self.identifier+'.in'
infile = os.path.join(self.locdir,infile)
f = open(infile,'w')
s = self.input.delete_optional('structure',None)
f.write(str(self.input))
if s is not None:
self.input.structure = s
#end if
f.close()
#end def write_prep


def check_result(self,result_name,sim):
return False
#end def check_result
Expand Down Expand Up @@ -111,9 +132,58 @@ def get_slave(self):


def app_command(self):
run_type = self.input.run_control.run_type

# get run controls
input = self.input
rc = input.run_control

# make the basic app command, no splitting etc
run_type = rc.run_type
app_command = self.app_name+' '+run_type+' '+self.infile

# prepare local vars in case splitting or other tricks are needed
fc = ''
job = self.job

# add cis-loop runs if requested
if 'cis_loop' in rc:
nloop = 0
if isinstance(rc.cis_loop,bool) and rc.cis_loop:
nloop = 2
else:
nloop = rc.cis_loop
#end for
if nloop>0:
jloop = job.clone()
fc+='\n'
for n in range(nloop):
jloop.app_command = self.app_name+' cis '+self.infile
fc += jloop.run_command()+' >{0}_{1}.out 2>{0}_{1}.err\n'.format(self.identifier,n)
jloop.app_command = self.app_name+' save_natorb '+self.infile
fc += jloop.run_command()+'\n'
#end for
fc+='\n'
integrals = [
'integrals_monoelec/disk_access_ao_one_integrals',
'integrals_monoelec/disk_access_mo_one_integrals',
'integrals_bielec/disk_access_ao_integrals',
'integrals_bielec/disk_access_mo_integrals',
]
cl = ''
for integral in integrals:
isec,ivar = integral.split('/')
if input.present(ivar):
val = input.delete(ivar)
cl += 'echo "{0}" > {1}/{2}\n'.format(val,self.infile,integral)
#end if
#end for
if len(cl)>0:
fc+=cl+'\n'
#end if
#end if
#end if

# perform master-slave job splitting if necessary
slave = self.get_slave()
split_nodes = job.nodes>1 and job.full_command is None
split_nodes &= slave is not None
Expand All @@ -130,11 +200,21 @@ def app_command(self):
job1,job2 = job.split_nodes(1)
job1.app_command = app_command
job2.app_command = slave_command
s = ''
s += job1.run_command()+' >{0} 2>{1}&\n'.format(outfile,errfile)
s += 'sleep {0}\n'.format(self.input.run_control.sleep)
s += job2.run_command()+' >{0} 2>{1}\n'.format(slave_outfile,slave_errfile)
job.full_command = s
fc += job1.run_command()+' >{0} 2>{1}&\n'.format(outfile,errfile)
fc += 'sleep {0}\n'.format(self.input.run_control.sleep)
fc += job2.run_command()+' >{0} 2>{1}\n'.format(slave_outfile,slave_errfile)

if 'davidson' in slave and not input.present('distributed_davidson'):
input.set(distributed_davidson=True)
#end if
elif len(fc)>0:
job.divert_out_err()
job.app_command = app_command
fc += job.run_command()+' >{0} 2>{1}\n'.format(self.outfile,self.errfile)
#end if

if len(fc)>0:
job.full_command = fc
#end if

return app_command
Expand Down
89 changes: 86 additions & 3 deletions nexus/library/quantum_package_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,12 @@ class QuantumPackageInput(SimulationInput):
fci_zmq
'''.split())

integral_write_allowed = set('''
SCF
cis
fci_zmq
'''.split())


def __init__(self,filepath=None):
self.structure = None
Expand All @@ -366,6 +372,55 @@ def __init__(self,filepath=None):
#end def __init__


def present(self,name):
if name not in known_variables:
self.error('attempted to check presence of unknown variable "{0}"valid options are: {1}'.format(name,sorted(known_variables)))
#end if
secname = variable_section[name]
return secname in self and name in self[secname]
#end def present


def set(self,**kwargs):
for name,value in kwargs.iteritems():
if name not in known_variables:
self.error('cannot set variable\nattempted to set unknown variable "{0}"\nwith value: {1}\nvalid options are: {2}'.format(name,value,sorted(known_variables)))
#end if
secname = variable_section[name]
if secname not in self:
self[secname] = Section()
#end if
self[secname][name] = value
#end for
#end def set


def get(self,name):
if name not in known_variables:
self.error('cannot get variable\nattempted to get unknown variable "{0}"\nvalid options are: {1}'.format(name,sorted(known_variables)))
#end if
value = None
secname = variable_section[name]
if secname in self and name in self[secname]:
value = self[secname][name]
#end if
return value
#end def get


def delete(self,name):
if name not in known_variables:
self.error('cannot get variable\nattempted to get unknown variable "{0}"\nvalid options are: {1}'.format(name,sorted(known_variables)))
#end if
value = None
secname = variable_section[name]
if secname in self and name in self[secname]:
value = self[secname].delete(name)
#end if
return value
#end def delete


def extract_added_keys(self):
extra = obj()
extra.move_from(self,QuantumPackageInput.added_keys)
Expand Down Expand Up @@ -410,7 +465,11 @@ def write(self,filepath=None):
if filepath is None:
return str(self)
#end if

# get the ezfio path
epath = filepath.rstrip('/')

# check that write can occur
if not epath.endswith('.ezfio'):
self.error('cannot write input\nprovided path does not end in an ezfio directory\ndirectory must end with .ezfio\npath provided: {0}'.format(epath))
#end if
Expand All @@ -421,6 +480,8 @@ def write(self,filepath=None):
if not os.path.exists(path):
self.error('cannot write input\nattempted to write ezfio directory "{0}" at non-existent destination path\ndestination path: {1}'.format(edir,path))
#end if

# if there is no ezfio directory, initialize one
if not os.path.exists(epath):
if self.structure is None:
self.error('cannot write input\nstructure is missing\ninput path provided: {0}'.format(epath))
Expand All @@ -444,6 +505,8 @@ def write(self,filepath=None):
execute('qp_edit -c '+edir)
os.chdir(cwd)
#end if

# write inputs into the ezfio directory/file tree
extra = self.extract_added_keys()
for secname,sec in self.iteritems():
secpath = os.path.join(epath,secname)
Expand All @@ -456,6 +519,18 @@ def write(self,filepath=None):
#end for
#end for
self.restore_added_keys(extra)

# take other steps that modify the input, as requested
if 'run_control' in self:
rc = self.run_control
if 'frozen_core' in rc and rc.frozen_core:
cwd = os.getcwd()
os.chdir(path)
execute('qp_set_frozen_core.py '+edir)
os.chdir(cwd)
#end if
#end if

return ''
#end def write

Expand Down Expand Up @@ -540,7 +615,10 @@ def is_valid(self):


run_inputs = set('''
prefix
run_type
frozen_core
cis_loop
sleep
slave
postprocess
Expand All @@ -554,7 +632,10 @@ def is_valid(self):
added_inputs = run_inputs | gen_inputs
added_types = obj(
# run inputs
prefix = str,
run_type = str,
frozen_core = bool,
cis_loop = (bool,int),
sleep = (int,float),
slave = str,
postprocess = (tuple,list),
Expand All @@ -566,6 +647,7 @@ def is_valid(self):
)
added_required = set('''
system
prefix
sleep
'''.split())
qp_defaults_version = 'v1'
Expand Down Expand Up @@ -610,9 +692,6 @@ def generate_quantum_package_input(**kwargs):
QuantumPackageInput.class_error('cannot generate input\nrequested invalid default set\ndefault set requested: {0}\nvalid options are: {1}'.format(kw.defaults,sorted(qp_defaults.keys())))
#end if
kw.set_optional(**qp_defaults[kw.defaults])
if kw.save_integrals:
kw.set_optional(**save_ints_defaults)
#end if

# check for required variables
req_missing = kw.check_required(added_required,exit=False)
Expand Down Expand Up @@ -640,6 +719,10 @@ def generate_quantum_package_input(**kwargs):
# separate generation inputs from input file variables
gen_kw = kw.extract_optional(gen_inputs)

if gen_kw.save_integrals and run_kw.run_type in QuantumPackageInput.integral_write_allowed:
kw.set_optional(**save_ints_defaults)
#end if

# partition inputs into sections and variables
sections = obj()
variables = obj()
Expand Down
7 changes: 6 additions & 1 deletion nexus/library/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ def __init__(self,**kwargs):
# accessed by dependents when calling get_dependencies

self.set(**kwargs)
self.pre_init()
self.set_directories()
self.set_files()
self.propagate_identifier()
Expand Down Expand Up @@ -610,6 +611,10 @@ def propagate_identifier(self):
None
#end def propagate_identifier

def pre_init(self):
None
#end def pre_init

def post_init(self):
None
#end def post_init
Expand Down Expand Up @@ -947,7 +952,7 @@ def write_inputs(self,save_image=True):
self.enter(self.locdir,False,self.simid)
self.log('writing input files'+self.idstr(),n=3)
self.write_prep()
if self.infile!=None:
if self.infile is not None:
infile = os.path.join(self.locdir,self.infile)
self.input.write(infile)
#end if
Expand Down