- Timestamp:
- Aug 8, 2017 9:26:44 AM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branch/2frame/GSASIIscriptable.py
r2967 r2968 1 #!/usr/bin/env python 1 2 # -*- coding: utf-8 -*- 2 3 ########### SVN repository information ################### … … 11 12 ----------------------------------- 12 13 13 Routines for reading, writing, modifying and creating GSAS-II project (.gpx) files. 14 Routines for reading, writing, modifying and creating GSAS-II project (.gpx) files. 14 15 15 16 """ 16 from __future__ import division, print_function # needed? 17 from __future__ import division, print_function # needed? 17 18 import os.path as ospath 18 19 import sys … … 47 48 :param str ProjFile: GSAS-II project (name.gpx) full file name 48 49 :returns: Project,nameList, where 49 50 50 51 * Project (dict) is a representation of gpx file following the GSAS-II tree struture 51 52 for each item: key = tree name (e.g. 'Controls','Restraints',etc.), data is dict … … 54 55 55 56 Example for fap.gpx:: 56 57 57 58 Project = { #NB:dict order is not tree order 58 u'Phases':{'data':None,'fap':{phase dict}}, 59 u'PWDR FAP.XRA Bank 1':{'data':[histogram data list],'Comments':comments,'Limits':limits, etc}, 59 u'Phases':{'data':None,'fap':{phase dict}}, 60 u'PWDR FAP.XRA Bank 1':{'data':[histogram data list],'Comments':comments,'Limits':limits, etc}, 60 61 u'Rigid bodies':{'data': {rigid body dict}}, 61 62 u'Covariance':{'data':{covariance data dict}}, 62 u'Controls':{'data':{controls data dict}}, 63 u'Notebook':{'data':[notebook list]}, 64 u'Restraints':{'data':{restraint data dict}}, 63 u'Controls':{'data':{controls data dict}}, 64 u'Notebook':{'data':[notebook list]}, 65 u'Restraints':{'data':{restraint data dict}}, 65 66 u'Constraints':{'data':{constraint data dict}}] 66 67 } 67 68 nameList = [ #NB: reproduces tree order 68 69 [u'Notebook',], 69 [u'Controls',], 70 [u'Covariance',], 70 [u'Controls',], 71 [u'Covariance',], 71 72 [u'Constraints',], 72 [u'Restraints',], 73 [u'Rigid bodies',], 73 [u'Restraints',], 74 [u'Rigid bodies',], 74 75 [u'PWDR FAP.XRA Bank 1', 75 u'Comments', 76 u'Limits', 77 u'Background', 76 u'Comments', 77 u'Limits', 78 u'Background', 78 79 u'Instrument Parameters', 79 u'Sample Parameters', 80 u'Peak List', 81 u'Index Peak List', 82 u'Unit Cells List', 83 u'Reflection Lists'], 80 u'Sample Parameters', 81 u'Peak List', 82 u'Index Peak List', 83 u'Unit Cells List', 84 u'Reflection Lists'], 84 85 [u'Phases', u'fap'] 85 86 ] 86 87 87 ''' 88 88 if not ospath.exists(ProjFile): … … 112 112 return None 113 113 return Project,nameList 114 114 115 115 def SaveDictToProjFile(Project,nameList,ProjFile): 116 116 '''Save a GSAS-II project file from dictionary/nameList created by LoadDictFromProjFile 117 117 118 118 :param dict Project: representation of gpx file following the GSAS-II 119 119 tree structure as described for LoadDictFromProjFile 120 120 :param list nameList: names of main tree entries & subentries used to reconstruct project file 121 121 :param str ProjFile: full file name for output project.gpx file (including extension) 122 123 122 ''' 124 123 file = open(ProjFile,'wb') … … 133 132 file.close() 134 133 print('project save successful') 135 134 136 135 def ImportPowder(reader,filename): 137 136 '''Use a reader to import a powder diffraction data file 138 137 139 138 :param str reader: a scriptable reader 140 139 :param str filename: full name of powder data file; can be "multi-Bank" data 141 142 :returns : list rdlist: list of rrader objects containing powder data, one for each140 141 :returns list rdlist: list of reader objects containing powder data, one for each 143 142 "Bank" of data encountered in file. Items in reader object of interest are: 144 143 145 144 * rd.comments: list of str: comments found on powder file 146 145 * rd.dnames: list of str: data nammes suitable for use in GSASII data tree NB: duplicated in all rd entries in rdlist 147 146 * rd.powderdata: list of numpy arrays: pos,int,wt,zeros,zeros,zeros as needed for a PWDR entry in GSASII data tree. 148 149 147 ''' 150 148 rdfile,rdpath,descr = imp.find_module(reader) 151 149 rdclass = imp.load_module(reader,rdfile,rdpath,descr) 152 rd = rdclass.GSAS_ReaderClass() 150 rd = rdclass.GSAS_ReaderClass() 153 151 if not rd.scriptable: 154 152 print(u'**** ERROR: '+reader+u' is not a scriptable reader') … … 173 171 print(rd.errors) 174 172 return None 175 173 176 174 def SetDefaultDData(dType,histoName,NShkl=0,NDij=0): 177 175 '''Create an initial Histogram dictionary 178 176 179 177 Author: Jackson O'Donnell jacksonhodonnell@gmail.com 180 178 ''' … … 203 201 def PreSetup(data): 204 202 '''Create part of an initial (empty) phase dictionary 205 203 206 204 from GSASIIphsGUI.py, near end of UpdatePhaseData 207 205 Author: Jackson O'Donnell jacksonhodonnell@gmail.com … … 594 592 595 593 class G2ObjectWrapper(object): 596 """Base class for all GSAS-II object wrappers 594 """Base class for all GSAS-II object wrappers. 595 596 The underlying GSAS-II format can be accessed as `wrapper.data`. A number 597 of overrides are implemented so that the wrapper behaves like a dictionary. 598 597 599 Author: Jackson O'Donnell jacksonhodonnell@gmail.com 598 600 """ … … 633 635 loaded from the gpxfile, then set to save to filename in the future""" 634 636 if gpxfile is None: 637 filename = os.path.abspath(os.path.expanduser(filename)) 635 638 self.filename = filename 636 639 self.data, self.names = make_empty_project(author=author, filename=filename) 637 640 elif isinstance(gpxfile, str): 638 641 # TODO set author, filename 639 self.filename = gpxfile642 self.filename = os.path.abspath(os.path.expanduser(gpxfile)) 640 643 self.data, self.names = LoadDictFromProjFile(gpxfile) 641 644 self.index_ids() … … 645 648 @classmethod 646 649 def from_dict_and_names(cls, gpxdict, names, filename=None): 650 """Creates a :class:`G2Project` directly from 651 a dictionary and a list of names. If in doubt, do not use this. 652 653 :returns: a :class:`G2Project` 654 """ 647 655 out = cls() 648 656 if filename: 657 filename = os.path.abspath(os.path.expanduser(filename)) 649 658 out.filename = filename 650 659 gpxdict['Controls']['data']['LastSavedAs'] = filename … … 663 672 # TODO update LastSavedUsing ? 664 673 if filename: 674 filename = os.path.abspath(os.path.expanduser(filename)) 665 675 self.data['Controls']['data']['LastSavedAs'] = filename 666 676 self.filename = filename … … 673 683 674 684 Automatically checks for an instrument parameter file, or one can be 675 provided.""" 685 provided. 686 687 :param str datafile: The powder data file to read, a filename. 688 :param str iparams: The instrument parameters file, a filename. 689 690 :returns: A :class:`G2PwdrData` object representing 691 the histogram""" 692 datafile = os.path.abspath(os.path.expanduser(datafile)) 693 iparams = os.path.abspath(os.path.expanduser(iparams)) 676 694 pwdrreaders = import_generic(datafile, PwdrDataReaders) 677 695 histname, new_names, pwdrdata = load_pwd_from_reader( … … 691 709 """Loads a phase into the project from a .cif file 692 710 693 :returns: A :class:`gpx_manipulations.G2Phase` object representing the 711 :param str phasefile: The CIF file from which to import the phase. 712 :param str phasename: The name of the new phase, or None for the default 713 :param list histograms: The names of the histograms to associate with 714 this phase 715 716 :returns: A :class:`G2Phase` object representing the 694 717 new phase.""" 718 phasefile = os.path.abspath(os.path.expanduser(phasefile)) 719 695 720 # TODO handle multiple phases in a file 696 721 phasereaders = import_generic(phasefile, PhaseReaders) … … 778 803 779 804 def histogram_names(self): 780 """Gives an iterator of the names of each histogram in the project.""" 805 """Gives a list of the names of each histogram in the project. 806 807 :returns: list of strings 808 809 .. seealso:: 810 :func:`~GSASIIscriptable.G2Project.histogram` 811 :func:`~GSASIIscriptable.G2Project.histograms` 812 :func:`~GSASIIscriptable.G2Project.phase` 813 :func:`~GSASIIscriptable.G2Project.phases` 814 :func:`~GSASIIscriptable.G2Project.phase_names` 815 """ 816 output = [] 781 817 for obj in self.names: 782 818 if len(obj) > 1 and obj[0] != u'Phases': 783 yield obj[0] 819 output.append(obj[0]) 820 return output 784 821 785 822 def histogram(self, histname): 786 """Returns the histogram named histname, or None if it does not exist.""" 823 """Returns the histogram named histname, or None if it does not exist. 824 825 :returns: A :class:`G2PwdrData` object, or None if 826 the histogram does not exist 827 .. seealso:: 828 :func:`~GSASIIscriptable.G2Project.histogram_names` 829 :func:`~GSASIIscriptable.G2Project.histograms` 830 :func:`~GSASIIscriptable.G2Project.phase` 831 :func:`~GSASIIscriptable.G2Project.phases` 832 :func:`~GSASIIscriptable.G2Project.phase_names` 833 """ 787 834 if histname in self.data: 788 return G2PwdrData(self.data[histname] )835 return G2PwdrData(self.data[histname], self) 789 836 return None 790 837 791 838 def histograms(self): 792 839 """Return a list of all histograms, as 793 :class:`gpx_manipulations.G2PwdrData` objects""" 840 :class:`G2PwdrData` objects 841 .. seealso:: 842 :func:`~GSASIIscriptable.G2Project.histogram_names` 843 :func:`~GSASIIscriptable.G2Project.histograms` 844 :func:`~GSASIIscriptable.G2Project.phase` 845 :func:`~GSASIIscriptable.G2Project.phases` 846 :func:`~GSASIIscriptable.G2Project.phase_names` 847 """ 794 848 return [self.histogram(name) for name in self.histogram_names()] 795 849 796 850 def phase_names(self): 797 """Gives an iterator of the names of each phase in the project.""" 851 """Gives an list of the names of each phase in the project. 852 853 :returns: A list of strings 854 .. seealso:: 855 :func:`~GSASIIscriptable.G2Project.histogram` 856 :func:`~GSASIIscriptable.G2Project.histograms` 857 :func:`~GSASIIscriptable.G2Project.histogram_names` 858 :func:`~GSASIIscriptable.G2Project.phase` 859 :func:`~GSASIIscriptable.G2Project.phases` 860 """ 798 861 for obj in self.names: 799 862 if obj[0] == 'Phases': 800 for name in obj[1:]: 801 yield name 802 break 863 return obj[1:] 864 return [] 803 865 804 866 def phase(self, phasename): 805 return G2Phase(self.data['Phases'][phasename]) 867 """ 868 Gives an object representing the specified phase in this project. 869 870 :param str phasename: The name of the desired phase 871 :returns: A :class:`G2Phase` object 872 :raises: KeyError 873 .. seealso:: 874 :func:`~GSASIIscriptable.G2Project.histogram_names` 875 :func:`~GSASIIscriptable.G2Project.histograms` 876 :func:`~GSASIIscriptable.G2Project.phase` 877 :func:`~GSASIIscriptable.G2Project.phases` 878 :func:`~GSASIIscriptable.G2Project.phase_names` 879 """ 880 phases = self.data['Phases'] 881 if phasename in phases: 882 return G2Phase(phases[phasename], self) 806 883 807 884 def phases(self): 885 """ 886 Returns a list of all the phases in the project. 887 888 :returns: A :class:`G2Phase` 889 .. seealso:: 890 :func:`~GSASIIscriptable.G2Project.histogram` 891 :func:`~GSASIIscriptable.G2Project.histograms` 892 :func:`~GSASIIscriptable.G2Project.histogram_names` 893 :func:`~GSASIIscriptable.G2Project.phase` 894 :func:`~GSASIIscriptable.G2Project.phase_names` 895 """ 808 896 return [self.phase(name) for name in self.phase_names()] 809 897 810 898 def do_refinements(self, refinements, histogram='all', phase='all', 811 899 outputnames=None): 812 """Conducts a series of refinements.""" 900 """Conducts a series of refinements. 901 902 :param list refinements: A list of dictionaries defining refinements 903 :param str histogram: Name of histogram for refinements to be applied 904 to, or 'all' 905 :param str phase: Name of phase for refinements to be applied to, or 906 'all' 907 """ 813 908 if outputnames: 814 909 if len(refinements) != len(outputnames): … … 904 999 string variable specifiers, or arguments for :meth:`make_var_obj` 905 1000 :param str type: A string constraint type specifier. See 906 : meth:`add_constraint_raw`"""1001 :class:`~GSASIIscriptable.G2Project.add_constraint_raw`""" 907 1002 for var in vars: 908 1003 if isinstance(var, str): … … 957 1052 958 1053 class G2AtomRecord(G2ObjectWrapper): 959 """Wrapper for an atom record 960 Author: Jackson O'Donnell jacksonhodonnell@gmail.com 1054 """Wrapper for an atom record. Has convenient accessors via @property. 1055 1056 Example: 1057 1058 >>> atom = some_phase.atom("O3") 1059 >>> # We can access the underlying data format 1060 >>> atom.data 1061 ['O3', 'O-2', '', ... ] 1062 >>> # We can also use wrapper accessors 1063 >>> atom.coordinates 1064 (0.33, 0.15, 0.5) 1065 >>> atom.refinement_flags 1066 u'FX' 1067 >>> atom.ranId 1068 4615973324315876477 961 1069 """ 962 def __init__(self, data, indices ):1070 def __init__(self, data, indices, proj): 963 1071 self.data = data 964 1072 self.cx, self.ct, self.cs, self.cia = indices 1073 self.proj = proj 965 1074 966 1075 @property … … 977 1086 978 1087 @refinement_flags.setter 979 def set_refinement(self, other): 1088 def refinement_flags(self, other): 1089 # Automatically check it is a valid refinement 980 1090 for c in other: 981 1091 if c not in ' FXU': … … 1005 1115 1006 1116 class G2PwdrData(G2ObjectWrapper): 1007 """Wraps a Poweder Data Histogram. 1008 Author: Jackson O'Donnell jacksonhodonnell@gmail.com 1009 """ 1117 """Wraps a Poweder Data Histogram.""" 1118 def __init__(self, data, proj): 1119 self.data = data 1120 self.proj = proj 1121 1010 1122 @staticmethod 1011 1123 def is_valid_refinement_key(key): … … 1050 1162 Y = [y for x, y in bgrnd[1]['FixedPoints']] 1051 1163 1164 limits = self['Limits'][1] 1165 if X[0] > limits[0]: 1166 X = [limits[0]] + X 1167 Y = [Y[0]] + Y 1168 if X[-1] < limits[1]: 1169 X += [limits[1]] 1170 Y += [Y[-1]] 1171 1052 1172 # Some simple lookups 1053 limits = self['Limits']1054 1173 inst, inst2 = self['Instrument Parameters'] 1055 1174 pwddata = self['data'][1] … … 1071 1190 data = np.array([xdata, ydata, W, Z, Z, Z]) 1072 1191 G2pwd.DoPeakFit('LSQ', [], bgrnd, limits, inst, inst2, data, 1073 preVaryList=bakVary, controls={})1192 bakVary, controls={}) 1074 1193 1075 1194 # Post-fit … … 1128 1247 bkg[3:] = value['coeffs'] 1129 1248 if 'FixedPoints' in value: 1130 peaks['FixedPoints'] = value 1249 peaks['FixedPoints'] = [(float(a), float(b)) 1250 for a, b in value['FixedPoints']] 1131 1251 if value.get('fit fixed points', False): 1132 1252 self.fit_fixed_points() … … 1175 1295 Author: Jackson O'Donnell jacksonhodonnell@gmail.com 1176 1296 """ 1297 def __init__(self, data, proj): 1298 self.data = data 1299 self.proj = proj 1300 1177 1301 @staticmethod 1178 1302 def is_valid_refinement_key(key): … … 1182 1306 def atom(self, atomlabel): 1183 1307 """Returns the atom specified by atomlabel, or None if it does not 1184 exist.""" 1308 exist. 1309 1310 :param str atomlabel: The name of the atom (e.g. "O2") 1311 1312 :returns: A :class:`G2AtomRecord` object 1313 representing the atom.""" 1185 1314 # Consult GSASIIobj.py for the meaning of this 1186 1315 cx, ct, cs, cia = self.data['General']['AtomPtrs'] … … 1189 1318 for atom in atoms: 1190 1319 if atom[ct-1] == atomlabel: 1191 return G2AtomRecord(atom, ptrs )1320 return G2AtomRecord(atom, ptrs, self.proj) 1192 1321 1193 1322 def atoms(self): 1194 """Returns a list of atoms present in the phase.""" 1323 """Returns a list of atoms present in the phase. 1324 1325 :returns: A list of :class:`G2AtomRecord` objects. See 1326 also :func:`~GSASIIscriptable.G2Phase.atom`""" 1195 1327 ptrs = self.data['General']['AtomPtrs'] 1196 1328 output = [] 1197 1329 atoms = self.data['Atoms'] 1198 1330 for atom in atoms: 1199 output.append(G2AtomRecord(atom, ptrs)) 1331 output.append(G2AtomRecord(atom, ptrs, self.proj)) 1332 return output 1333 1334 def histograms(self): 1335 output = [] 1336 for hname in self.data.get('Histograms', {}).keys(): 1337 output.append(self.proj.histogram(hname)) 1200 1338 return output 1201 1339 … … 1205 1343 1206 1344 def cell_dict(self): 1345 """Returns a dictionary of the cell parameters, with keys: 1346 'a', 'b', 'c', 'alpha', 'beta', 'gamma', 'vol' 1347 1348 :returns: a dict""" 1207 1349 cell = self['General']['Cell'] 1208 1350 return {'a': cell[1], 'b': cell[2], 'c': cell[3], 1209 1351 'alpha': cell[4], 'beta': cell[5], 'gamma': cell[6], 1210 'vol': cell[ 6]}1352 'vol': cell[7]} 1211 1353 1212 1354 def set_refinement(self, key, value): … … 1217 1359 1218 1360 for atomlabel, atomrefinement in value.items(): 1219 atom = self.atom(atomlabel) 1220 atom.refinement_flags = atomrefinement 1361 if atomlabel == 'all': 1362 for atom in self.atoms(): 1363 atom.refinement_flags = atomrefinement 1364 else: 1365 atom = self.atom(atomlabel) 1366 atom.refinement_flags = atomrefinement 1221 1367 elif key == "LeBail": 1222 1368 hists = self.data['Histograms'] … … 1247 1393 raise ValueError("Unknown key:", key) 1248 1394 1395 1396 ########################## 1397 # Command Line Interface # 1398 ########################## 1399 1400 1401 def create(*args): 1402 """The create subcommand. 1403 1404 Should be passed all the command-line arguments after `create`""" 1405 proj = G2Project(filename=args[0]) 1406 1407 isPhase = False 1408 isPowderData = False 1409 isInstPrms = False 1410 instPrms = None 1411 1412 # TODO how to associate phase with histogram? 1413 for arg in args[1:]: 1414 if arg == '--phases': 1415 isPhase = True 1416 isPowderData = False 1417 isInstPrms = False 1418 elif arg == '--powder': 1419 isPhase = False 1420 isPowderData = True 1421 isInstPrms = False 1422 # Instrument parameters must be specified before 1423 # any powder data files are passed 1424 elif arg == '--iparams': 1425 isPhase = False 1426 isPowderData = False 1427 isInstPrms = True 1428 elif isPhase: 1429 proj.add_phase(arg) 1430 elif isPowderData: 1431 proj.add_powder_histogram(arg, instPrms) 1432 elif isInstPrms: 1433 instPrms = arg 1434 isInstPrms = False 1435 else: 1436 print("Not sure what to do with: {}".format(arg)) 1437 1438 proj.save() 1439 1440 1441 def dump(*args): 1442 """The dump subcommand""" 1443 import IPython.lib.pretty as pretty 1444 proj, nameList = LoadDictFromProjFile(args[0]) 1445 print("names:", nameList) 1446 for key, val in proj.items(): 1447 print(key, ":", sep='') 1448 pretty.pprint(val) 1449 1450 1451 def refine(*args): 1452 """The refine subcommand""" 1453 proj = G2Project(args[0]) 1454 proj.refine() 1455 1456 1457 def seqrefine(*args): 1458 """The seqrefine subcommand""" 1459 pass 1460 1461 1462 def export(*args): 1463 pass 1464 1465 1466 subcommands = {"create": create, 1467 "dump": dump, 1468 "refine": refine, 1469 "seqrefine": seqrefine, 1470 "export": export} 1471 1472 1249 1473 def main(): 1250 1474 '''TODO: the command-line options need some thought 1251 1475 ''' 1252 arg = sys.argv 1253 print(arg) 1254 if len(arg) > 1: 1255 GPXfile = arg[1] 1256 if not ospath.exists(GPXfile): 1257 print(u'ERROR - '+GPXfile+u" doesn't exist!") 1258 exit() 1259 Project,nameList = LoadDictFromProjFile(GPXfile) 1260 SaveDictToProjFile(Project,nameList,'testout.gpx') 1476 argv = sys.argv 1477 if len(argv) > 1 and argv[1] in subcommands: 1478 subcommands[argv[1]](*argv[2:]) 1479 elif len(argv) == 1 or argv[1] in ('help', '--help', '-h'): 1480 # TODO print usage 1481 subcommand_names = ' | '.join(subcommands.keys()) 1482 print("USAGE: {} [ {} ] ...".format(argv[0], subcommand_names)) 1261 1483 else: 1262 print('ERROR - missing filename') 1263 exit() 1264 print("Done") 1265 1484 print("Unknown subcommand: {}".format(argv[1])) 1485 print("Available subcommands:") 1486 for name in subcommands.keys(): 1487 print("\t{}".format(name)) 1488 sys.exit(-1) 1489 # arg = sys.argv 1490 # print(arg) 1491 # if len(arg) > 1: 1492 # GPXfile = arg[1] 1493 # if not ospath.exists(GPXfile): 1494 # print(u'ERROR - '+GPXfile+u" doesn't exist!") 1495 # exit() 1496 # Project,nameList = LoadDictFromProjFile(GPXfile) 1497 # SaveDictToProjFile(Project,nameList,'testout.gpx') 1498 # else: 1499 # print('ERROR - missing filename') 1500 # exit() 1501 # print("Done") 1502 1503 PwdrDataReaders = G2fil.LoadImportRoutines("pwd", "Powder_Data") 1504 PhaseReaders = G2fil.LoadImportRoutines("phase", "Phase") 1266 1505 if __name__ == '__main__': 1267 PwdrDataReaders = G2fil.LoadImportRoutines("pwd", "Powder_Data")1268 PhaseReaders = G2fil.LoadImportRoutines("phase", "Phase")1269 1506 main() 1270 1507 … … 1318 1555 # print(key, ":", sep='') 1319 1556 # pretty.pprint(val) 1320 1557
Note: See TracChangeset
for help on using the changeset viewer.