1##################################################################
2##  (c) Copyright 2015-  by Jaron T. Krogel                     ##
3##################################################################
4
5
6#====================================================================#
7#  qmcpack_converters.py                                             #
8#    Nexus interfaces for orbital converter tools of QMCPACK:        #
9#    pw2qmcpack and convert4qmc                                      #
10#                                                                    #
11#  Content summary:                                                  #
12#    generate_pw2qmcpack                                             #
13#      User-facing function to create pw2qmcpack simulation objects. #
14#                                                                    #
15#    generate_pw2qmcpack_input                                       #
16#      User-facing funcion to create input for pw2qmcpack.           #
17#                                                                    #
18#    Pw2qmcpack                                                      #
19#      Simulation class for pw2qmcpack.                              #
20#                                                                    #
21#    Pw2qmcpackInput                                                 #
22#      SimulationInput class for pw2qmcpack.                         #
23#                                                                    #
24#    Pw2qmcpackAnalyzer                                              #
25#      SimulationAnalyzer class for pw2qmcpack.                      #
26#                                                                    #
27#                                                                    #
28#    Convert4qmcInput                                                #
29#      Class representing command line interface of convert4qmc.     #
30#                                                                    #
31#    Convert4qmcAnalyzer                                             #
32#      Placeholder class for output analysis.                        #
33#                                                                    #
34#    Convert4qmc                                                     #
35#      Class representing convert4qmc instance.                      #
36#                                                                    #
37#    generate_convert4qmc_input                                      #
38#      Function to generate arbitrary convert4qmc input.             #
39#                                                                    #
40#    generate_convert4qmc                                            #
41#      Function to generate Convert4qmc simulation object.           #
42#                                                                    #
43#====================================================================#
44
45
46
47import os
48from generic import obj
49from simulation import Simulation,SimulationInput,SimulationAnalyzer
50from pwscf import Pwscf
51from gamess import Gamess
52from pyscf_sim import Pyscf
53from quantum_package import QuantumPackage
54
55
56# read/write functions associated with pw2qmcpack only
57def read_str(sv):
58    return sv.strip('"').strip("'")
59#end def read_str
60
61def read_int(sv):
62    return int(sv)
63#end def read_int
64
65def read_float(sv):
66    return float(sv.replace('d','e').replace('D','e'))
67#end def read_float
68
69bconv = {'.true.':True,'.false.':False}
70def read_bool(sv):
71    return bconv[sv]
72#end def read_bool
73
74def write_str(val):
75    return "'"+val+"'"
76#end def write_str
77
78def write_int(val):
79    return str(val)
80#end def write_int
81
82def write_float(val):
83    return str(val)
84#end def write_float
85
86def write_bool(val):
87    return '.'+str(val).lower()+'.'
88#end def write_bool
89
90readval={str:read_str,int:read_int,float:read_float,bool:read_bool}
91writeval={str:write_str,int:write_int,float:write_float,bool:write_bool}
92
93
94class Pw2qmcpackInput(SimulationInput):
95    ints   = []
96    floats = []
97    strs   = ['outdir','prefix']
98    bools  = ['write_psir']
99
100    var_types = dict()
101    for v in ints:
102        var_types[v]=int
103    #end for
104    for v in floats:
105        var_types[v]=float
106    #end for
107    for v in strs:
108        var_types[v]=str
109    #end for
110    for v in bools:
111        var_types[v]=bool
112    #end for
113
114    allowed = set(ints+floats+strs+bools)
115
116    def read_text(self,contents,filepath=None):
117        lines = contents.split('\n')
118        inside = False
119        for l in lines:
120            if inside:
121                tokens = l.split(',')
122                for t in tokens:
123                    ts = t.strip()
124                    if ts!='' and ts!='/':
125                        name,value = ts.split('=')
126                        name = name.strip()
127                        value= value.strip()
128                        if name in self.allowed:
129                            vtype = self.var_types[name]
130                            value = readval[vtype](value)
131                            sobj[name]=value
132                        else:
133                            self.error('encountered unknown variable: '+name)
134                        #end if
135                    #end if
136                #end for
137            #end if
138            if '&' in l:
139                inside=True
140                section = l.lstrip('&').lower()
141                sobj = obj()
142                self[section]=sobj
143            elif l.strip()=='/':
144                inside=False
145            #end if
146        #end for
147    #end def read_text
148
149
150    def write_text(self,filepath=None):
151        contents = ''
152        for sname,section in self.items():
153            contents+='&'+sname+'\n'
154            for name,value in section.items():
155                vtype = type(value)
156                contents += '  '+name+' = '+writeval[vtype](value)+'\n'
157            #end for
158            contents+='/\n'
159        #end for
160        return contents
161    #end def write_text
162
163
164    def __init__(self,filepath=None,**vars):
165        if filepath!=None:
166            self.read(filepath)
167        else:
168            inputpp = obj()
169            for name,value in vars.items():
170                inputpp[name] = value
171            #end for
172            self.inputpp = inputpp
173        #end if
174    #end def __init__
175#end class Pw2qmcpackInput
176
177
178def generate_pw2qmcpack_input(prefix='pwscf',outdir='pwscf_output',write_psir=False):
179    pw = Pw2qmcpackInput(
180        prefix     = prefix,
181        outdir     = outdir,
182        write_psir = write_psir
183        )
184    return pw
185#end def generate_pw2qmcpack_input
186
187
188
189class Pw2qmcpackAnalyzer(SimulationAnalyzer):
190    def __init__(self,arg0):
191        if isinstance(arg0,Simulation):
192            sim = arg0
193            self.infile = sim.infile
194            prefix,outdir = sim.input.inputpp.tuple('prefix','outdir')
195            self.dir = sim.locdir
196            self.h5file = os.path.join(sim.locdir,outdir,prefix+'.pwscf.h5')
197        else:
198            self.infile = arg0
199        #end if
200    #end def __init__
201
202    def analyze(self):
203        None
204    #end def analyze
205
206    def get_result(self,result_name):
207        self.not_implemented()
208    #end def get_result
209#end class Pw2qmcpackAnalyzer
210
211
212class Pw2qmcpack(Simulation):
213    input_type = Pw2qmcpackInput
214    analyzer_type = Pw2qmcpackAnalyzer
215    generic_identifier = 'pw2qmcpack'
216    application = 'pw2qmcpack.x'
217    application_properties = set(['serial'])
218    application_results    = set(['orbitals'])
219
220    def check_result(self,result_name,sim):
221        calculating_result = False
222        if result_name=='orbitals':
223            calculating_result = True
224        #end if
225        return calculating_result
226    #end def check_result
227
228
229    def get_result(self,result_name,sim):
230        result = obj()
231        inputpp = self.input.inputpp
232        prefix = 'pwscf'
233        outdir = './'
234        if 'prefix' in inputpp:
235            prefix = inputpp.prefix
236        #end if
237        if 'outdir' in inputpp:
238            outdir = inputpp.outdir
239        #end if
240        if outdir.startswith('./'):
241            outdir = outdir[2:]
242        #end if
243        if result_name=='orbitals':
244            result.h5file   = os.path.join(self.locdir,outdir,prefix+'.pwscf.h5')
245            result.ptcl_xml = os.path.join(self.locdir,outdir,prefix+'.ptcl.xml')
246            result.wfs_xml  = os.path.join(self.locdir,outdir,prefix+'.wfs.xml')
247        else:
248            self.error('ability to get result '+result_name+' has not been implemented')
249        #end if
250        return result
251    #end def get_result
252
253
254    def incorporate_result(self,result_name,result,sim):
255        implemented = True
256        if result_name=='orbitals':
257            if isinstance(sim,Pwscf):
258                pwin = sim.input.control
259                p2in = self.input.inputpp
260                pwprefix = 'pwscf'
261                p2prefix = 'pwscf'
262                pwoutdir = './'
263                p2outdir = './'
264                if 'prefix' in pwin:
265                    pwprefix = pwin.prefix
266                #end if
267                if 'prefix' in p2in:
268                    p2prefix = p2in.prefix
269                #end if
270                if 'outdir' in pwin:
271                    pwoutdir = pwin.outdir
272                #end if
273                if 'outdir' in p2in:
274                    p2outdir = p2in.outdir
275                #end if
276                if pwoutdir.startswith('./'):
277                    pwoutdir = pwoutdir[2:]
278                #end if
279                if p2outdir.startswith('./'):
280                    p2outdir = p2outdir[2:]
281                #end if
282                pwdir = os.path.abspath(os.path.join(sim.locdir ,pwoutdir))
283                p2dir = os.path.abspath(os.path.join(self.locdir,p2outdir))
284                errors = False
285                if pwdir!=p2dir:
286                    self.error('to use orbitals, '+self.generic_identifier+' must have the same outdir as pwscf\n  pwscf outdir: '+pwdir+'\n  '+self.generic_identifier+' outdir: '+p2dir,exit=False)
287                    errors = True
288                #end if
289                if pwprefix!=p2prefix:
290                    self.error('to use orbitals, '+self.generic_identifier+' must have the same prefix as pwscf\n  pwscf prefix: '+pwprefix+'\n  '+self.generic_identifier+' prefix: '+p2prefix,exit=False)
291                    errors = True
292                #end if
293                if errors:
294                    self.error(self.generic_identifier+' cannot use orbitals from pwscf')
295                #end if
296            else:
297                implemented = False
298            #end if
299        else:
300            implemented = False
301        #end if
302        if not implemented:
303            self.error('ability to incorporate result "{0}" from {1} has not been implemented'.format(result_name,sim.__class__.__name__))
304        #end if
305    #end def incorporate_result
306
307
308    def check_sim_status(self):
309        outfile = os.path.join(self.locdir,self.outfile)
310        fobj = open(outfile,'r')
311        output = fobj.read()
312        fobj.close()
313        inputpp = self.input.inputpp
314        prefix = 'pwscf'
315        outdir = './'
316        if 'prefix' in inputpp:
317            prefix = inputpp.prefix
318        #end if
319        if 'outdir' in inputpp:
320            outdir = inputpp.outdir
321        #end if
322        if outdir.startswith('./'):
323            outdir = outdir[2:]
324        #end if
325        h5file   = os.path.join(self.locdir,outdir,prefix+'.pwscf.h5')
326        ptcl_xml = os.path.join(self.locdir,outdir,prefix+'.ptcl.xml')
327        wfs_xml  = os.path.join(self.locdir,outdir,prefix+'.wfs.xml')
328        must_exist = [h5file,ptcl_xml,wfs_xml]
329
330        files_exist = True
331        for file in must_exist:
332            files_exist = files_exist and os.path.exists(file)
333        #end for
334        outfin = True
335        #outfin = outfin and 'esh5 create' in output
336        #outfin = outfin and 'Creating electrons' in output
337        outfin = outfin and 'npw=' in output
338        outfin = outfin and 'ik=' in output
339
340        outfin = outfin or 'JOB DONE' in output
341
342        success = files_exist and outfin
343
344        #self.finished = success and self.job.finished
345
346        # pw2qmcpack has too many variants to assess completion based on log output
347        #   assume (optimistically) that job completion indicates success
348        self.finished = files_exist and self.job.finished
349    #end def check_sim_status
350
351
352    def get_output_files(self):
353        output_files = []
354        return output_files
355    #end def get_output_files
356
357
358    def app_command(self):
359        return self.app_name+'<'+self.infile
360    #end def app_command
361#end class Pw2qmcpack
362
363
364
365
366def generate_pw2qmcpack(**kwargs):
367    sim_args,inp_args = Simulation.separate_inputs(kwargs)
368
369    if not 'input' in sim_args:
370        sim_args.input = generate_pw2qmcpack_input(**inp_args)
371    #end if
372    pw2qmcpack = Pw2qmcpack(**sim_args)
373
374    return pw2qmcpack
375#end def generate_pw2qmcpack
376
377
378
379
380
381
382
383
384
385
386class Convert4qmcInput(SimulationInput):
387
388    input_codes = '''
389        pyscf
390        qp
391        gaussian
392        casino
393        vsvb
394        gamess
395        gamess_ascii
396        gamess_fmo
397        gamess_xml
398        '''.split()
399
400    input_order = input_codes + '''
401        prefix
402        hdf5
403        add_cusp
404        psi_tag
405        ion_tag
406        no_jastrow
407        production
408        orbitals
409        multidet
410        gridtype
411        first
412        last
413        size
414        ci
415        read_initial_guess
416        target_state
417        natural_orbitals
418        threshold
419        opt_det_coeffs
420        zero_ci
421        add_3body_J
422        '''.split()
423
424    input_aliases = obj(
425        pyscf              = 'pyscf',
426        qp                 = 'QP',
427        gaussian           = 'gaussian',
428        casino             = 'casino',
429        vsvb               = 'VSVB',
430        gamess             = 'gamess',
431        gamess_ascii       = 'gamess',
432        gamess_fmo         = 'gamessFMO',
433        gamess_xml         = 'gamesxml', # not a typo
434        prefix             = 'prefix',
435        hdf5               = 'hdf5',
436        add_cusp           = 'addCusp',
437        psi_tag            = 'psi_tag',
438        ion_tag            = 'ion_tag',
439        no_jastrow         = 'nojastrow',
440        production         = 'production',
441        orbitals           = 'orbitals',
442        multidet           = 'multidet',
443        gridtype           = 'gridtype',
444        first              = 'first',
445        last               = 'last',
446        size               = 'size',
447        ci                 = 'ci',
448        read_initial_guess = 'readInitialGuess',
449        target_state       = 'TargetState',
450        natural_orbitals   = 'NaturalOrbitals',
451        threshold          = 'threshold',
452        opt_det_coeffs     = 'optDetCoeffs',
453        zero_ci            = 'zeroCi',
454        add_3body_J        = 'add3BodyJ',
455        )
456
457    input_types = obj(
458        app_name           = str, # executable name
459        pyscf              = str, # file path
460        qp                 = str, # file path
461        gaussian           = str, # file path
462        casino             = str, # file path
463        vsvb               = str, # file path
464        gamess             = str, # file path
465        gamess_ascii       = str, # file path
466        gamess_fmo         = str, # file path
467        gamess_xml         = str, # file path
468        prefix             = str, # any name
469        hdf5               = bool,
470        add_cusp           = bool,
471        psi_tag            = str, # wavefunction tag
472        ion_tag            = str, # particeset tag
473        no_jastrow         = bool,
474        production         = bool,
475        orbitals           = str,
476        multidet           = str,
477        gridtype           = str,
478        first              = float,
479        last               = float,
480        size               = int,
481        ci                 = str, # file path
482        read_initial_guess = int,
483        target_state       = int,
484        natural_orbitals   = int,
485        threshold          = float,
486        opt_det_coeffs     = bool,
487        zero_ci            = bool,
488        add_3body_J        = bool,
489        )
490
491    input_defaults = obj(
492        app_name           = 'convert4qmc',
493        pyscf              = None, # input codes
494        qp                 = None,
495        gaussian           = None,
496        casino             = None,
497        vsvb               = None,
498        gamess             = None,
499        gamess_ascii       = None,
500        gamess_fmo         = None,
501        gamess_xml         = None,
502        prefix             = None, # general options
503        hdf5               = False,
504        add_cusp           = False,
505        psi_tag            = None,
506        ion_tag            = None,
507        no_jastrow         = False,
508        production         = False,
509        orbitals           = None,
510        multidet           = None,
511        gridtype           = None,
512        first              = None,
513        last               = None,
514        size               = None,
515        ci                 = None, # gamess specific below
516        read_initial_guess = None,
517        target_state       = None,
518        natural_orbitals   = None,
519        threshold          = None,
520        opt_det_coeffs     = False,
521        zero_ci            = False,
522        add_3body_J        = False,# deprecated
523        )
524
525
526    def __init__(self,**kwargs):
527        # check that only allowed keyword inputs are provided
528        invalid = set(kwargs.keys())-set(self.input_types.keys())
529        if len(invalid)>0:
530            self.error('invalid inputs encountered\ninvalid keywords: {0}\nvalid keyword inputs are: {1}'.format(sorted(invalid),sorted(self.input_types.keys())))
531        #end if
532
533        # assign inputs
534        self.set(**kwargs)
535
536        # assign default values
537        self.set_optional(**self.input_defaults)
538
539        # check that all keyword inputs are valid
540        self.check_valid()
541    #end def __init__
542
543
544    def check_valid(self,exit=True):
545        valid = True
546        # check that all inputs have valid types and assign them
547        for k,v in self.items():
548            if v is not None and not isinstance(v,self.input_types[k]):
549                valid = False
550                if exit:
551                    self.error('keyword input {0} must be of type {1}\nyou provided a value of type {2}\nplease revise your input and try again'.format(k,self.input_types[k].__name__),v.__class__.__name__)
552                #end if
553                break
554            #end if
555        #end for
556        return valid
557    #end def check_valid
558
559
560    def set_app_name(self,app_name):
561        self.app_name = app_name
562    #end def set_app_name
563
564
565    def input_code(self):
566        input_code = None
567        for k in self.input_codes:
568            if k in self and self[k] is not None:
569                if input_code is not None:
570                    input_code = None
571                    break
572                else:
573                    input_code = self[k]
574                #end if
575            #end if
576        #end for
577        return input_code
578    #end def input_code
579
580
581    def has_input_code(self):
582        return self.input_code() is not None
583    #end def has_input_code
584
585
586    def app_command(self):
587        self.check_valid()
588        c = self.app_name
589        for k in self.input_order:
590            if k in self:
591                v = self[k]
592                n = self.input_aliases[k]
593                if isinstance(v,bool):
594                    if v:
595                        c += ' -{0}'.format(n)
596                    #end if
597                elif v is not None:
598                    c += ' -{0} {1}'.format(n,str(v))
599                #end if
600            #end if
601        #end for
602        return c
603    #end def app_command
604
605
606    def read(self,filepath):
607        None
608    #end def read
609
610
611    def write_text(self,filepath=None):
612        return self.app_command()
613    #end def write_text
614
615
616    def output_files(self):
617        prefix = 'sample'
618        if self.prefix!=None:
619            prefix = self.prefix
620        #end if
621        wfn_file  = prefix+'.Gaussian-G2.xml'
622        ptcl_file = prefix+'.Gaussian-G2.ptcl.xml'
623        return wfn_file,ptcl_file
624    #end def output_files
625#end class Convert4qmcInput
626
627
628
629def generate_convert4qmc_input(**kwargs):
630    return Convert4qmcInput(**kwargs)
631#end def generate_convert4qmc_input
632
633
634
635class Convert4qmcAnalyzer(SimulationAnalyzer):
636    def __init__(self,arg0):
637        if isinstance(arg0,Simulation):
638            self.infile = arg0.infile
639        else:
640            self.infile = arg0
641        #end if
642    #end def __init__
643
644    def analyze(self):
645        None
646    #end def analyze
647#end class Convert4qmcAnalyzer
648
649
650
651class Convert4qmc(Simulation):
652    input_type             = Convert4qmcInput
653    analyzer_type          = Convert4qmcAnalyzer
654    generic_identifier     = 'convert4qmc'
655    application            = 'convert4qmc'
656    application_properties = set(['serial'])
657    application_results    = set(['orbitals','particles'])
658    renew_app_command      = True
659
660    def __init__(self,*args,**kwargs):
661        Simulation.__init__(self,*args,**kwargs)
662        self.input_code = None
663    #end def __init__
664
665
666    def set_app_name(self,app_name):
667        self.app_name = app_name
668        self.input.set_app_name(app_name)
669    #end def set_app_name
670
671
672    def propagate_identifier(self):
673        None
674        #self.input.prefix = self.identifier
675    #end def propagate_identifier
676
677
678    def get_prefix(self):
679        input = self.input
680        prefix = 'sample'
681        if input.prefix is not None:
682            prefix = input.prefix
683        #end if
684        return prefix
685    #end def get_prefix
686
687
688    def list_output_files(self):
689        # try to support both pre and post v3.3.0 convert4qmc
690        prefix = self.get_prefix()
691        wfn_file  = prefix+'.Gaussian-G2.xml'
692        ptcl_file = prefix+'.Gaussian-G2.ptcl.xml'
693        if not os.path.exists(os.path.join(self.locdir,ptcl_file)):
694            if self.input.no_jastrow:
695                wfn_file  = prefix+'.wfnoj.xml'
696            else:
697                wfn_file  = prefix+'.wfj.xml'
698            #end if
699            ptcl_file = prefix+'.structure.xml'
700        #end if
701        return wfn_file,ptcl_file
702    #end def list_output_files
703
704
705    def check_result(self,result_name,sim):
706        calculating_result = False
707        if result_name=='orbitals':
708            calculating_result = True
709        elif result_name=='particles':
710            calculating_result = True
711        #end if
712        return calculating_result
713    #end def check_result
714
715
716    def get_result(self,result_name,sim):
717        result = obj()
718        input = self.input
719        wfn_file,ptcl_file = self.list_output_files()
720        if result_name=='orbitals':
721            result.location = os.path.join(self.locdir,wfn_file)
722            if self.input.hdf5==True:
723                orbfile = self.get_prefix()+'.orbs.h5'
724                result.orbfile = os.path.join(self.locdir,orbfile)
725            #end if
726        elif result_name=='particles':
727            result.location = os.path.join(self.locdir,ptcl_file)
728        else:
729            self.error('ability to get result '+result_name+' has not been implemented')
730        #end if
731        return result
732    #end def get_result
733
734
735    def incorporate_result(self,result_name,result,sim):
736        implemented = True
737        input = self.input
738        if isinstance(sim,Gamess):
739            self.input_code = 'gamess'
740            if result_name=='orbitals':
741                orbpath = os.path.relpath(result.location,self.locdir)
742                if result.scftyp=='mcscf':
743                    input.gamess_ascii = orbpath
744                    input.ci           = orbpath
745                elif result.scftyp=='none': # cisd, etc
746                    input.gamess_ascii = orbpath
747                    input.ci           = orbpath
748                    if result.mos>0:
749                        input.read_initial_guess = result.mos
750                    elif result.norbitals>0:
751                        input.read_initial_guess = result.norbitals
752                    #end if
753                else:
754                    input.gamess_ascii = orbpath
755                #end if
756                self.job.app_command = input.app_command()
757            else:
758                implemented = False
759            #end if
760        elif isinstance(sim,Pyscf):
761            self.input_code = 'pyscf'
762            if result_name=='orbitals':
763                orbpath = os.path.relpath(result.h5_file,self.locdir)
764                input.pyscf = orbpath
765            else:
766                implemented = False
767            #end if
768        elif isinstance(sim,QuantumPackage):
769            self.input_code = 'qp'
770            if result_name=='orbitals':
771                orbpath = os.path.relpath(result.outfile,self.locdir)
772                input.qp = orbpath
773            else:
774                implemented = False
775            #end if
776        else:
777            implemented = False
778        #end if
779        if not implemented:
780            self.error('ability to incorporate result "{0}" from {1} has not been implemented'.format(result_name,sim.__class__.__name__))
781        #end if
782    #end def incorporate_result
783
784
785    def check_sim_status(self):
786        output = open(os.path.join(self.locdir,self.outfile),'r').read()
787        #errors = open(os.path.join(self.locdir,self.errfile),'r').read()
788
789        success = 'QMCGaussianParserBase::dump' in output
790        for filename in self.list_output_files():
791            success &= os.path.exists(os.path.join(self.locdir,filename))
792        #end for
793
794        self.failed = not success
795        self.finished = self.job.finished
796    #end def check_sim_status
797
798
799    def get_output_files(self):
800        output_files = []
801        return output_files
802    #end def get_output_files
803
804
805    def app_command(self):
806        return self.input.app_command()
807    #end def app_command
808#end class Convert4qmc
809
810
811
812def generate_convert4qmc(**kwargs):
813    sim_args,inp_args = Simulation.separate_inputs(kwargs)
814    if 'identifier' in sim_args and not 'prefix' in inp_args:
815        inp_args.prefix = sim_args.identifier
816    #end if
817
818    if not 'input' in sim_args:
819        sim_args.input = generate_convert4qmc_input(**inp_args)
820    #end if
821    convert4qmc = Convert4qmc(**sim_args)
822
823    return convert4qmc
824#end def generate_convert4qmc
825
826
827
828
829
830
831class PyscfToAfqmcInput(SimulationInput):
832
833    input_order = '''
834        help
835        input
836        output
837        wavefunction
838        qmcpack_input
839        cholesky_threshold
840        kpoint
841        gdf
842        ao
843        cas
844        disable_ham
845        num_dets
846        real_ham
847        verbose
848        '''.split()
849
850    input_flags = obj(
851        help               = 'h',
852        input              = 'i',
853        output             = 'o',
854        wavefunction       = 'w',
855        qmcpack_input      = 'q',
856        cholesky_threshold = 't',
857        kpoint             = 'k',
858        gdf                = 'g',
859        ao                 = 'a',
860        cas                = 'c',
861        disable_ham        = 'd',
862        num_dets           = 'n',
863        real_ham           = 'r',
864        verbose            = 'v',
865        )
866
867    input_types = obj(
868        app_name           = str,
869        help               = bool,
870        input              = str,
871        output             = str,
872        wavefunction       = str,
873        qmcpack_input      = str,
874        cholesky_threshold = float,
875        kpoint             = bool,
876        gdf                = bool,
877        ao                 = bool,
878        cas                = tuple,
879        disable_ham        = bool,
880        num_dets           = int,
881        real_ham           = int,
882        verbose            = bool,
883        )
884
885    input_defaults = obj(
886        app_name           = 'pyscf_to_afqmc.py',
887        help               = False,
888        input              = None,
889        output             = None,
890        wavefunction       = None,
891        qmcpack_input      = None,
892        cholesky_threshold = None,
893        kpoint             = False,
894        gdf                = False,
895        ao                 = False,
896        cas                = None,
897        disable_ham        = False,
898        num_dets           = None,
899        real_ham           = None,
900        verbose            = False,
901        )
902
903
904    def __init__(self,**kwargs):
905        # reassign inputs provided via short flag names
906        for k,v in PyscfToAfqmcInput.input_flags.items():
907            if v in kwargs:
908                kwargs[k] = kwargs.pop(v)
909            #end if
910        #end for
911
912        # check that only allowed keyword inputs are provided
913        invalid = set(kwargs.keys())-set(self.input_types.keys())
914        if len(invalid)>0:
915            self.error('invalid inputs encountered\ninvalid keywords: {0}\nvalid keyword inputs are: {1}'.format(sorted(invalid),sorted(self.input_types.keys())))
916        #end if
917
918        # assign inputs
919        self.set(**kwargs)
920
921        # assign default values
922        self.set_optional(**self.input_defaults)
923
924        # check that all keyword inputs are valid
925        self.check_valid()
926    #end def __init__
927
928
929    def check_valid(self,exit=True):
930        valid = True
931        # check that all inputs have valid types and assign them
932        for k,v in self.items():
933            if v is not None and not isinstance(v,self.input_types[k]):
934                valid = False
935                if exit:
936                    self.error('keyword input "{0}" must be of type "{1}"\nyou provided a value of type "{2}"\nplease revise your input and try again'.format(k,self.input_types[k].__name__),v.__class__.__name__)
937                #end if
938                break
939            #end if
940        #end for
941        if 'cas' in self and self.cas is not None:
942            if len(self.cas)!=2:
943                valid = False
944                if exit:
945                    self.error('keyword input "cas" must contain only two elements\nnumber of elements provided: {}\nvalue provided: {}'.format(len(self.cas),self.cas))
946                #end if
947            #end if
948            noninteger = False
949            for v in self.cas:
950                noninteger |= not isinstance(v,int)
951            #end for
952            if noninteger:
953                valid = False
954                if exit:
955                    self.error('keyword input "cas" must contain two integers\nvalue provided: {}'.format(self.cas))
956                #end if
957            #end if
958        #end if
959        return valid
960    #end def check_valid
961
962
963    def is_valid(self):
964        return self.check_valid(exit=False)
965    #end def is_valid
966
967
968    def set_app_name(self,app_name):
969        self.app_name = app_name
970    #end def set_app_name
971
972
973    def app_command(self):
974        self.check_valid()
975        c = self.app_name
976        for k in self.input_order:
977            if k in self:
978                v = self[k]
979                n = self.input_flags[k]
980                if isinstance(v,bool):
981                    if v:
982                        c += ' -{0}'.format(n)
983                    #end if
984                elif isinstance(v,tuple):
985                    vs = ''
986                    for tv in v:
987                        vs += '{},'.format(tv)
988                    #end for
989                    c += ' -{0} {1}'.format(n,vs[:-1])
990                elif v is not None:
991                    c += ' -{0} {1}'.format(n,str(v))
992                #end if
993            #end if
994        #end for
995        return c
996    #end def app_command
997
998
999    def read(self,filepath):
1000        None
1001    #end def read
1002
1003
1004    def write_text(self,filepath=None):
1005        return self.app_command()
1006    #end def write_text
1007#end class PyscfToAfqmcInput
1008
1009
1010
1011def generate_pyscf_to_afqmc_input(**kwargs):
1012    return PyscfToAfqmcInput(**kwargs)
1013#end def generate_pyscf_to_afqmc_input
1014
1015
1016
1017class PyscfToAfqmcAnalyzer(SimulationAnalyzer):
1018    def __init__(self,arg0):
1019        if isinstance(arg0,Simulation):
1020            self.infile = arg0.infile
1021        else:
1022            self.infile = arg0
1023        #end if
1024    #end def __init__
1025
1026    def analyze(self):
1027        None
1028    #end def analyze
1029#end class PyscfToAfqmcAnalyzer
1030
1031
1032
1033class PyscfToAfqmc(Simulation):
1034    input_type             = PyscfToAfqmcInput
1035    analyzer_type          = PyscfToAfqmcAnalyzer
1036    generic_identifier     = 'pyscf2afqmc'
1037    application            = 'pyscf_to_afqmc.py'
1038    application_properties = set(['serial'])
1039    application_results    = set(['wavefunction','hamiltonian'])
1040    renew_app_command      = True
1041
1042
1043    def set_app_name(self,app_name):
1044        self.app_name = app_name
1045        self.input.set_app_name(app_name)
1046    #end def set_app_name
1047
1048
1049    def check_result(self,result_name,sim):
1050        calculating_result = False
1051        if result_name=='wavefunction':
1052            calculating_result = self.input.output is not None
1053        elif result_name=='hamiltonian':
1054            calculating_result = self.input.output is not None
1055        #end if
1056        return calculating_result
1057    #end def check_result
1058
1059
1060    def get_result(self,result_name,sim):
1061        result = obj()
1062        input = self.input
1063        if result_name in ('wavefunction','hamiltonian'):
1064            result.h5_file = os.path.join(self.locdir,input.output)
1065            if input.qmcpack_input is not None:
1066                result.xml = os.path.join(self.locdir,input.qmcpack_input)
1067            #end if
1068        else:
1069            self.error('ability to get result '+result_name+' has not been implemented')
1070        #end if
1071        return result
1072    #end def get_result
1073
1074
1075    def incorporate_result(self,result_name,result,sim):
1076        implemented = True
1077        input = self.input
1078        if isinstance(sim,Pyscf):
1079            if result_name=='wavefunction':
1080                chkfile = os.path.relpath(result.chkfile,self.locdir)
1081                input.input = chkfile
1082            else:
1083                implemented = False
1084            #end if
1085        else:
1086            implemented = False
1087        #end if
1088        if not implemented:
1089            self.error('ability to incorporate result "{0}" from {1} has not been implemented'.format(result_name,sim.__class__.__name__))
1090        #end if
1091    #end def incorporate_result
1092
1093
1094    def check_sim_status(self):
1095        output = open(os.path.join(self.locdir,self.outfile),'r').read()
1096
1097        success = '# Finished.' in output
1098        success &= os.path.exists(os.path.join(self.locdir,self.input.output))
1099
1100        self.failed = not success
1101        self.finished = self.job.finished
1102    #end def check_sim_status
1103
1104
1105    def get_output_files(self):
1106        output_files = []
1107        return output_files
1108    #end def get_output_files
1109
1110
1111    def app_command(self):
1112        return self.input.app_command()
1113    #end def app_command
1114#end class PyscfToAfqmc
1115
1116
1117
1118def generate_pyscf_to_afqmc(**kwargs):
1119    sim_args,inp_args = Simulation.separate_inputs(kwargs)
1120    if 'identifier' in sim_args:
1121        if 'output' not in inp_args:
1122            inp_args.output = '{}.afqmc.h5'.format(sim_args.identifier)
1123        #end if
1124        if 'qmcpack_input' not in inp_args:
1125            inp_args.qmcpack_input = '{}.afqmc.xml'.format(sim_args.identifier)
1126        #end if
1127    #end if
1128
1129    if not 'input' in sim_args:
1130        sim_args.input = generate_pyscf_to_afqmc_input(**inp_args)
1131    #end if
1132    sim = PyscfToAfqmc(**sim_args)
1133
1134    return sim
1135#end def generate_pyscf_to_afqmc
1136