mirror of https://github.com/QMCPACK/qmcpack.git
355 lines
13 KiB
Python
355 lines
13 KiB
Python
##################################################################
|
|
## (c) Copyright 2015- by Jaron T. Krogel ##
|
|
##################################################################
|
|
|
|
|
|
#====================================================================#
|
|
# template_simulation.py #
|
|
# Instructions and code templates for developers seeking to #
|
|
# interface a new simulation code with Nexus. #
|
|
# #
|
|
# Content summary: #
|
|
# TemplateSimulationInput #
|
|
# Code template for a SimulationInput class. #
|
|
# #
|
|
# generate_template_simulation_input #
|
|
# Code template for user-facing simulation input generator #
|
|
# function. #
|
|
# #
|
|
# TemplateSimulationAnalyzer #
|
|
# Code template for a SimulationAnalyzer class. #
|
|
# #
|
|
# TemplateSimulation #
|
|
# Code template for a Simulation class. #
|
|
# #
|
|
# generate_template_simulation #
|
|
# Code template for user-facing simulation generator function. #
|
|
# #
|
|
#====================================================================#
|
|
|
|
|
|
import os
|
|
from generic import obj
|
|
from simulation import Simulation,SimulationInput,SimulationAnalyzer
|
|
|
|
|
|
# PLEASE READ THIS
|
|
#
|
|
# depending on what you want to do with a simulation
|
|
# you will have to implement different functions below
|
|
# here are a few use cases and the functions required
|
|
# details about each function are given within the classes
|
|
#
|
|
# use cases
|
|
# 1) standalone simulation
|
|
# nexus drives this simulation in isolation of others
|
|
# i.e., one performs parameter scans to drive several independent template_simulation runs
|
|
# in this setting, a template_simulation simulation does not provide information to
|
|
# other simulations (e.g. orbitals to qmcpack) and does not accept
|
|
# information from prior simulations (e.g. structure from pwscf or template_simulation)
|
|
#
|
|
# the input file will be read from a template file
|
|
# and modified to obtain the desired inputs
|
|
# one could also provide the input longhand in python
|
|
# in a form TemplateSimulationInput understands (this depends on your implementation)
|
|
#
|
|
# required functions to be implemented:
|
|
# TemplateSimulationInput: read_text, write_text
|
|
# TemplateSimulation: app_command, check_sim_status
|
|
#
|
|
# 2) generated standalone simulation
|
|
# as above, but with fully generated input files
|
|
# generate functions provide a short-hand of minimal vars for input
|
|
# structure information for the input is extracted from
|
|
# a standard PhysicalSystem object
|
|
#
|
|
# required functions to be implemented:
|
|
# TemplateSimulationInput: read_text, write_text, incorporate_system
|
|
# TemplateSimulation: app_command, check_sim_status
|
|
# generate_template_simulation_input
|
|
#
|
|
# 3) simulation that provides information to subsequent chained simulations
|
|
# as above (with or without #2)
|
|
# other simulations can request and get information about
|
|
# results produced by this simulation
|
|
# (e.g. relaxed structure data, location of orbital files, etc.)
|
|
# this information is used by the others to populate input files
|
|
#
|
|
# required functions to be implemented:
|
|
# TemplateSimulationInput: read_text, write_text
|
|
# TemplateSimulation: app_command,check_sim_status,
|
|
# check_result, get_result
|
|
#
|
|
# if required to get needed output information:
|
|
# TemplateSimulationAnalyzer: analyze
|
|
#
|
|
# 3) simulation that provides/receives info to/from other simulations
|
|
# as above (with or without #2)
|
|
# this simulation can request info from other sims
|
|
# info is used to populate own input file
|
|
#
|
|
# required functions to be implemented:
|
|
# TemplateSimulationInput: read_text, write_text
|
|
# TemplateSimulation: app_command,check_sim_status,
|
|
# check_result, get_result,
|
|
# incorporate_result
|
|
#
|
|
# if required to get needed output information:
|
|
# TemplateSimulationAnalyzer: analyze
|
|
#
|
|
|
|
|
|
|
|
class TemplateSimulationInput(SimulationInput):
|
|
def __init__(self,filepath=None):
|
|
# optional
|
|
# below is a convenient default
|
|
# but it can be changed to anything desired
|
|
if filepath!=None:
|
|
self.read(filepath)
|
|
#end if
|
|
#end def __init__
|
|
|
|
|
|
def read_text(self,text,filepath=None):
|
|
# required
|
|
# the string 'text' contains the text of an input file
|
|
# translate text into an internal representation of the input
|
|
# for example, an input file looking like:
|
|
# section_a
|
|
# var_a 1
|
|
# var_b word
|
|
# section_b
|
|
# var_c 1e4
|
|
# var_d T
|
|
# might be translated into:
|
|
# sec = obj()
|
|
# sec['var_a'] = 1
|
|
# sec['var_b'] = 'word'
|
|
# self['section_a'] = sec
|
|
# sec = obj()
|
|
# sec['var_c'] = 1e4
|
|
# sec['var_d'] = True
|
|
# self['section_b'] = sec
|
|
# with some line parsing:
|
|
# for line in text.splitlines():
|
|
# # parse lines here
|
|
# #end for
|
|
# the resulting input object can then be worked with in a simple way:
|
|
# >>> input = DemoInput()
|
|
# >>> input
|
|
# section_a obj
|
|
# section_b obj
|
|
#
|
|
# >>> print input
|
|
# section_a
|
|
# var_a = 1
|
|
# var_b = word
|
|
# end section_a
|
|
# section_b
|
|
# var_c = 10000.0
|
|
# var_d = True
|
|
# end section_b
|
|
#
|
|
# >>> input.section_b.var_c = 25.0
|
|
None
|
|
#end def read_text
|
|
|
|
|
|
def write_text(self,filepath=None):
|
|
# required
|
|
# translate the internal representation of input into a string
|
|
# for the above example, this might look like:
|
|
# text = ''
|
|
# for secname,sec in self.items():
|
|
# text += secname+'\n'
|
|
# for val,val in sec.items():
|
|
# text += ' '+var+' = '+val2str(val)
|
|
# #end for
|
|
# #end for
|
|
text = ''
|
|
return text
|
|
#end def write_text
|
|
|
|
|
|
def incorporate_system(self,system):
|
|
# optional
|
|
# only necessary if you want to populate atomic positions, etc
|
|
# from a PhysicalSystem object
|
|
# if you don't want to implement it, no action is required
|
|
self.not_implemented()
|
|
#end def incorporate_system
|
|
#end class TemplateSimulationInput
|
|
|
|
|
|
|
|
def generate_template_simulation_input(
|
|
# probably lots of keyword arguments
|
|
# kw1 = default_val1,
|
|
# kw2 = default_val2,
|
|
# system = None,
|
|
# ...
|
|
):
|
|
# optional
|
|
# only necessary if you want to make template_simulation input files
|
|
# with the fewest relevant variables
|
|
# if you don't want to implement it, uncomment the following line
|
|
#exit()
|
|
|
|
gi = TemplateSimulationInput()
|
|
|
|
# use keyword inputs to complete template_simulation input
|
|
|
|
# a common feature is to read information from a PhysicalSystem object
|
|
# (#electrons, atom positions, etc)
|
|
# if system!=None
|
|
# gi.incorporate_system(system)
|
|
# #end if
|
|
|
|
return gi
|
|
#end def generate_template_simulation_input
|
|
|
|
|
|
|
|
class TemplateSimulationAnalyzer(SimulationAnalyzer):
|
|
def __init__(self,arg0=None):
|
|
# optional
|
|
# only necessary if you want to use results from output files
|
|
# to inform the inputs of subsequent simulations
|
|
# or if you want to have a general purpose class to scrape
|
|
# and process simulation data
|
|
# below is a reasonable default implementation
|
|
# if you don't want to implement it, just uncomment the following line
|
|
#return
|
|
|
|
self.path = None
|
|
self.input = None
|
|
infile = None
|
|
if isinstance(arg0,Simulation):
|
|
sim = arg0
|
|
infile = os.path.join(sim.locdir,sim.infile)
|
|
else:
|
|
infile = arg0
|
|
#end if
|
|
if infile!=None:
|
|
self.path = os.path.dirname(infile)
|
|
self.input = TemplateSimulationInput(infile)
|
|
#end if
|
|
#end def __init__
|
|
|
|
|
|
def analyze(self):
|
|
# optional
|
|
# only necessary if you want to use results from output files
|
|
# to inform the inputs of subsequent simulations
|
|
# or if you want to have a general purpose class to scrape
|
|
# and process simulation data
|
|
# if you don't want to implement it, no action is required
|
|
None
|
|
#end def analyze
|
|
#end class TemplateSimulationAnalyzer
|
|
|
|
|
|
|
|
class TemplateSimulation(Simulation):
|
|
input_type = TemplateSimulationInput
|
|
analyzer_type = TemplateSimulationAnalyzer
|
|
generic_identifier = 'template_simulation'
|
|
application = 'template_simulation_exe' #replace with default name of template_simulation executable
|
|
application_properties = set(['serial','mpi'])
|
|
application_results = set(['orbitals']) #what template_simulation produces that other simulations can use
|
|
|
|
def check_result(self,result_name,sim):
|
|
# optional
|
|
# only necessary if another simulation depends on this one
|
|
# e.g.
|
|
# other_sim.depends(template_simulation_sim,'orbitals') or similar
|
|
# if you don't want to implement it, uncomment the line below
|
|
#return False
|
|
calculating_result = False
|
|
input = self.input # a TemplateSimulationInput object
|
|
# check the input to see if result is being calculated
|
|
# (e.g. result_name='orbitals')
|
|
return calculating_result
|
|
#end def check_result
|
|
|
|
|
|
def get_result(self,result_name,sim):
|
|
# optional
|
|
# only necessary if another simulation depends on this one
|
|
# e.g.
|
|
# other_sim.depends(template_simulation_sim,'orbitals') or similar
|
|
# if you don't want to implement it, uncomment the line below
|
|
#self.not_implemented()
|
|
|
|
result = obj()
|
|
input = self.input
|
|
#analyzer = self.load_analyzer_image()
|
|
|
|
# package information about a result/product in the result object
|
|
# for example, if orbitals are requested,
|
|
# the path to the orbital file might be provided:
|
|
# result.orbital_file = '/path/to/orbital/file'
|
|
return result
|
|
#end def get_result
|
|
|
|
|
|
def incorporate_result(self,result_name,result,sim):
|
|
# optional
|
|
# only necessary if this template_simulation sim depends on another sim
|
|
# e.g.
|
|
# template_simulation_sim.depends(other_sim,'structure') or similar
|
|
# if you don't want to implement it no action is required
|
|
self.not_implemented()
|
|
#end def incorporate_result
|
|
|
|
|
|
def app_command(self):
|
|
# required
|
|
# specify command line arguments to the executable, such as the input file
|
|
# e.g. command_line_args = ' '+self.infile
|
|
command_line_args = ''
|
|
return self.app_name + command_line_args
|
|
#end def app_command
|
|
|
|
|
|
def check_sim_status(self):
|
|
# required
|
|
# read output/error files to check whether simulation has
|
|
# completed successfully
|
|
# one could also check whether all output files exist
|
|
output = open(os.path.join(self.locdir,self.outfile),'r').read()
|
|
errors = open(os.path.join(self.locdir,self.errfile),'r').read()
|
|
|
|
success = False
|
|
# check output and errors
|
|
# set success=True if run completed successfully
|
|
|
|
self.finished = success and self.job.finished
|
|
#end def check_sim_status
|
|
|
|
|
|
def get_output_files(self):
|
|
# optional
|
|
# if provided, the listed output files will be copied to the results directory
|
|
# if you don't want to implement it, no action is required
|
|
output_files = []
|
|
return output_files
|
|
#end def get_output_files
|
|
#end class TemplateSimulation
|
|
|
|
|
|
|
|
def generate_template_simulation(**kwargs):
|
|
# optional
|
|
# the following code should work provided
|
|
# generate_template_simulation_input is suitably defined
|
|
sim_args,inp_args = Simulation.separate_inputs(kwargs)
|
|
|
|
sim_args.input = generate_template_simulation_input(**inp_args)
|
|
|
|
template_simulation = TemplateSimulation(**sim_args)
|
|
|
|
return template_simulation
|
|
#end def generate_template_simulation
|