1################################################################## 2## (c) Copyright 2015- by Jaron T. Krogel ## 3################################################################## 4 5 6#====================================================================# 7# gamess.py # 8# Nexus interface to the GAMESS simulation code. # 9# # 10# Content summary: # 11# GamessInput # 12# Input class for the GAMESS code. # 13# Capable of reading/writing arbitrary GAMESS input files. # 14# # 15# generate_gamess_input # 16# User function to create arbitrary GAMESS input. # 17# # 18# KeywordGroup # 19# Represents an arbitrary keyword group in the input file. # 20# # 21# KeywordSpecGroup # 22# Base class for specialized keyword groups. # 23# Derived classes enforce the keyword specification. # 24# See ContrlGroup, SystemGroup, GuessGroup, ScfGroup, # 25# McscfGroup, DftGroup, GugdiaGroup, DrtGroup, CidrtGroup, # 26# and DetGroup # 27# # 28# FormattedGroup # 29# Represents strict machine-formatted input groups. # 30# # 31#====================================================================# 32 33 34import os 35import numpy as np 36from numpy import array,ndarray,abs 37from generic import obj 38from developer import DevBase 39from debug import * 40from simulation import Simulation 41from gamess_input import GamessInput,generate_gamess_input,FormattedGroup,KeywordGroup,GuessGroup,GIarray 42from gamess_analyzer import GamessAnalyzer 43 44 45 46class Gamess(Simulation): 47 input_type = GamessInput 48 analyzer_type = GamessAnalyzer 49 generic_identifier = 'gamess' 50 application = 'gamess.x' 51 infile_extension = '.inp' 52 application_properties = set(['serial','mpi']) 53 application_results = set(['orbitals']) 54 55 ericfmt = None 56 mcppath = None 57 58 @staticmethod 59 def settings(ericfmt=None,mcppath=None): 60 Gamess.ericfmt = ericfmt 61 Gamess.mcppath = mcppath 62 #end def settings 63 64 @staticmethod 65 def restore_default_settings(): 66 Gamess.ericfmt = None 67 Gamess.mcppath = None 68 #end def restore_default_settings 69 70 71 def __init__(self,**kwargs): 72 self.mo_reorder = None 73 mo_reorder = kwargs.pop('mo_reorder',None) 74 if mo_reorder is not None: 75 self.mo_reorder = [s.lower() for s in mo_reorder] 76 #end if 77 Simulation.__init__(self,**kwargs) 78 #end def __init__ 79 80 81 def init_job_extra(self): 82 # gamess seems to need lots of environment variables to run properly 83 # nearly all of these are names of output/work files 84 # setup the environment to run gamess 85 if not isinstance(self.ericfmt,str): 86 self.error('you must set ericfmt with settings() or Gamess.settings()') 87 #end if 88 env = obj() 89 for file,unit in GamessInput.file_units.items(): 90 env[file] = '{0}.F{1}'.format(self.identifier,str(unit).zfill(2)) 91 #end for 92 env.INPUT = self.infile 93 env.ERICFMT = self.ericfmt 94 env.MCPPATH = self.mcppath 95 self.job.set_environment(**env) 96 #end def init_job_extra 97 98 99 def check_result(self,result_name,sim): 100 input = self.input 101 if result_name=='orbitals': 102 calculating_result = 'contrl' in input and 'scftyp' in input.contrl and input.contrl.scftyp.lower() in ('rhf','rohf','uhf','mcscf','none') 103 else: 104 calculating_result = False 105 #end if 106 return calculating_result 107 #end def check_result 108 109 110 def get_result(self,result_name,sim): 111 result = obj() 112 input = self.input 113 analyzer = self.load_analyzer_image() 114 if result_name=='orbitals': 115 result.location = os.path.join(self.locdir,self.outfile) 116 result.outfile = result.location 117 result.vec = None # vec from punch 118 result.norbitals = 0 # orbital count in punch 119 result.mos = 0 # orbital count (MO's) from log file 120 result.scftyp = input.contrl.scftyp.lower() 121 if 'counts' in analyzer and 'mos' in analyzer.counts: 122 result.mos = analyzer.counts.mos 123 #end if 124 if 'punch' in analyzer and 'vec' in analyzer.punch: 125 result.norbitals = analyzer.punch.norbitals 126 result.vec = analyzer.punch.vec 127 #end if 128 if 'orbitals' in analyzer: 129 result.orbitals = analyzer.orbitals 130 #end if 131 else: 132 self.error('ability to get result '+result_name+' has not been implemented') 133 #end if 134 return result 135 #end def get_result 136 137 138 def incorporate_result(self,result_name,result,sim): 139 input = self.input 140 if result_name=='orbitals': 141 if result.vec is None or result.norbitals<1: 142 self.error('could not obtain orbitals from previous GAMESS run') 143 #end if 144 if not 'guess' in input: 145 input.guess = GuessGroup() 146 #end if 147 if 'norb' in input.guess: # user provided norb 148 norb = input.guess.norb 149 else: 150 norb = result.norbitals 151 #end if 152 if 'norder' not in input.guess: 153 input.guess.clear() 154 #end if 155 if self.mo_reorder is not None: 156 if 'orbitals' not in result: 157 self.error('Orbital information from prior calculation "{}" located at {} cannot be found. You requested orbital reordering via the "mo_reorder" input keyword. Due to missing information, this operation cannot be performed. The current simulation "{}" is located at {}.'.format(sim.identifier,sim.locdir,self.identifier,self.locdir)) 158 self.block() 159 #end if 160 guess_inputs = obj() 161 ecounts = self.system.particles.electron_counts() 162 orbs = result.orbitals 163 order_map = obj(up='iorder',down='jorder') 164 nelec_map = obj(up=ecounts[0],down=ecounts[1]) 165 for spin,vname in order_map.items(): 166 nelec = nelec_map[spin] 167 if len(self.mo_reorder)<nelec: 168 self.error('Too few symmetries provided in "mo_reorder" for spin "{0}".\nNumber of electrons with spin "{0}": {1}\nNumber of entries in "mo_reorder": {2}\nContents of "mo_reorder": {3}\nSimulation identifier: {4}\nSimulation location: {5}'.format(spin,nelec,len(self.mo_reorder),self.mo_reorder,self.identifier,self.locdir)) 169 #end if 170 symmetries = [s.lower() for s in orbs[spin].symmetry] 171 missing = set(self.mo_reorder)-set(symmetries) 172 if len(missing)>0: 173 self.error('Symmetries provided by "mo_reorder" keyword are not found in the outputted MOs.\nSet of symmetries provided in "mo_reorder": {}\nSet of symmetries present in MOs: {}\nContents of "mo_reorder": {}\nSimulation identifier: {}\nSimulation location: {}'.format(sorted(set(self.mo_reorder)),sorted(set(symmetries)),self.mo_reorder,self.identifier,self.locdir)) 174 #end if 175 occ = np.zeros(len(symmetries),dtype=bool) 176 for symm in self.mo_reorder[:nelec]: 177 for i,(s,o) in enumerate(zip(symmetries,occ)): 178 if not o and symm==s: 179 occ[i] = True 180 break 181 #end if 182 #end for 183 #end for 184 if occ.sum()<nelec: 185 self.error('Too few orbitals occupied based on "mo_reorder" request.\nNumber of orbitals occupied: {}\nNumber of spin "{}" electrons: {}\nContents of "mo_reorder": {}\nSimulation identifier: {}\nSimulation location: {}'.format(occ.sum(),spin,nelec,self.mo_reorder,self.identifier,self.locdir)) 186 #end if 187 indices = np.arange(len(symmetries),dtype=int)[occ]+1 188 start = 0 189 found = False 190 for i in range(len(indices)): 191 start = i 192 if indices[i]!=i+1: 193 found = True 194 break 195 #end if 196 #end if 197 if found: 198 reduced_indices = indices[start:] 199 start+=1 200 else: 201 reduced_indices = [] 202 #end if 203 if len(reduced_indices)>0: 204 guess_inputs.norder = 1 205 guess_inputs[vname] = GIarray({start:reduced_indices}) 206 #end if 207 #end for 208 input.guess.set(**guess_inputs) 209 #end if 210 input.guess.set( 211 guess = 'moread', 212 norb = norb, 213 prtmo = True, 214 ) 215 input.vec = FormattedGroup(result.vec) 216 else: 217 self.error('ability to incorporate result '+result_name+' has not been implemented') 218 #end if 219 #end def incorporate_result 220 221 222 def app_command(self): 223 if self.app_name == 'rungms': 224 return 'rungms '+self.infile 225 else: 226 return self.app_name+' '+self.infile.replace('.inp','') 227 #end if 228 #end def app_command 229 230 231 def check_sim_status(self): 232 output = open(os.path.join(self.locdir,self.outfile),'r').read() 233 #errors = open(os.path.join(self.locdir,self.errfile),'r').read() 234 235 self.failed = 'EXECUTION OF GAMESS TERMINATED -ABNORMALLY-' in output 236 self.finished = self.failed or 'EXECUTION OF GAMESS TERMINATED NORMALLY' in output 237 #end def check_sim_status 238 239 240 def get_output_files(self): 241 output_files = [] 242 return output_files 243 #end def get_output_files 244 245 246 def output_filename(self,name): 247 name = name.upper() 248 if name not in GamessInput.file_units: 249 self.error('gamess does not produce a file matching the requested description: {0}'.format(name)) 250 #end if 251 unit = GamessInput.file_units[name] 252 filename = '{0}.F{1}'.format(self.identifier,str(unit).zfill(2)) 253 return filename 254 #end def output_filename 255 256 257 def output_filepath(self,name): 258 filename = self.output_filename(name) 259 filepath = os.path.join(self.locdir,filename) 260 filepath = os.path.abspath(filepath) 261 return filepath 262 #end def 263#end class Gamess 264 265 266 267def generate_gamess(**kwargs): 268 sim_args,inp_args = Gamess.separate_inputs(kwargs,copy_pseudos=False,sim_kw=['mo_reorder']) 269 270 if not 'input' in sim_args: 271 sim_args.input = generate_gamess_input(**inp_args) 272 #end if 273 gamess = Gamess(**sim_args) 274 275 return gamess 276#end def generate_gamess 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291