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