Changeset 5118
- Timestamp:
- Dec 23, 2021 6:00:10 PM (8 months ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/GSASIIconstrGUI.py
r5082 r5118 750 750 errmsg,warnmsg = CheckConstraints(G2frame,Phases,Histograms,data,[],reqVaryList,seqhst=seqhistnum,seqmode=seqmode) 751 751 except Exception as msg: 752 if GSASIIpath.GetConfigValue('debug'): 753 import traceback 754 print (traceback.format_exc()) 752 755 return 'CheckConstraints error retrieving parameter\nError='+str(msg),'' 753 756 return errmsg,warnmsg … … 1258 1261 panel.delBtn.checkboxList.append([constDel,Id,name]) 1259 1262 if refineflag: 1260 ch = G2G.G2CheckBox(panel,'vary ',item,-2) 1263 refresh = lambda event: wx.CallAfter(UpdateConstraints, G2frame, data, G2frame.constr.GetSelection(), True) 1264 ch = G2G.G2CheckBox(panel,'vary ',item,-2,OnChange=refresh) 1261 1265 constSizer.Add(ch,0,wx.LEFT|wx.RIGHT|WACV|wx.ALIGN_CENTER,1) 1262 1266 else: … … 1384 1388 btn.Bind(wx.EVT_BUTTON,lambda event: 1385 1389 G2G.ShowScrolledInfo(panel, 1386 ' Constraints after processing\n\n'+G2mv.VarRemapShow(),1390 '*** Constraints after processing ***\n'+G2mv.VarRemapShow(), 1387 1391 header='Generated constraints')) 1388 1392 panel.delBtn = wx.Button(panel, wx.ID_ANY, 'Delete selected') -
trunk/GSASIIdataGUI.py
r5106 r5118 5297 5297 for key in ('parmMinDict','parmMaxDict','parmFrozen'): 5298 5298 if key not in Controls: Controls[key] = {} 5299 G2mv.Map2Dict(parmValDict,G2mv.saveVaryList) 5299 5300 wx.EndBusyCursor() 5300 5301 # # check for limits on dependent vars … … 5318 5319 # imp.reload(G2G) 5319 5320 # end debug stuff 5320 dlg = G2G.ShowLSParms(self,'Least Squares Parameters',parmValDict, varyList,reqVaryList,Controls)5321 dlg = G2G.ShowLSParms(self,'Least Squares Parameters',parmValDict,G2mv.saveVaryList,reqVaryList,Controls) 5321 5322 dlg.CenterOnParent() 5322 5323 dlg.ShowModal() -
trunk/GSASIImapvars.py
r5110 r5118 507 507 508 508 This is done by creating a square matrix from the group using 509 :func:`_FillArray` with parameter ``FillDiagonals=False`` (the default). Any 510 unspecified rows are left as all zero. The first Nc rows in the 511 array are then coverted to row-echelon form using :func:`_RowEchelon`. This 512 will create an Exception if any two rows are linearly dependent (which means 513 that no matter what values are used for the remaining rows, that the matrix 514 will be singular). :func:`_FillArray` is then called with parameter 515 ``FillDiagonals=True``, which again creates a square matrix but where 516 unspecified rows are zero except for the diagonal elements. The 509 :func:`_FillArray`. The top Nc rows in the matrix are filled 510 as described above. Then :func:`_RowEchelon` is used to see if 511 those entries in the matrix can be coverted to row-echelon form. This 512 will raise an Exception there is linear dependence between the initial Nc rows 513 (which means that no matter what values are used for any remaining rows, that the matrix 514 will be singular). If that is not the case and Nc<Np then any remaining rows that 515 were not specified are filled in. For each of these rows, first only the 516 diagonal element in that row of the matrix is set to 1 517 and the upper portion of the matrix is again tested with :func:`_RowEchelon` 518 to check for linear independence. This is likely to be non-singular, 519 but should :func:`_RowEchelon` fail, 520 :func:`_FillArray` will then try setting each other element in that row to either 521 1 or -1. One of those options should be linearly independent from every other 522 row of the matrix. 523 524 The 517 525 `Gram-Schmidt process <http://en.wikipedia.org/wiki/Gram-Schmidt>`_, 518 526 implemented in :func:`GramSchmidtOrtho`, is used to find orthonormal unit 519 vectors for the remaining Np-Nc rows of the matrix. This will fail with 520 a ``ConstraintException`` if this is not possible (singular matrix) or 521 the result is placed in :data:`constrArr` as a numpy array. 527 vectors which are used to replace the remaining Np-Nc rows of the matrix. This will fail with 528 a ``ConstraintException`` if this is not possible (singular matrix), but that would be 529 unexpected since the matrix could be converted to row-echelon form. The 530 Gram-Schmidt result is placed in :data:`constrArr` as a numpy array. 522 531 523 532 Rows in the matrix corresponding to "New Var" constraints and those that 524 were generated by the Gram-Schmidt process are provided with parameter names 525 (this can be specified if a "New Var" entry by using a ``"_name"`` element 526 in the constraint dict, but at present this is not implemented.) Names are527 generated using :data:`paramPrefix` which is set to ``"::constr"``, plus a528 number to make the new parameter name unique. 533 were generated by the Gram-Schmidt process are provided with parameter names. 534 These names are generated using :data:`paramPrefix`, which is set to ``"::constr"``, 535 plus a number to make the new parameter name unique, 536 unless a name was specified for the 537 "New Var" entry by using a ``"_name"`` element in the constraint dict. 529 538 530 539 Finally the parameters used as input to the constraint are placed in … … 609 618 **Mixing Hold (Fixed) parameters in equivalences** 610 619 611 * If one parameter is designated as a "Hold" in an equivalence, then all parameters in that620 * If one parameter (or more) is designated as a "Hold" in an equivalence, then all parameters in that 612 621 equivalence cannot be varied. Considering this equivalence:: 613 622 … … 660 669 These globals are expected to be used only by this module's (:mod:`GSASIImapvars`) internal routines. 661 670 671 Lists with information from Constraint Equation and New Var constraints. Each entry 672 in these variables is related to a group of constraints. 662 673 663 674 .. tabularcolumns:: |l|p{4.5in}| … … 667 678 ============================= =================================================================== 668 679 :data:`dependentParmList` a list containing group of lists of 669 parameters used in the group. Note that parameters listed in 680 parameters used in the group. 681 The columns of the matrices in :data:`arrayList` match 682 the order of parameters here. 683 Note that parameters listed in 670 684 dependentParmList will not be included in the Hessian as their 671 685 derivatives will not affect the model 672 686 673 :data:`indParmList` a list containing groups of Independent parameters defined in 674 each group. This contains both parameters used in parameter 675 redefinitions as well as names of generated new parameters. 687 :data:`indParmList` a list containing groups of variables or constants matching 688 the columns of the matrices in :data:`invarrayList`. 676 689 677 690 :data:`arrayList` a list containing group of relationship matrices to relate … … 681 694 parameters in indParmList to those in dependentParmList. 682 695 Unlikely to be used externally. 683 684 :data:`holdParmList` a list of parameters that have been marked as "Hold".685 Unlikely to be used externally. Holds have a single686 entry in the indParmList parameter list.687 Set in :func:`StoreHold`. (Also see :data:`newHolds`)688 696 689 697 :data:`symGenList` a list of boolean values that will be True to indicate … … 691 699 meaning it is generated based on symmetry, twining 692 700 or Pawley overlap. 701 ============================= =================================================================== 702 703 Lists with information from Hold and Equivalence constraints. Each entry 704 in these variables is related to a group of constraints. 705 706 .. tabularcolumns:: |l|p{4.5in}| 707 708 ============================= =================================================================== 709 variable explanation 710 ============================= =================================================================== 711 712 :data:`holdParmList` a list of parameters that have been marked as "Hold". 713 Unlikely to be used externally. 714 715 Set in :func:`StoreHold`. (Also see :data:`newHolds`) 693 716 694 717 :data:`dependentVars` a list of dependent variables in equivalences, compiled … … 696 719 Used within :func:`GetDependentVars`. 697 720 698 :data:`independentVars` a list of dependent variables in equivalences, compiled 699 from (:data:`indParmList`). 721 :data:`independentVars` a list of dependent variables in equivalences. 700 722 Used within :func:`GetIndependentVars`. 701 723 … … 772 794 #------------------------------------------------------------------------------------ 773 795 # Global vars used for storing constraints and equivalences after processing 774 # note that constraints are stored listed by contraintgroups,775 # where each constraint 776 # group contains those parameters that must be handled together796 # note that new var and constraint equations are stored together in groups, 797 # where each constraint group contains those parameters that must be handled 798 # together. Equivalences are also stored in these 777 799 778 800 dependentParmList = [] … … 781 803 indParmList = [] # a list of names for the new parameters 782 804 '''a list of lists where each item contains a list for each constraint group with 783 fixed values for constraint equations and names of generated (New Var) parameters. 805 fixed values for constraint equations and names of generated/New Var parameters. 806 In the case of equivalences, the name of a single independent parameter is stored. 784 807 ''' 785 808 arrayList = [] … … 793 816 (in :data:`dependentParmList`). 794 817 ''' 818 symGenList = [] 819 '''A list of flags that if True indicates a constraint was generated by symmetry 820 ''' 795 821 holdParmList = [] 796 822 '''List of parameters that should not be refined ("Hold"s). 797 823 Set in :func:`StoreHold`. Initialized in :func:`InitVars`. 798 '''799 symGenList = []800 '''A list of flags that if True indicates a constraint was generated by symmetry801 824 ''' 802 825 dependentVars = [] … … 825 848 826 849 #------------------------------------------------------------------------------------ 827 # global variables isused in :func:`getConstrError` to store error and warning information.850 # global variables used in :func:`getConstrError` to store error and warning information. 828 851 # set in CheckEquivalences and in GenerateConstraints 829 852 convVarList = [] … … 905 928 groups = [] # contains a list of grouplists 906 929 ParmList = [] 907 for i,cons iin enumerate(constrDict):930 for i,constrI in enumerate(constrDict): 908 931 if i in assignedlist: continue # already in a group, skip 909 932 # starting a new group 910 933 grouplist = [i,] 911 934 assignedlist.append(i) 912 groupset = set(VarKeys(cons i))935 groupset = set(VarKeys(constrI)) 913 936 changes = True # always loop at least once 914 937 while(changes): # loop until we can't find anything to add to the current group 915 938 changes = False # but don't loop again unless we find something 916 for j,cons jin enumerate(constrDict):939 for j,constrJ in enumerate(constrDict): 917 940 if j in assignedlist: continue # already in a group, skip 918 if len(set(VarKeys(cons j)) & groupset) > 0: # true if this needs to be added941 if len(set(VarKeys(constrJ)) & groupset) > 0: # true if this needs to be added 919 942 changes = True 920 943 grouplist.append(j) 921 944 assignedlist.append(j) 922 groupset = groupset | set(VarKeys(cons j))945 groupset = groupset | set(VarKeys(constrJ)) 923 946 group = sorted(grouplist) 924 947 varlist = sorted(list(groupset)) … … 931 954 :func:`ProcessConstraints` into lists ``constrDict`` and ``fixedList`` 932 955 933 This routine then calls :func:`CheckEquivalences` 934 for internalconsistency. This includes converting equivalenced variables into956 This routine then calls :func:`CheckEquivalences` for internal 957 consistency. This includes converting equivalenced variables into 935 958 constraints when a variable is used in both. 936 959 … … 994 1017 global saveVaryList 995 1018 saveVaryList = copy.copy(varyList) 1019 1020 global dependentVars # List of dependent and independent variables for all constraints 1021 global independentVars 996 1022 997 1023 errmsg = '' # save error messages here. If non-blank, constraints cannot be used. 998 1024 warning = '' # save informational text messages here. 999 1025 1000 # tabulate a list of all parameters as defined initially setting the following global variables: 1001 global depVarList # parameters used in equivalences as dependent parameters 1002 global indepVarList # parameters used in equivalences as independent parameters 1003 global constrVarList # list of parameters used in other constraints 1026 # Process the equivalences; If there are conflicting parameters, move them into constraints 1027 warning = CheckEquivalences(constrDict,varyList,fixedList,parmDict) 1028 1029 # find parameters used in constraint equations & new var assignments (all are dependent) 1030 global constrVarList 1004 1031 constrVarList = [] 1005 1032 for cdict in constrDict: 1006 1033 constrVarList += [i for i in cdict if i not in constrVarList and not i.startswith('_')] 1007 # tabulate all parameters in equivalences by type and look for repeated dependent vars1008 global depVarList,indepVarList1009 depVarList = [] # list of all dependent parameters in equivalences1010 indepVarList = [] # list of all independent parameters in equivalences1011 for cnum,(varlist,mapvars,multarr,invmultarr) in enumerate(zip(1012 dependentParmList,indParmList,arrayList,invarrayList)):1013 if multarr is not None: continue # equivalence1014 indepVarList += [mv for mv in mapvars if mv not in indepVarList]1015 depVarList += [v for v in varlist if v not in depVarList]1016 1017 # Translate & generate lookup table for wildcard parameter names (sequential fits only)1018 # TODO: where should this be done in the sequence of events? Probably here, so that1019 # variable names can be looked up in varyList properly. Also, should names be changed in place1020 # or stored in translateTable and then looked up later?1021 #translateTable = {} # lookup table for wildcard-referenced parameters1022 if SeqHist is not None:1023 for varlist,mapvars,multarr,invmultarr in zip(1024 dependentParmList,indParmList,arrayList,invarrayList):1025 for i,mv in enumerate(mapvars):1026 if mv.split(':')[1] == '*':1027 # convert wildcard var to reference current histogram; save translation in table1028 sv = mv.split(':')1029 sv[1] = str(SeqHist)1030 #mapvars[i][1] = translateTable[mv] = ':'.join(sv)1031 mapvars[i][1] = ':'.join(sv)1032 for i,(v,m) in enumerate(zip(varlist,invmultarr)):1033 if v.split(':')[1] == '*':1034 # convert wildcard var to reference current histogram; save translation in table1035 sv = v.split(':')1036 sv[1] = str(SeqHist)1037 #varlist[i] = translateTable[v] = ':'.join(sv)1038 varlist[i] = ':'.join(sv)1039 for rel in constrDict:1040 for i,var in enumerate(rel):1041 if var.startswith('_'): continue1042 if var.split(':')[1] == '*': # convert wildcard var to reference current histogram1043 sv = var.split(':')1044 sv[1] = str(SeqHist)1045 #rel[i][1] = translateTable[var] = ':'.join(sv) # add to translation in table for later use1046 rel[i][1] = ':'.join(sv)1047 1048 # Process the equivalences; If there are conflicting parameters, move them into constraints1049 warning = CheckEquivalences(constrDict,varyList,fixedList,parmDict)1050 1034 1051 1035 # look through "Constr" and "New Var" constraints looking for zero multipliers and 1052 1036 # Hold, Unvaried & Undefined parameters 1053 1037 skipList = [] 1054 for cnum,(cdict, val) in enumerate(zip(constrDict,fixedList)):1055 valid = 0 # count of good parameter 1038 for cnum,(cdict,fixVal) in enumerate(zip(constrDict,fixedList)): 1039 valid = 0 # count of good parameters 1056 1040 # error reporting 1057 1041 zeroList = [] # parameters with zero multipliers … … 1063 1047 problem = False # constraint must be dropped 1064 1048 dropList = [] # parameters to remove 1065 setAsHoldList = [] # parameters that will be held if the constraint is invalid 1066 for i,var in enumerate(cdict): 1067 if var.startswith('_'): continue 1049 for var in VarKeys(cdict): # assemble warning info 1068 1050 if cdict[var] == 0: # zero multiplier 1069 1051 if var not in zeroList: zeroList.append(var) 1070 setAsHoldList.append(var) 1071 dropList.append(var) 1072 elif var in holdParmList: # already hold 1073 #if var not in newHolds: newHolds.append(var) 1052 if var not in dropList: dropList.append(var) 1053 elif var in holdParmList: # hold invalid in New Var, drop from constraint eqn 1074 1054 holdList.append(var) 1075 dropList.append(var) 1076 elif ':*:' in var and SeqHist is None: # unvaried 1055 if fixVal is None: 1056 problem = True 1057 else: 1058 if var not in dropList: dropList.append(var) 1059 elif ':*:' in var : # wildcard still present should be treated as undefined 1060 if var not in undefinedVars: undefinedVars.append(var) 1077 1061 noWildcardList.append(var) 1078 dropList.append(var) 1079 elif var not in varyList: # unvaried 1080 if var not in unvariedParmsList: unvariedParmsList.append(var) 1081 noVaryList.append(var) 1082 setAsHoldList.append(var) 1083 dropList.append(var) 1062 problem = True 1084 1063 elif parmDict is not None and var not in parmDict: # not defined, constraint will not be used 1085 1064 if var not in undefinedVars: undefinedVars.append(var) 1086 1065 notDefList.append(var) 1087 if ':dAx:' in var or ':dAy:' in var or ':dAz:' in var: # undefined atoms 1088 dropList.append(var) # these can be ignored 1066 if ':dAx:' in var or ':dAy:' in var or ':dAz:' in var: # coordinates from undefined atoms 1067 if fixVal is None: 1068 problem = True # invalid in New Var 1069 else: 1070 if var not in dropList: dropList.append(var) # ignore in constraint eqn 1089 1071 else: 1090 1072 problem = True 1073 elif var not in varyList and fixVal is not None: # unvaried, constraint eq. only 1074 if var not in unvariedParmsList: unvariedParmsList.append(var) 1075 noVaryList.append(var) 1076 dropList.append(var) 1091 1077 else: 1092 1078 valid += 1 … … 1101 1087 if i != 0: msg += ', ' 1102 1088 msg += v 1103 warn(msg,cdict, val)1104 if not valid and (problem or len(dropList) > 0): # no valid entries1105 warn('Ignoring constraint ',cdict,val)1089 warn(msg,cdict,fixVal) 1090 if valid == 0: # no valid entries 1091 warn('Ignoring constraint, no valid entries',cdict) 1106 1092 skipList.append(cnum) 1107 1093 elif problem: # mix of valid & refined and undefined items, cannot use this 1108 warn(' Holding varied items & Dropping constraint',cdict,val)1094 warn('Invalid constraint',cdict) 1109 1095 skipList.append(cnum) 1110 newHolds += [i for i in holdListif i not in newHolds]1096 newHolds += [i for i in VarKeys(cdict) if i not in newHolds] 1111 1097 elif len(dropList) > 0: # mix of valid and problematic items, drop problem vars, but keep rest 1112 1098 if GSASIIpath.GetConfigValue('debug'): … … 1115 1101 if msg: msg += ' ,' 1116 1102 msg += v 1117 warn('removing: '+msg,cdict ,val)1103 warn('removing: '+msg,cdict) 1118 1104 value = fixedList[cnum] 1119 1105 for var in dropList: # do cleanup 1120 # TODO: evaluate expressions in constraint multipliers here? I am assuming no 1121 # as I think G2mv.EvaluateMultipliers does that already. For now assuming 1122 # otherwise; note SubfromParmDict 1123 if ':dAx:' in var or ':dAy:' in var or ':dAz:' in var: # undefined atoms can be ignored 1124 pass 1106 # NB expressions in constraint multipliers have already been evaluated 1107 if ':dAx:' in var or ':dAy:' in var or ':dAz:' in var: 1108 pass # treat delta coords as 0; no change in total is needed 1125 1109 elif cdict[var] != 0: 1126 1110 value = float(value) - cdict[var]*parmDict[var] 1127 1111 del cdict[var] 1128 if float(value) != float(fixedList[cnum]): fixedList[cnum] = str(np.round(value,12))1112 if float(value) != float(fixedList[cnum]): fixedList[cnum] = float(np.round(value,12)) 1129 1113 if GSASIIpath.GetConfigValue('debug'): 1130 1114 warn('revised as: '+_FormatConstraint(constrDict[cnum],fixedList[cnum])) … … 1145 1129 # and all newly created relationships will be varied. For NewVar constraints, 1146 1130 # vary if the vary flag was set. 1147 for group, varlist in zip(groups,parmlist):1148 if len( varlist) < len(group): # too many relationships -- no can do1131 for group,depPrmList in zip(groups,parmlist): 1132 if len(depPrmList) < len(group): # too many relationships -- no can do 1149 1133 if errmsg: errmsg += '\n' 1150 1134 errmsg += "Over-constrained input. " 1151 1135 errmsg += "There are more constraints (" + str(len(group)) 1152 errmsg += ") than parameters (" + str(len( varlist)) + ")\nin these constraints:"1136 errmsg += ") than parameters (" + str(len(depPrmList)) + ")\nin these constraints:" 1153 1137 for rel in group: 1154 1138 errmsg += '\n\t'+ _FormatConstraint(constrDict[rel],fixedList[rel]) 1155 groupErrors += varlist1139 groupErrors += depPrmList 1156 1140 continue # go on to next group 1157 1141 1158 VaryFree = False1159 for rel in group:1160 varied = 01161 for var in VarKeys(constrDict[rel]):1162 #var = translateTable.get(var,var) # replace wildcards1163 #if parmDict is not None and var not in parmDict:1164 if var in varyList: varied += 11165 if fixedList[rel] is not None and varied > 0:1166 VaryFree = True1167 1168 # fill in additional degrees of freedom1169 1142 try: 1170 arr = _FillArray(group,constrDict,varlist) 1171 _RowEchelon(len(group),arr,varlist) 1172 except: 1143 constrArr = _FillArray(group,constrDict,depPrmList) 1144 except Exception as err: 1173 1145 if errmsg: errmsg += '\n' 1174 errmsg += "\nSingular input. " 1175 errmsg += "There are internal inconsistencies in these constraints:" 1176 for rel in group: 1177 errmsg += '\n\t' + _FormatConstraint(constrDict[rel],fixedList[rel]) 1178 groupErrors += varlist 1146 if 'Initial' in str(err): 1147 errmsg += "\nSingular input. " 1148 errmsg += "There are internal inconsistencies in these constraints:" 1149 else: 1150 errmsg += "\nError expanding matrix with these constraints:" 1151 for rel in group: 1152 errmsg += '\n\t' + _FormatConstraint(constrDict[rel],fixedList[rel]) 1153 groupErrors += depPrmList 1179 1154 continue 1180 1155 1181 1156 try: 1182 constrArr = _FillArray(group,constrDict,varlist,FillDiagonals=True)1183 1157 GramSchmidtOrtho(constrArr,len(group)) 1184 1158 except: … … 1187 1161 for rel in group: 1188 1162 errmsg += '\n\t' + _FormatConstraint(constrDict[rel],fixedList[rel]) 1189 groupErrors += varlist1163 groupErrors += depPrmList 1190 1164 continue 1191 1165 1192 try: 1193 np.linalg.inv(constrArr)1166 try: 1167 invConstrArr = np.linalg.inv(constrArr) 1194 1168 except: 1195 1169 if errmsg: errmsg += '\n' … … 1201 1175 for rel in group: 1202 1176 errmsg += '\n\t' + _FormatConstraint(constrDict[rel],fixedList[rel]) 1203 groupErrors += varlist1177 groupErrors += depPrmList 1204 1178 continue 1205 1206 mapvar = [] 1207 group = group[:] 1208 # scan through all generated and input relationships, we need to add to the varied list 1209 # all the new parameters where VaryFree has been set or where a New Var is varied. 1210 # 1211 # If a group does not contain any fixed values (constraint equations) 1212 # and nothing in the group is varied, drop this group, so that the 1213 # dependent parameters can be refined individually. 1214 unused = True 1215 for i in range(len(varlist)): 1216 if len(group) > 0: # get the original equation reference 1217 rel = group.pop(0) 1218 fixedval = fixedList[rel] 1219 varyflag = constrDict[rel].get('_vary',False) 1220 varname = constrDict[rel].get('_name','') 1221 else: # this relationship has been generated 1222 varyflag = False 1223 varname = '' 1224 fixedval = None 1225 if fixedval is None: # this is a new parameter, not a constraint 1226 if not varname: 1227 varname = paramPrefix + str(consNum) # no assigned name, create one 1179 1180 # scan through current group looking for new var assignments 1181 hasNewVar = False 1182 for i,rel in enumerate(group): 1183 if fixedList[rel] is None: 1184 hasNewVar = True # there a New Var relationship in this group 1185 break 1186 else: # only constraint equations, check for unvaried parameters in 1187 unvaried = False 1188 # this should not happen as they should have been removed 1189 for var in depPrmList: 1190 if var not in varyList: 1191 unvaried = True 1192 break 1193 if unvaried: # something is not varied: skip group & remove all parameters from varyList 1194 for var in depPrmList: 1195 if var not in newHolds: newHolds.append(var) 1196 if GSASIIpath.GetConfigValue('debug'): 1197 print('Unexpected: Constraint group ignored (some parameters unvaried)') 1198 for rel in group: 1199 print (' '+_FormatConstraint(constrDict[rel],fixedList[rel])) 1200 continue 1201 maplist = [] # value or param name mapped to each row in expression matrix 1202 if not hasNewVar: # constraint equations; all remaining entries varied, vary generated 1203 for i in range(len(depPrmList)): 1204 if i >= len(group): # tag generated degrees of freedom with names and vary them 1205 varname = paramPrefix + str(consNum) # assign a unique name 1228 1206 consNum += 1 1229 mapvar.append(varname) 1230 #genVarLookup[varname] = varlist # save list of parameters related to this new var 1231 # vary the new relationship if it is a degree of freedom in 1232 # a set of contraint equations or if a New Var is flagged to be varied. 1233 if VaryFree or varyflag: 1234 unused = False 1207 maplist.append(varname) 1235 1208 varyList.append(varname) 1236 # fix (prevent varying) of all the parameters inside the constraint group 1237 # (dependent vars) 1238 for var in varlist: 1239 if var in varyList: varyList.remove(var) 1240 else: 1241 unused = False 1242 mapvar.append(float(fixedval)) 1243 if unused: # skip over constraints that don't matter (w/o fixed value or any refined parameters) 1244 if GSASIIpath.GetConfigValue('debug'): 1245 print('Unexpected: Constraint ignored (all parameters unvaried)') 1246 print (' '+_FormatConstraint(constrDict[rel],fixedList[rel])) 1247 continue 1248 #dependentParmList.append([translateTable.get(var,var) for var in varlist]) 1249 dependentParmList.append(varlist) 1209 else: 1210 maplist.append(fixedList[rel]) 1211 else: # ------------------------- groups with new var assignments, vary only NV's w/flags set 1212 for i,rel in enumerate(group): 1213 if fixedList[rel] is None: 1214 varname = constrDict[rel].get('_name','::?????') 1215 maplist.append(varname) 1216 if constrDict[rel].get('_vary',False): 1217 varyList.append(varname) 1218 else: 1219 maplist.append(fixedList[rel]) # constraint equation 1220 for i in range(len(depPrmList)): 1221 if i >= len(group): # name generated degrees of freedom 1222 varname = paramPrefix + str(consNum) # assign a unique name 1223 consNum += 1 1224 maplist.append(varname) 1225 for var in depPrmList: 1226 if var not in newHolds: newHolds.append(var) 1227 # keep this group 1228 dependentParmList.append(depPrmList) 1250 1229 arrayList.append(constrArr) 1251 invarrayList.append( np.linalg.inv(constrArr))1252 indParmList.append(map var)1230 invarrayList.append(invConstrArr) 1231 indParmList.append(maplist) 1253 1232 symGenList.append(False) 1233 1254 1234 if errmsg and SeqHist is not None: 1255 1235 print (' *** ERROR in constraint definitions! ***') … … 1262 1242 return errmsg,warning,None,None 1263 1243 1264 # Make list of dependent and independent variables (after possibly dropping unused vars) 1265 global dependentVars 1266 global independentVars 1244 # Make list of dependent and independent variables for all constraints 1267 1245 dependentVars = [] 1268 1246 independentVars = [] … … 1273 1251 for mv in varlist: 1274 1252 if mv not in dependentVars: dependentVars.append(mv) 1275 saveVaryList = copy.copy(varyList) 1253 if mv not in newHolds: newHolds.append(mv) 1254 saveVaryList = copy.copy(varyList) # save varyList so it can be used within module 1276 1255 1277 1256 # if equivMoved: … … 1331 1310 removeList = [] # equivalences that are not needed 1332 1311 convertList = [] # equivalences that should be converted to "Const" constraints 1312 1313 # tabulate parameters used in equivalences by type 1314 depVarList = [] # list of all dependent parameters in equivalences 1315 indepVarList = [] # list of all independent parameters in equivalences 1316 for cnum,(varlist,mapvars,multarr,invmultarr) in enumerate(zip( 1317 dependentParmList,indParmList,arrayList,invarrayList)): 1318 #if multarr is not None: continue # equivalence 1319 indepVarList += [mv for mv in mapvars if mv not in indepVarList] 1320 depVarList += [v for v in varlist if v not in depVarList] 1333 1321 1334 1322 # process equivalences: make a list of dependent and independent vars … … 1420 1408 else: 1421 1409 msg = 'All parameters set as "Hold". ' 1422 msg += " Ignoring equivalence"1410 msg += "\n Ignoring equivalence" 1423 1411 warn(msg,cnum) 1424 1412 removeList.append(cnum) … … 1446 1434 else: 1447 1435 msg = 'No parameters varied. ' 1448 msg += " Ignoring equivalence"1436 msg += "\n Ignoring equivalence" 1449 1437 warn(msg,cnum) 1450 1438 removeList.append(cnum) … … 1545 1533 :param str seqmode: one of 'use-all', 'wildcards-only' or 'auto-wildcard'. 1546 1534 When seqmode=='wildcards-only' then any constraint with a numerical 1547 constraintnumber is skipped. With seqmode=='auto-wildcard',1535 histogram number is skipped. With seqmode=='auto-wildcard', 1548 1536 any non-null constraint number is set to the selected histogram. 1549 1537 :param int seqhst: number for current histogram (used for … … 1564 1552 namedVarList = [] 1565 1553 for constr in constList: 1566 terms = copy.deepcopy(constr[:-3]) 1554 terms = copy.deepcopy(constr[:-3]) # don't change the tree contents 1555 # deal with wildcards in sequential fits 1567 1556 if seqmode == 'wildcards-only' and seqhst is not None: 1568 1557 skip = False … … 1576 1565 for term in terms: 1577 1566 term[1] = term[1].varname(seqhst) 1578 el se:1567 elif seqhst is not None: 1579 1568 for term in terms: 1580 if term[1].histogram == '*' and seqhst is not None:1569 if term[1].histogram == '*': 1581 1570 term[1] = term[1].varname(seqhst) 1582 else:1583 term[1] = term[1].varname()1584 1571 # else: 1572 # term[1] = term[1].varname() # does this change anything??? 1573 # separate processing by constraint type 1585 1574 if constr[-1] == 'h': 1586 1575 # process a hold 1587 var = str( constr[0][1])1576 var = str(term[0][1]) 1588 1577 if '?' not in var: 1589 1578 StoreHold(var) … … 1602 1591 if len(D) > 1: 1603 1592 # add extra dict terms for input variable name and vary flag 1604 if varname is not None: 1593 if varname is None: # no assigned name, create one 1594 global consNum 1595 varname = str(consNum) 1596 consNum += 1 1597 else: 1605 1598 varname = str(varname) # in case this is a G2VarObj 1606 if varname.startswith(':'):1607 D['_name'] = varname1608 1609 1610 1599 if '::' in varname: 1600 D['_name'] = varname.replace('::','::nv-') 1601 else: 1602 D['_name'] = '::nv-' + varname 1603 D['_name'] = G2obj.MakeUniqueLabel(D['_name'],namedVarList) 1611 1604 D['_vary'] = varyFlag == True # force to bool 1612 1605 constrDict.append(D) … … 1615 1608 #constFlag[-1] = ['Vary'] 1616 1609 elif constr[-1] == 'c': 1617 # process a con traint relationship1610 # process a constraint equation 1618 1611 D = {} 1619 1612 for term in terms: … … 1622 1615 D[var] = term[0] 1623 1616 if len(D) >= 1: 1624 fixedList.append( str(constr[-3]))1617 fixedList.append(float(constr[-3])) 1625 1618 constrDict.append(D) 1626 1619 else: … … 2027 2020 elif v in undefinedVars: 2028 2021 undef.append(str(v)) 2029 elif v in unvariedParmsList :2022 elif v in unvariedParmsList and not (constrLst[-1] == 'f' and constrLst[-2]): 2030 2023 unvar.append(str(v)) 2031 2024 elif v in holdParmList: … … 2172 2165 s = '' 2173 2166 if len(holdParmList) > 0: 2174 s += ' User-supplied Fixed Parameters:\n'2167 s += '\nUser-supplied Fixed Parameters:\n' 2175 2168 for v in holdParmList: 2176 2169 s += ' ' + v + '\n' 2177 2170 if len(newHolds) > 0: 2178 s += 'Additional Fixed Parameters:\n' 2171 s1 = '' 2172 s2 = '' 2179 2173 for v in newHolds: 2180 s += ' ' + v + '\n' 2174 if v in dependentVars: 2175 s1 += ' ' + v + '\n' 2176 else: 2177 s2 += ' ' + v + '\n' 2178 if s2: 2179 s += '\nParameters to be Fixed based on constraints:\n' 2180 s += s2 2181 if s1: 2182 s += '\nDependent parameters with values to be set from constraints:\n' 2183 s += s1 2181 2184 userOut = '' 2182 2185 symOut = '' 2183 2186 consOut = '' 2184 2187 varOut = '' 2188 freeOut = '' 2185 2189 global dependentParmList,arrayList,invarrayList,indParmList,symGenList 2186 2190 … … 2208 2212 userOut += s1 + '\n' 2209 2213 continue 2210 if mv in varyList: 2211 lineOut = ' {} (**Varied**) = '.format(mv) 2212 else: 2213 lineOut = ' {} = '.format(mv) 2214 ln = '' 2215 # if mv in varyList: 2216 # lineOut = ' (V)* {} = '.format(mv) 2217 # else: 2218 # lineOut = ' {} = '.format(mv) 2214 2219 j = 0 2220 lineOut = ' {} = '.format(mv) 2215 2221 for (m,v) in zip(multarr[i,:],varlist): 2216 2222 if m == 0: continue … … 2221 2227 lineOut += ' + ' 2222 2228 j += 1 2223 if len(lineOut) > 60 and type(mv) is float: 2224 consOut += lineOut 2225 lineOut = '\n\t' 2226 elif len(lineOut) > 60: 2227 varOut += lineOut 2229 if len(lineOut) > 60: 2230 ln += lineOut 2228 2231 lineOut = '\n\t' 2229 2232 if m == 1: … … 2231 2234 else: 2232 2235 lineOut += '({:.4g} * {})'.format(m,v) 2233 if type(mv) is not float: 2234 varOut += lineOut + '\n' 2236 if mv in varyList: 2237 lineOut += ' **VARIED**' 2238 ln += lineOut 2239 2240 if type(mv) is float: 2241 consOut += ln + '\n' 2242 elif '::nv-' in mv: 2243 varOut += ln + '\n' 2235 2244 else: 2236 consOut += lineOut+ '\n'2245 freeOut += ln + '\n' 2237 2246 if userOut: 2238 s += '\n User-supplied equivalences:\n' + userOut2247 s += '\nEquivalences:\n' + userOut 2239 2248 if consOut: 2240 s += '\n User-supplied Constraints:\n' + consOut2249 s += '\nConstraint Equations:\n' + consOut 2241 2250 if varOut: 2242 s += '\nUser-input generated New Variables:\n' + varOut 2251 s += '\nNew Variable assignments:\n' + varOut 2252 if freeOut: 2253 s += '\nGenerated Degrees of Freedom:\n' + freeOut 2243 2254 if symOut: 2244 2255 s += '\nSymmetry-generated equivalences:\n' + symOut … … 2371 2382 if debug: print ('start dMdv',dMdv[varyList.index(name)]) 2372 2383 if debug: print ('add derv',v,'*',m,'to derv',name,'add=',m * derivDict[v]) 2373 if m == 0 : continue2384 if m == 0 or name not in varyList: continue 2374 2385 dMdv[varyList.index(name)] += m * derivDict[v] 2375 2386 … … 2402 2413 global dependentParmList,arrayList,invarrayList,indParmList 2403 2414 for varlist,mapvars,multarr,invmultarr in zip(dependentParmList,indParmList,arrayList,invarrayList): 2404 for item in varlist: 2415 for item in varlist: # TODO: is this still needed? 2405 2416 if item in varyList: varyList.remove(item) 2406 2417 if multarr is None: … … 2417 2428 for varlist,mapvars,multarr in zip(dependentParmList,indParmList,arrayList): 2418 2429 if multarr is None: continue 2419 # evaluate all constraints in the forward direction 2420 for key,value in zip(mapvars,np.dot(multarr,np.array([parmDict[var] for var in varlist]))): 2421 if type(key) is float: continue 2422 #print('parmDict set',key,':',value) 2423 parmDict[key] = value 2430 # evaluate constraints in the forward direction 2431 z = zip(mapvars,np.dot(multarr,np.array([parmDict[var] for var in varlist]))) 2432 # add/replace in parameter dict 2433 parmDict.update([i for i in z if type(i[0]) is not float]) 2424 2434 global saveVaryList 2425 2435 saveVaryList = copy.copy(varyList) … … 2472 2482 return a 2473 2483 2474 def _FillArray(sel,dict,collist,FillDiagonals=False): 2475 '''Construct a n by n matrix (n = len(collist) 2476 filling in the rows using the relationships defined 2477 in the dictionaries selected by sel 2478 2479 If FillDiagonals is True, diagonal elements in the 2480 array are set to 1.0 2484 def _FillArray(sel,d,collist): 2485 '''Construct a n by n matrix [n = len(collist)] 2486 with the initial m rows [m = len(sel)] using the 2487 relationships defined in the expressions dict, d. 2488 Since m may be smaller than n, the remaining rows 2489 are filled with rows that are tested to not create 2490 a singular matrix. 2491 2492 :param list sel: a list of indices in dict d 2493 :param list d: a list of dict's where each dict describes an 2494 expression from a constraint equation or a new var 2495 :param list collist: a list parameter names. 2496 :returns: an n by n numpy.array matrix 2481 2497 ''' 2482 2498 n = len(collist) 2483 if FillDiagonals: 2484 arr = np.eye(n) 2485 else: 2486 arr = np.zeros(2*[n,]) 2499 m = len(sel) 2500 arr = np.zeros(2*[n,]) 2487 2501 # fill the top rows 2488 2502 for i,cnum in enumerate(sel): 2489 2503 for j,var in enumerate(collist): 2490 arr[i,j] = dict[cnum].get(var,0) 2504 arr[i,j] = d[cnum].get(var,0) 2505 try: 2506 _RowEchelon(m,copy.copy(arr),collist) 2507 except: 2508 raise Exception('Initial constraints singular') 2509 for i in range(m,n): 2510 arr[i][i] = 1 # add a diagonal element 2511 try: 2512 _RowEchelon(i+1,copy.copy(arr),collist) 2513 continue 2514 except: 2515 pass 2516 for j in range(n): 2517 if j == i: continue 2518 arr[i][j] = 1 # add another element 2519 try: 2520 _RowEchelon(i+1,copy.copy(arr),collist) 2521 break 2522 except: 2523 pass 2524 arr[i][j] = -1 # try a different valuefor this element 2525 try: 2526 _RowEchelon(i+1,copy.copy(arr),collist) 2527 break 2528 except: 2529 arr[i][j] = 0 # reset to add another element 2530 else: 2531 raise Exception('Unable to create non-singular matrix') 2491 2532 return arr 2492 2533 … … 2521 2562 2522 2563 if __name__ == "__main__": 2564 d = [{'a': 0, 'b': 1.5,'d':0}, {'d': -1}] 2565 lbls = ['a','c','b','d'] 2566 sel = (0,1) 2567 try: 2568 arr2 = _FillArray(sel,d,lbls) 2569 except Exception as err: 2570 if 'Initial' in str(err): 2571 print('initial error') 2572 else: 2573 print('unable to extend matrix error') 2574 import sys; sys.exit() 2575 print(arr2) 2576 2577 d = [{'a': 1, 'b': 1,}] 2578 lbls = ['a','b'] 2579 sel = (0,) 2580 arr1 = _FillArray(sel,d,lbls) 2581 print(arr1) 2582 print(GramSchmidtOrtho(arr1,1)) 2583 2584 import sys; sys.exit() 2585 2523 2586 parmdict = {} 2524 2587 constrDict = [ -
trunk/GSASIIobj.py
r5110 r5118 1991 1991 'RBR([TLS])([123AB][123AB])' : 'Residue rigid body group disp. param.', 1992 1992 'RBRU' : 'Residue rigid body group Uiso param.', 1993 'constr([0-9]*)' : ' Parameterfrom constraint',1994 'nv-( [^_]+)_*' : 'New variable constraint parameter named\\1',1993 'constr([0-9]*)' : 'Generated degree of freedom from constraint', 1994 'nv-(.+)' : 'New variable assignment with name \\1', 1995 1995 # supersymmetry parameters p::<var>:a:o 'Flen','Fcent'? 1996 1996 'mV([0-2])$' : 'Modulation vector component \\1',
Note: See TracChangeset
for help on using the changeset viewer.