1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15  __id__ = "$Id: fitrt.py 6626 2011-06-07 08:32:48Z yshang $" 
 16   
 17  import tempfile, shutil, copy, os 
 18  from diffpy.srrietveld.exceptions import SrrRunTimeError 
 19  from diffpy.refinementdata.refinement import Refinement 
 20  from diffpy.pyfullprof.exception import RietException as FPError 
 21  from diffpy.pygsas.exception import RietException as GSASError 
 22  from diffpy.srrietveld.gui import srrguiglobals as GLOBALS  
 23  from diffpy.srrietveld.utility import printWarning 
 24  from diffpy.srrietveld.convert.datafile import DataFile 
 25  import diffpy.srrietveld.utility as UTILS 
 26   
 28      """FitRT provides the runtime control of refinements. It uses two basic ways 
 29      to run a refinement, either step by step or finish everything by one call. 
 30   
 31      Data member: 
 32   
 33          fit       -- a diffpy.refinementdata.Refinement object that stores a fit 
 34          strategy  -- a refine strategy to be applied 
 35          index     -- the index to a single fit (if multiple fits are saved 
 36                       together as an array) 
 37          enginefit -- the engine fit object 
 38          step      -- record the refinement step 
 39          tempDir   -- the working folder 
 40          workdingDir -- the current working directory 
 41      """ 
 42 -    def __init__(self, job, fit,index=None): 
  43          """ Initialization. 
 44   
 45          job       -- the job this fitrt belonged to 
 46          fit       -- a diffpy.refinementdata.Refinement object that stores a fit 
 47          index     -- the index to a single fit (if multiple fits are saved 
 48                       together as an array) 
 49          """ 
 50          self.fit = fit 
 51          self.job = job 
 52           
 53          self.index = index 
 54   
 55          self.enginefit = None 
 56          self.step = 0 
 57           
 58          self.tempDir = None 
 59           
 60          self.workingDir = os.getcwd() 
 61           
 62           
 63          self.isStrategyEnabled = GLOBALS.isStrategyEnabled 
 64   
 65          return 
  66   
 68          '''Set the strategy based on the global settings''' 
 69          if isStrategyEnabled: 
 70              self.strategy = copy.deepcopy(self.fit.getPyObj("Strategy")) 
 71          else: 
 72              self.strategy = self.fit.getOneStepStrategy() 
 73           
 74          return 
  75   
 76 -    def run(self, isStrategyEnabled = False, continuous=True): 
  77          """Run the refinement according to its strategy. 
 78           
 79          isStrategyEnabled -- if the strategy is enabled  
 80           
 81          continuous  -- run the whole refinement continuously or not 
 82   
 83          return: True if the refinement finished. False if not. 
 84          """ 
 85   
 86           
 87          self.isStrategyEnabled = isStrategyEnabled 
 88   
 89           
 90          if self.prepare(): 
 91               
 92              try: 
 93                  os.chdir(self.tempDir) 
 94                   
 95                  self.enginefit.fixAll() 
 96                  self.enginefit.refine(cycle=5, srtype="l", 
 97                      mode="refine", signature=["dry", '.']) 
 98                   
 99              except (FPError, GSASError), e: 
100                  self.fit.setStatus(Refinement.ERROR, self.index) 
101                  self.enginefit = None 
102                  self.tempDir = None 
103                  os.chdir(self.workingDir) 
104                  self.clean() 
105                  UTILS.printWarning(e.message) 
106                   
107                  return True 
108   
109              GLOBALS.project.updateFit(self) 
110              if not continuous: 
111                  return False 
112           
113          else: 
114              self.fit.setStatus(Refinement.ERROR, self.index) 
115              self.enginefit = None 
116              self.tempDir = None 
117              os.chdir(self.workingDir) 
118              self.clean() 
119               
120              return True 
121   
122           
123          self.__setStrategy(isStrategyEnabled) 
124           
125          while self.step < len(self.strategy): 
126               
127              try: 
128                   
129                  self.refineSingleStep() 
130              except (FPError, GSASError), e: 
131                  self.fit.setStatus(Refinement.ERROR, self.index) 
132                  self.enginefit = None 
133                  self.tempDir = None 
134                  os.chdir(self.workingDir) 
135                  self.clean() 
136                  return True 
137   
138              GLOBALS.project.updateFit(self) 
139              self.step += 1 
140               
141              if not continuous: 
142                  break 
143   
144           
145          if self.step < len(self.strategy): 
146           
147              os.chdir(self.workingDir) 
148              return False 
149   
150          self.fit.setStatus(self.fit.FINISHED, self.index) 
151           
152          os.chdir(self.workingDir) 
153          self.clean() 
154               
155          return True 
 156   
157   
158       
160          """Prepare the refinement, consisting of three steps: 
161          1. Check if the engine fit object is available 
162          2. Create temporary folder for running 
163          3. Generate the data file 
164   
165          return: True if it runs sucessfully, otherwise False. 
166          """ 
167           
168          if self.tempDir: 
169              return False 
170   
171           
172          if self.enginefit is None: 
173              self.enginefit =  self.fit.owner.exportEngineFit(self.fit, self.index) 
174   
175           
176          self.tempDir = tempfile.mkdtemp() 
177   
178           
179          patterns = self.fit.getObject('Pattern') 
180           
181           
182          engineName = self.fit.getEngineType() 
183           
184           
185           
186          for bankid, pattern in enumerate(patterns): 
187               
188              ds = pattern.get('Instrumentfile') 
189              if ds is not None:  
190                  instFilePath = self.fit.findFileFromDataset(ds, self.index) 
191              else: instFilePath = None 
192               
193              for param in ['Datafile', 'MFIL']: 
194                   
195                  ds = pattern.get(param) 
196                   
197                  if ds is None: 
198                      if param == "Datafile": 
199                          __msg = 'The data file path is not specified. ' 
200                          UTILS.printWarning(__msg) 
201                          return False 
202                      else: 
203                          continue 
204                   
205                  filepath = self.fit.findFileFromDataset(ds, self.index) 
206                   
207                  if filepath: 
208                       
209                       
210                      filepath = os.path.abspath( 
211                                                 os.path.join(GLOBALS.project.basepath,  
212                                                              filepath) 
213                                                 ) 
214                  else: 
215                      if param == 'Datafile': 
216                          __msg = 'The data file is not found. ' 
217                          UTILS.printWarning(__msg) 
218                          return False 
219                      else: 
220                          continue 
221                   
222                  dataFile = DataFile(filepath = filepath, engine = engineName) 
223                   
224                  filepath = dataFile.prepDataFile(self.tempDir, 
225                                                     instFilePath) 
226                       
227                   
228                   
229                  engPattern = self.enginefit.Pattern.get(bankid) 
230                  if hasattr(engPattern, param): 
231                      engPattern.set( param, os.path.basename(filepath) ) 
232                  else: 
233                      if param == "Datafile": 
234                          __msg = 'The data file path is not set in the engine file. ' 
235                          UTILS.printWarning(__msg) 
236                          return False 
237           
238          return True 
 239   
241          '''Clean up after each refinement''' 
242          from diffpy.srrietveld.gui.srrguiglobals import isDebug 
243          if not isDebug:  
244              if self.tempDir: 
245                  from shutil import rmtree 
246                  from os import path 
247                  if path.exists(self.tempDir): 
248                      rmtree(self.tempDir) 
249           
250          return 
 251   
252 -    def prepareFile(self, fid, engineName, bankid = None, instFilePath = None): 
 253          """Write or move data/instrument files in running/tmp directory 
254   
255          enginename -- the type of engine, can be either gsas or fullprof 
256          fid -- the file id 
257          bankid -- the bankid, used to convert the file format 
258          instFilePath -- The instrument file path 
259           
260          return the file name 
261          """ 
262          from hashlib import sha1 
263           
264          bankid = 1 
265           
266          from diffpy.srrietveld.addon.datafile import DataFileConverter as DFC 
267           
268          fileList = GLOBALS.project.getObject('SourceFileList') 
269           
270          fileObj = fileList.findFileByID(fid) 
271           
272           
273           
274          fileObj.dump(self.tempDir) 
275           
276          oldPath = os.path.join(self.tempDir, fileObj.fileName) 
277           
278           
279          root, ext = os.path.splitext(fileObj.fileName) 
280          if engineName == 'gsas': 
281               
282              if ext.lower() in [".chi", ".dat", ".txt"]: 
283                   
284                  fileName = root + '.gsa' 
285                  newPath = os.path.join(self.tempDir, fileName) 
286                   
287                   
288   
289                  if os.path.isfile(newPath) and \ 
290                  fileObj.fid == sha1(open(newPath, 'rb').read()).hexdigest(): 
291                      __message = "A different file with same name exist. " + \ 
292                      "will be replaced with the new one" 
293                      print __message 
294                   
295                  dfc = DFC(oldPath) 
296                   
297                  dfc.toGSASFile(oldPath, newPath, bankid) 
298   
299   
300          if engineName == 'fullprof': 
301              fileName = root + '.dat' 
302              newPath = os.path.join(self.tempDir, fileName) 
303               
304              if ext.lower() in [".chi", ".gsa", ".gda", "fxye"]: 
305                  if instFilePath is not None: 
306                      instFid = sha1(open(instFilePath, 'rb').read()).hexdigest() 
307                   
308                  if ext.lower() != '.chi' and fid != instFid: 
309                      __warningMsg = 'To convert GSAS data file, installation of ' + \ 
310                      'GSAS is needed and an instrument file is required. ' 
311                       
312                      printWarning(__warningMsg) 
313                   
314                   
315                   
316                  dfc = DFC(oldPath, instFilePath) 
317                  import glob 
318                  desfile = os.path.join(os.getcwd(), "*.EXP") 
319                  for fn in glob.glob(desfile): 
320                      expfilename = fn 
321                  if expfilename: 
322                      dfc.toFPFile(oldPath, newPath, bankid, expfilename) 
323                  elif ext.lower() == '.chi': 
324                      dfc.toFPFile(oldPath, newPath, bankid) 
325                  else: 
326                      __warningMsg = "To convert GSAS data file, GSAS is needed " + \ 
327                      "to be installed and an instrument file is required." + \ 
328                      "The gsas data file can not be converted. The refinment may " + \ 
329                      "not run. " 
330                      printWarning(__warningMsg) 
331                   
332              if ext.lower() not in [".chi", ".gsa", ".gda", "fxye", '.dat', '.raw']: 
333                  __warningMsg = 'Data file extension is not recognized. The ' + \ 
334                  'refinement may not run correctly. ' 
335                  printWarning(__warningMsg) 
336                       
337          return fileName 
 338   
339   
341          """Refine a single step in the strategy list. 
342          """ 
343          import re 
344   
345           
346          strategystep = copy.deepcopy(self.strategy[self.step]) 
347          method, paramlist = strategystep.items()[0] 
348   
349          headparam = paramlist[0][0] 
350          refmsg = "\nRefinable Parameter = %-10s   Over-all Step = %-5s  Refine-Type = %-10s\n"% \ 
351                  (headparam, self.step, method) 
352          refmsg += "%-10sNew Variables: \n"% ("") 
353          for param in paramlist: 
354               
355              fullpath = param[0] 
356              formula = param[2] 
357              self.setConstraint(fullpath, formula) 
358              refmsg += "%-20s%-20s:  %-20s\n"% ("", fullpath, formula) 
359          print refmsg 
360   
361           
362          sig = str(self.step) + "_" + headparam.split(".")[-1] 
363          '''Windows directory name can not include following chars: 
364          < (less than)> (greater than) : (colon) " (double quote) 
365           / (forward slash) \ (backslash) | (vertical bar or pipe) 
366           ? (question mark) * (asterisk)''' 
367          sig = sig.replace(':','.') 
368          fitsummary = self.enginefit.refine(40, srtype = method.lower()[0], 
369                  mode = "refine", signature=[sig, '.']) 
370   
371           
372          chi2 = fitsummary.getResidueValue(-1, residname="Chi2") 
373          rwp = fitsummary.getResidueValue(-1, residname="Rwp") 
374          re = fitsummary.getResidueValue(-1, residname="Re") 
375   
376          print "%-10s:  Chi2 = %-15s   Rp = %-15s  Rexp = %-15s"% (method, chi2, rwp, re) 
377          print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" 
378   
379          return 
 380   
381   
383          """ Turn on the refinement flag for parameters 
384          """ 
385          fitname = key.split(".")[0] 
386          key = key.replace(fitname+".", "") 
387          try: 
388               
389              newvalue = int(formula) 
390          except: 
391               
392              try: 
393                  newvalue = float(formula) 
394              except: 
395                  self.enginefit.setConstraintByPath(key, formula) 
396                  return 
397          self.enginefit.setByPath(key, newvalue) 
398          return 
  399   
400