Skip to content

Commit 98c08c9

Browse files
committed
implement mag constraints w/CIF import from ISO; remove duplicate constraints; improve constraint error & warning msgs
1 parent ac70c72 commit 98c08c9

5 files changed

Lines changed: 717 additions & 645 deletions

File tree

GSASII/GSASIIconstrGUI.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1916,14 +1916,16 @@ def SetUniqAj(pId,iA,SGData):
19161916
G2lat.cell2A(oldPhase['General']['Cell'][1:7]),
19171917
oldPhase['General']['SGData'],
19181918
newPhase['General']['SGData'],debug=False)
1919+
detTrans = np.abs(nl.det(Trans)) # volume ratio
1920+
#Vratio = newPhase['General']['Cell'][7]/oldPhase['General']['Cell'][7]
19191921

19201922
# create constraints on HAP Scale, Isotropic size and mustrain
19211923
# (anisotropic constraints would be more complex)
19221924
UseList = newPhase['Histograms']
19231925
Histograms, Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
19241926
for hId,hist in enumerate(UseList):
19251927
hRanId = Histograms[hist]['ranId']
1926-
constrList = G2lat.GenHAPConstraints(Trans,oRanId,nRanId,hRanId)
1928+
constrList = G2lat.GenHAPConstraints(detTrans,oRanId,nRanId,hRanId)
19271929
constraints['HAP'] += constrList
19281930

19291931
#### Rigid bodies #############################################################

GSASII/GSASIIdataGUI.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import re
1818
import numpy as np
1919
import numpy.ma as ma
20+
import numpy.linalg as nl
2021
import matplotlib as mpl
2122
try:
2223
import OpenGL as ogl
@@ -1364,6 +1365,52 @@ def OnImportPhase(self,event):
13641365
Constraints['_Explain'].update(i)
13651366
else:
13661367
Constraints['Phase'].append(i)
1368+
# make ISODISTORT magnetic phase constraints here
1369+
Phases = self.GetPhaseData()
1370+
prevPhases = list(Phases.keys())
1371+
parentPhase = None
1372+
Vratio = None
1373+
if ('ISODISTORT' in rd.Phase and
1374+
'XformInfo' in rd.Phase['ISODISTORT'] and
1375+
PhaseName in prevPhases and len(prevPhases) > 1):
1376+
Trans = rd.Phase['ISODISTORT']['XformInfo'].get('Trans',np.eye(3))
1377+
Vec = rd.Phase['ISODISTORT']['XformInfo'].get('offset',[0,0,0])
1378+
prevPhases.pop(prevPhases.index(PhaseName))
1379+
if len(prevPhases) == 1:
1380+
parentPhase = prevPhases[0]
1381+
else:
1382+
dlg = G2G.G2SingleChoiceDialog(self,
1383+
f'Select parent phase to {PhaseName}',
1384+
'Select phase',prevPhases)
1385+
dlg.CenterOnParent()
1386+
if dlg.ShowModal() == wx.ID_OK:
1387+
sel = dlg.GetSelection()
1388+
parentPhase = prevPhases[sel]
1389+
dlg.Destroy()
1390+
else:
1391+
dlg.Destroy()
1392+
if parentPhase:
1393+
oldPhase = Phases[parentPhase]
1394+
newPhase = Phases[PhaseName]
1395+
oRanId = oldPhase['ranId']
1396+
nRanId = newPhase['ranId']
1397+
Vratio = np.abs(nl.det(Trans)) # volume ratio
1398+
#Vratio = newPhase['General']['Cell'][7]/oldPhase['General']['Cell'][7]
1399+
debug = True
1400+
# create constraints relating two unit cells
1401+
Constraints['Phase'] += G2lat.GenCellConstraints(Trans,oRanId,nRanId,
1402+
G2lat.cell2A(oldPhase['General']['Cell'][1:7]),
1403+
oldPhase['General']['SGData'],
1404+
newPhase['General']['SGData'],debug)
1405+
# create constraints relating the atoms in newPhase to their positions in the chemical cell
1406+
constr,message = G2lat.MatchGenAtomConstraints(
1407+
oldPhase,newPhase,Trans,[0,0,0],Vec)
1408+
if message:
1409+
wx.MessageDialog(self,message,
1410+
'Constraint Gen. Problem',style=wx.ICON_INFORMATION).ShowModal()
1411+
1412+
Constraints['Phase'] += constr
1413+
13671414
if not newPhaseList: return # somehow, no new phases
13681415
# get a list of existing histograms
13691416
PWDRlist = []
@@ -1434,7 +1481,12 @@ def OnImportPhase(self,event):
14341481
data['Histograms'][histoName] = G2mth.SetDefaultDData(Inst['Type'][0],histoName,NShkl=NShkl,NDij=NDij)
14351482
else:
14361483
raise Exception('Unexpected histogram '+histoName)
1484+
14371485
Histograms,Phases = self.GetUsedHistogramsAndPhasesfromTree() # reindex
1486+
if Vratio: # make HAP constraints for ISODISTORT mag phase
1487+
for hist in data['Histograms']:
1488+
hRanId = Histograms[hist]['ranId']
1489+
Constraints['HAP'] += G2lat.GenHAPConstraints(Vratio,oRanId,nRanId,hRanId)
14381490
wx.EndBusyCursor()
14391491
self.EnableRefineCommand()
14401492

GSASII/GSASIIlattice.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -878,25 +878,24 @@ def GenCellConstraints(Trans,oRanId,nRanId,origA,oSGLaue,nSGLaue,debug=False):
878878
print('xfm cell',fmt4(A2cell(Anew)))
879879
return constrList
880880

881-
def GenHAPConstraints(Trans,oRanId,nRanId,hRanId):
882-
'''Generate the HAP constraints between two phase constants
883-
for a phase transformed by matrix Trans.
881+
def GenHAPConstraints(Vratio,oRanId,nRanId,hRanId):
882+
'''Generate the HAP constraints between two phases: the original
883+
chemical (nuclear) phase and the new, magnetic phase.
884884
885-
:param np.array Trans: a 3x3 direct cell transformation matrix where,
886-
Trans = np.array([ [2/3, 4/3, 1/3], [-1, 0, 0], [-1/3, -2/3, 1/3] ])
887-
(for a' = 2/3a + 4/3b + 1/3c; b' = -a; c' = -1/3, -2/3, 1/3)
885+
:param float Vratio: the ratio of the volume of the magnetic phase
886+
divided by the original phase. This should be 1 or >1 [often 2
887+
or sqrt(2) etc.]
888888
:param int oRanId: Random id for the original phase
889-
:param int nRanId: Random id for the transformed phase to be constrained from
890-
original phase
889+
:param int nRanId: Random id for the transformed (magnetic) phase to
890+
be constrained to match the original phase
891891
:param str hRanId: histogram Random Id
892892
:returns: a list of generated constraints
893893
'''
894894
from . import GSASIIobj as G2obj
895895
constrList = []
896-
detTrans = np.abs(nl.det(Trans)) # volume ratio
897896
# Phase fractions (note volume term)
898897
IndpCon = [1.0,G2obj.G2VarObj([oRanId,hRanId,'Scale',None])]
899-
DepCons = [detTrans,G2obj.G2VarObj([nRanId,hRanId,'Scale',None])]
898+
DepCons = [Vratio,G2obj.G2VarObj([nRanId,hRanId,'Scale',None])]
900899
constrList.append([IndpCon,DepCons,None,None,'e'])
901900
# Isotropic size and mustrain (anisotropic constraints are messy)
902901
for name in ['Size;i','Mustrain;i']:

GSASII/GSASIImapvars.py

Lines changed: 70 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -254,10 +254,24 @@ def warn(msg,cdict=None,val=None,prefix=None):
254254
if '_vary' in cdict:
255255
warninfo['msg'] += prefix + 'new var expression: ' + _FormatConstraint(cdict,cdict.get('_name','New Var'))
256256
else:
257-
warninfo['msg'] += prefix + 'constraint equation: ' + _FormatConstraint(cdict,val)
257+
warninfo['msg'] += prefix + 'constraint equation:\n\t' + _FormatConstraint(cdict,val)
258258
if warninfo['msg']: warninfo['msg'] += '\n'
259259
warninfo['msg'] += ' ' + msg
260-
260+
def showChanged(group):
261+
errmsg = ''
262+
changed = False
263+
for rel in group:
264+
orel = OrigSeq[rel]
265+
if constrDict[rel] != OrigConstrDict[orel]: changed = True
266+
if changed:
267+
errmsg += '\n\nNote that these constraints were changed (due\n'
268+
errmsg += 'to unrefined parameters?) Original constraints:\n'
269+
for rel in group:
270+
orel = OrigSeq[rel]
271+
errmsg += '\n\t' + _FormatConstraint(OrigConstrDict[orel],OrigFixedList[orel])
272+
errmsg += '\n\nSee the Warnings for details on unrefined parameters.\n'
273+
return errmsg
274+
261275
global dependentParmList,arrayList,invarrayList,indParmList,consNum
262276
# lists of parameters used for error reporting
263277
global undefinedVars # parameters that are used in equivalences but are not defined
@@ -284,6 +298,9 @@ def warn(msg,cdict=None,val=None,prefix=None):
284298
# Hold, Unvaried & Undefined parameters
285299
skipList = []
286300
invalidParms = []
301+
OrigConstrDict = copy.deepcopy(constrDict)
302+
OrigFixedList = copy.deepcopy(fixedList)
303+
OrigSeq = list(range(len(constrDict)))
287304
for cnum,(cdict,fixVal) in enumerate(zip(constrDict,fixedList)):
288305
#constrVarList += [i for i in cdict if i not in constrVarList and not i.startswith('_')]
289306
valid = 0 # count of good parameters
@@ -334,11 +351,11 @@ def warn(msg,cdict=None,val=None,prefix=None):
334351
notDefList = []
335352

336353
if noVaryList and cdict.get('_vary',True): # true for constr eq & varied New Var
337-
msg = "parameter(s) not varied: "
354+
noVarMsg = "parameter(s) not varied: "
338355
for i,v in enumerate(noVaryList):
339-
if i != 0: msg += ', '
340-
msg += v
341-
warn(msg,cdict,fixVal,prefix='\nUnused ')
356+
if i != 0: noVarMsg += ', '
357+
noVarMsg += v
358+
warn(noVarMsg,cdict,fixVal,prefix='\nUnused parameters in ')
342359
for l,m in ((zeroList,"have zero multipliers"), # show warning
343360
(holdList,'set as "Hold"'),
344361
#(noVaryList,"not varied"),
@@ -352,20 +369,19 @@ def warn(msg,cdict=None,val=None,prefix=None):
352369
warn(msg,cdict,fixVal)
353370
if valid == 0: # no valid entries
354371
if seqHistNum is None:
355-
warn('Ignoring constraint, contains no usable parameters',cdict,prefix='\nUnused ')
372+
warn('Ignoring this constraint; contains no refined parameters',cdict,prefix='\nUnused ')
356373
skipList.append(cnum)
357374
elif problem: # mix of valid & refined and undefined items, cannot use this
358375
if cdict.get('_vary',True): # true for constr eq & varied New Var
359376
warn('New Var constraint will be ignored',cdict,prefix='\nUnused ')
360377
skipList.append(cnum)
361378
invalidParms += VarKeys(cdict)
362379
elif len(dropList) > 0: # mix of valid and problematic items, drop problem vars, but keep rest
363-
if GSASIIpath.GetConfigValue('debug'):
364-
msg = ''
365-
for v in dropList:
366-
if msg: msg += ' ,'
367-
msg += v
368-
warn('removing: '+msg,cdict)
380+
msg = ''
381+
for v in dropList:
382+
if msg: msg += ' ,'
383+
msg += v
384+
warn('removing unvaried: '+msg,cdict)
369385
value = fixedList[cnum]
370386
for var in dropList: # do cleanup
371387
# NB expressions in constraint multipliers have already been evaluated
@@ -375,19 +391,36 @@ def warn(msg,cdict=None,val=None,prefix=None):
375391
value = float(value) - cdict[var]*parmDict[var]
376392
del cdict[var]
377393
if float(value) != float(fixedList[cnum]): fixedList[cnum] = float(np.round(value,12))
378-
if GSASIIpath.GetConfigValue('debug'):
379-
warn('revised as: '+_FormatConstraint(constrDict[cnum],fixedList[cnum]))
394+
warn('constraint revised as: '+_FormatConstraint(constrDict[cnum],fixedList[cnum]))
380395
for i in list(range(len(constrDict)-1,-1,-1)): # remove the dropped constraints
381396
if i in skipList:
382397
del constrDict[i]
383398
del fixedList[i]
399+
del OrigSeq[i] # keep pointer to original lists
384400

385401
for i in invalidParms: StoreHold(i,"Used in invalid constraint")
386402
if warning: warning += '\n'
387403
warning += warninfo['msg']
388404

389405
groups,parmlist = GroupConstraints(constrDict)
390406

407+
# Look for duplicate constraints and eliminate one
408+
for group,depPrmList in zip(groups,parmlist):
409+
droplist = []
410+
for i in group:
411+
for j in group:
412+
if i == j: continue
413+
if i in droplist: continue
414+
if j in droplist: continue
415+
if constrDict[i] == constrDict[j] and fixedList[i] == fixedList[j]:
416+
droplist.append(j)
417+
if droplist and warning: warning += '\n'
418+
for j in sorted(droplist,reverse=True):
419+
warning += '\nIgnoring duplicated constraint\n\t'
420+
warning += _FormatConstraint(constrDict[j],fixedList[j])
421+
warning += '\n'
422+
del group[group.index(j)]
423+
391424
# now process each group and create the relations that are needed to form
392425
# a non-singular square matrix
393426
# Now check that all parameters are varied (probably do not need to do this
@@ -402,6 +435,7 @@ def warn(msg,cdict=None,val=None,prefix=None):
402435
errmsg += ") than parameters (" + str(len(depPrmList)) + ")\nin these constraints:"
403436
for rel in group:
404437
errmsg += '\n\t'+ _FormatConstraint(constrDict[rel],fixedList[rel])
438+
errmsg += showChanged(group)
405439
groupErrors += depPrmList
406440
continue # go on to next group
407441

@@ -416,6 +450,7 @@ def warn(msg,cdict=None,val=None,prefix=None):
416450
errmsg += "\nError expanding matrix with these constraints:"
417451
for rel in group:
418452
errmsg += '\n\t' + _FormatConstraint(constrDict[rel],fixedList[rel])
453+
errmsg += showChanged(group)
419454
groupErrors += depPrmList
420455
continue
421456

@@ -426,6 +461,7 @@ def warn(msg,cdict=None,val=None,prefix=None):
426461
errmsg += "\nUnexpected singularity with constraints group (in Gram-Schmidt)"
427462
for rel in group:
428463
errmsg += '\n\t' + _FormatConstraint(constrDict[rel],fixedList[rel])
464+
errmsg += showChanged(group)
429465
groupErrors += depPrmList
430466
continue
431467

@@ -440,6 +476,7 @@ def warn(msg,cdict=None,val=None,prefix=None):
440476
errmsg += 'This is unexpected. Please report this (toby@anl.gov)'
441477
for rel in group:
442478
errmsg += '\n\t' + _FormatConstraint(constrDict[rel],fixedList[rel])
479+
errmsg += showChanged(group)
443480
groupErrors += depPrmList
444481
continue
445482

@@ -559,12 +596,12 @@ def CheckEquivalences(constrDict,varyList,fixedList,parmDict=None,seqHistNum=Non
559596
'''
560597

561598
warninfo = {'msg':'', 'shown':-1}
562-
def warnEqv(msg,cnum=None):
599+
def warnEqv(msg,cnum=None,prefix='Problem with equivalence'):
563600
if cnum is not None and cnum != warninfo['shown']:
564601
warninfo['shown'] = cnum
565-
if warninfo['msg']: warninfo['msg'] += '\n'
566-
warninfo['msg'] += '\nProblem with equivalence: ' + _showEquiv(
567-
dependentParmList[cnum],indParmList[cnum],invarrayList[cnum])
602+
if warninfo['msg']: warninfo['msg'] += '\n\n'
603+
warninfo['msg'] += f'{prefix}: '
604+
warninfo['msg'] += _showEquiv(dependentParmList[cnum],indParmList[cnum],invarrayList[cnum])
568605
if warninfo['msg']: warninfo['msg'] += '\n'
569606
warninfo['msg'] += ' ' + msg
570607

@@ -634,23 +671,27 @@ def warnEqv(msg,cnum=None):
634671
if v in constrVarList+convVarList:
635672
changed = True
636673
msg = True
637-
warnEqv("Independent parameter "+str(v)+' used in constraint',cnum)
674+
warnEqv("Independent parameter "+str(v)+' used in constraint',cnum,
675+
prefix='Converting equivalence to constraint')
638676
if cnum not in convertList: convertList.append(cnum)
639677
for v in varlist:
640678
if v in multdepVarList:
641679
changed = True
642680
msg = True
643-
warnEqv("Dependent parameter "+str(v)+' repeated',cnum)
681+
warnEqv("Dependent parameter "+str(v)+' repeated',cnum,
682+
prefix='Converting equivalence to constraint')
644683
if cnum not in convertList: convertList.append(cnum)
645684
elif v in indepVarList:
646685
changed = True
647686
msg = True
648-
warnEqv("Dependent parameter "+str(v)+' used elsewhere as independent',cnum)
687+
warnEqv("Dependent parameter "+str(v)+' used elsewhere as independent',cnum,
688+
prefix='Converting equivalence to constraint')
649689
if cnum not in convertList: convertList.append(cnum)
650690
elif v in constrVarList+convVarList:
651691
changed = True
652692
msg = True
653-
warnEqv("Dependent parameter "+str(v)+' used in constraint',cnum)
693+
warnEqv("Dependent parameter "+str(v)+' used in constraint',cnum,
694+
prefix='Converting equivalence to constraint')
654695
if cnum not in convertList: convertList.append(cnum)
655696
if msg:
656697
warnEqv('Converting to "Constr"',cnum)
@@ -685,7 +726,8 @@ def warnEqv(msg,cnum=None):
685726
else:
686727
msg = ' All parameters set as "Hold" '
687728
msg += "\n Will ignore equivalence"
688-
warnEqv(msg,cnum)
729+
warnEqv(msg,cnum,prefix='Unused equivalence')
730+
689731
removeList.append(cnum)
690732
continue
691733

@@ -711,9 +753,10 @@ def warnEqv(msg,cnum=None):
711753
removeList.append(cnum)
712754
continue
713755
else:
714-
msg = 'No parameters varied '
715-
msg += "\n Will ignore equivalence"
716-
warnEqv(msg,cnum)
756+
msg = 'Contains no varied parameters'
757+
msg += "\n Will ignore this equivalence"
758+
warnEqv(msg,cnum,prefix='Unused equivalence')
759+
717760
removeList.append(cnum)
718761
continue
719762

0 commit comments

Comments
 (0)