1##################################################################
2##  (c) Copyright 2015-  by Jaron T. Krogel                     ##
3##################################################################
4
5
6#====================================================================#
7#  qmcpack_method_analyzers.py                                       #
8#    Analyzer classes at the level of QMC methods.  Instances        #
9#    contain all data outputted by VMC, Opt, DMC, etc. sub-runs      #
10#    carried out by QMCPACK.                                         #
11#                                                                    #
12#  Content summary:                                                  #
13#    MethodAnalyzer                                                  #
14#      Base class for specific method analyzers.                     #
15#      Derived classes are OptAnalyzer, VmcAnalyzer, DmcAnalyzer     #
16#                                                                    #
17#====================================================================#
18
19
20import os
21import re
22from generic import obj
23from hdfreader import HDFreader
24from qmcpack_analyzer_base import Checks,QAanalyzer,QAdata,QAHDFdata
25from qmcpack_property_analyzers import WavefunctionAnalyzer
26from qmcpack_quantity_analyzers import HDFAnalyzer
27from debug import *
28
29
30class MethodAnalyzer(QAanalyzer):
31    def __init__(self,series=None,calc=None,input=None,nindent=0):
32        QAanalyzer.__init__(self,nindent=nindent)
33        if series!=None and calc!=None and input!=None:
34            self.init_sub_analyzers(series,calc,input)
35        #end if
36    #end def __init__
37
38
39    def init_sub_analyzers(self,series,calc,input):
40        request  = QAanalyzer.request
41        run_info = QAanalyzer.run_info
42
43        source_path = run_info.source_path
44        file_prefix = run_info.file_prefix+'.s'+str(series).zfill(3)
45        method = calc.method
46
47        files  = obj()
48        outfiles = os.listdir(source_path)
49        self.vlog('looking for file prefix: '+file_prefix,n=2)
50        matched = False
51        for file in outfiles:
52            if file.startswith(file_prefix):
53                local_match = True
54                if file.endswith('scalar.dat'):
55                    files.scalar = file
56                elif file.endswith('stat.h5'):
57                    files.stat   = file
58                elif file.endswith('storeConfig.h5'):
59                    files.storeconfig = file
60                elif file.endswith('opt.xml'):
61                    files.opt    = file
62                elif file.endswith('dmc.dat') and method=='dmc':
63                    files.dmc    = file
64                elif '.traces.' in file:
65                    if not 'traces' in files:
66                        files.traces = []
67                    #end if
68                    files.traces.append(file)
69                else:
70                    local_match = False
71                #end if
72                matched = matched or local_match
73                self.vlog('match found: '+file,n=3)
74            #end if
75        #end for
76        complete = matched
77        complete &= 'scalar' in files
78        if 'linear' in method or method=='opt':
79            complete &= 'opt' in files
80        #end if
81        equil = request.equilibration
82        nblocks_exclude = -1
83        if isinstance(equil,int):
84            nblocks_exclude = equil
85        elif isinstance(equil,(dict,obj)):
86            if series in equil:
87                nblocks_exclude = equil[series]
88            #end if
89        elif equil!=None:
90            self.error('invalid input for equilibration which must be an int, dict, or obj\n  you provided: {0}\n  with type {1}'.format(equil,equil.__class__.__name__))
91        #end if
92        data_sources     = request.data_sources & set(files.keys())
93        method_info = obj(
94            method       = method,
95            series       = series,
96            file_prefix  = file_prefix,
97            files        = files,
98            data_sources = data_sources,
99            method_input = calc.copy(),
100            nblocks_exclude = nblocks_exclude,
101            complete     = complete,
102            )
103        self.info.transfer_from(method_info)
104
105        self.vlog('requested sources = '+str(list(request.data_sources)),n=2)
106        self.vlog('files available   = '+str(list(files.keys())),n=2)
107        self.vlog('available sources = '+str(list(data_sources)),n=2)
108
109        if not matched:
110            msg = 'no data files found\n  file prefix used for matching: {0}\n  checked all files in directory: {1}'.format(file_prefix,source_path)
111            #self.error(msg,trace=False)
112            #self.warn(msg)
113            return
114        #end if
115
116        self.set_global_info()
117
118        try:
119            analyzers = self.capabilities.analyzers
120            if 'scalar' in data_sources:
121                filepath = os.path.join(source_path,files.scalar)
122                self.scalars = analyzers.scalars_dat(filepath,equilibration='LocalEnergy',nindent=self.subindent())
123            #end if
124            if 'stat' in data_sources:
125                #determine scalars and analyzer quantities
126                analyzer_quantities = self.capabilities.analyzer_quantities
127                analyzer_quants = obj()
128                ignored_quantities = set()
129                ham = input.get('hamiltonian')
130                ham = ham.get_single('h0')
131                ham_est  = ham.get('estimator')
132                calc_est = calc.get('estimator')
133                estimators = obj()
134                if ham_est!=None:
135                    estimators.transfer_from(ham_est)
136                #end if
137                if calc_est!=None:
138                    estimators.transfer_from(calc_est)
139                #end if
140                for estname,est in estimators.items():
141                    if est==None:
142                        self.error('estimators have not been read properly by QmcpackInput',trace=False)
143                    #end if
144                    has_type = 'type' in est
145                    has_name = 'name' in est
146                    if has_type and has_name:
147                        type = est.type
148                        name = est.name
149                    elif has_name:
150                        type = est.name
151                        name = est.name
152                    elif has_type:
153                        type = est.type
154                        name = est.type
155                    else:
156                        self.error('estimator '+estname+' has no type or name')
157                    #end if
158                    cname = self.condense_name(name)
159                    ctype = self.condense_name(type)
160
161                    if ctype=='density' and not has_name:
162                        name = 'any'
163                    #end if
164
165                    if ctype in analyzer_quantities:
166                        analyzer_quants[name] = self.condense_name(type)
167                    #end if
168                #end for
169                not_scalars = set(analyzer_quants.keys())
170
171                self.scalars_hdf = analyzers.scalars_hdf(not_scalars,nindent=self.subindent())
172
173                analyzer_quantities = analyzer_quantities & request.quantities
174                for name,type in analyzer_quants.items():
175                    if type in analyzer_quantities:
176                        if type in analyzers:
177                            qqa = analyzers[type](name,nindent=self.subindent())
178                            qqa.init_sub_analyzers()
179                            self[name] = qqa
180                        else:
181                            ignored_quantities.add(name)
182                        #end if
183                    #end if
184                #end for
185                self.info.ignored_quantities = ignored_quantities
186            #end if
187            if 'dmc' in data_sources:
188                filepath = os.path.join(source_path,files.dmc)
189                self.dmc = analyzers.dmc_dat(filepath,nindent=self.subindent())
190            #end if
191            if 'traces' in data_sources and 'traces' in files:
192                self.traces = analyzers.traces(source_path,files.traces,nindent=self.subindent())
193            #end if
194        except:
195            self.info.complete = False
196        #end try
197
198        self.unset_global_info()
199
200        return
201    #end def init_sub_analyzers
202
203
204    def load_data_local(self):
205        source_path = QAanalyzer.run_info.source_path
206        data_sources = self.info.data_sources
207        files  = self.info.files
208        if 'stat' in data_sources:
209            filepath = os.path.join(source_path,files.stat)
210            hr = HDFreader(filepath)
211            if not hr._success:
212                self.warn('  hdf file seems to be corrupted, skipping contents:\n    '+filepath)
213            #end if
214            hdf = hr.obj
215            self.data = QAHDFdata()
216            self.data.transfer_from(hdf)
217        #end if
218        remove = []
219        for name,value in self.items():
220            if isinstance(value,HDFAnalyzer):
221                value.load_data_local(self.data)
222                value.info.data_loaded = True
223                if value.info.should_remove:
224                    remove.append(name)
225                #end if
226            #end if
227        #end for
228        for name in remove:
229            del self[name]
230        #end for
231    #end def load_data_local
232
233
234
235    def set_global_info(self):
236        QAanalyzer.method_info = self.info
237    #end def set_global_info
238
239    def unset_global_info(self):
240        QAanalyzer.method_info = None
241    #end def unset_global_info
242
243
244    def check_traces(self,pad=None):
245        verbose = pad!=None
246        method = self.info.method
247        series = self.info.series
248        if verbose:
249            desc = 'method {0} series {1}'.format(method,series)
250        #end if
251        if 'traces' in self:
252            check = {None:True,False:False,True:True}
253            if verbose:
254                self.log(pad+'Checking traces in '+desc)
255            #end if
256            scalars     = None
257            scalars_hdf = None
258            dmc         = None
259            if 'scalars' in self and 'data' in self.scalars:
260                scalars = self.scalars.data
261            #end if
262            if 'scalars_hdf' in self and 'data' in self.scalars_hdf:
263                scalars_hdf = self.scalars_hdf.data
264            #end if
265            if 'dmc' in self and 'data' in self.dmc:
266                dmc = self.dmc.data
267            #end if
268            checks = Checks('traces')
269            checks.exclude(None)
270            traces = self.traces
271            traces.form_diagnostic_data()
272            checks.psums   = traces.check_particle_sums()
273            if method=='dmc':
274                checks.dmc = traces.check_dmc(dmc)
275            else:
276                svalid,shvalid = traces.check_scalars(scalars,scalars_hdf)
277                checks.scalars     = svalid
278                checks.scalars_hdf = shvalid
279            #end if
280            valid = checks.valid()
281            if verbose:
282                checks.write(pad+'  ')
283            #end if
284            return valid
285        else:
286            if verbose:
287                self.log(pad+'No traces in '+desc)
288            #end if
289            return None
290        #end if
291    #end def check_traces
292
293#end class MethodAnalyzer
294
295
296
297
298class OptAnalyzer(MethodAnalyzer):
299    def init_sub_analyzers(self,series,calc,input):
300        MethodAnalyzer.init_sub_analyzers(self,series,calc,input)
301
302        source_path = QAanalyzer.run_info.source_path
303        files = self.info.files
304
305        if 'opt' in files:
306            opt_out_xml = os.path.join(source_path,files.opt)
307            self.wavefunction = WavefunctionAnalyzer(opt_out_xml)
308        #end if
309    #ed def init_sub_analyzers
310#end class OptAnalyzer
311
312class VmcAnalyzer(MethodAnalyzer):
313    None
314#end class OptAnalyzer
315
316class DmcAnalyzer(MethodAnalyzer):
317    None
318#end class OptAnalyzer
319