Skip to content

Commit 5da350f

Browse files
committed
add import & export of constraints, as per #345
1 parent 013259a commit 5da350f

3 files changed

Lines changed: 153 additions & 0 deletions

File tree

GSASII/GSASIIconstrGUI.py

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,6 +1577,142 @@ def SetStatusLine(text):
15771577
def OnShowISODISTORT(event):
15781578
ShowIsoDistortCalc(G2frame)
15791579

1580+
def ExportConstraints(event):
1581+
import datetime
1582+
G2frame = wx.GetApp().GetTopWindow()
1583+
sub = G2gd.GetGPXtreeItemId(G2frame,G2frame.root,'Constraints')
1584+
Constraints = G2frame.GPXtree.GetItemPyData(sub)
1585+
text = f'# Constraints from {G2frame.GSASprojectfile} on '
1586+
text += datetime.datetime.strftime(datetime.datetime.now(),
1587+
"%Y-%m-%dT%H:%M\n")
1588+
for key in 'Hist', 'HAP', 'Phase':
1589+
for c in Constraints[key]:
1590+
s = ''
1591+
for i0,i1 in c[:-3]:
1592+
if c[-1] == 'e' and s:
1593+
s += ' = '
1594+
elif c[-1] == 'h' and s: # unexpected, should be 1 hold per constraint
1595+
s += ' = '
1596+
elif s:
1597+
s += ' + '
1598+
if c[-1] == 'h':
1599+
s += f'{i1}'
1600+
else:
1601+
s += f'{i0} * {i1}'
1602+
if c[-1] == 'c':
1603+
s = f'Equation & {s} = {c[-3]}'
1604+
elif c[-1] == 'e':
1605+
s = f'Equivalence & {s}'
1606+
elif c[-1] == 'h':
1607+
s = f'Hold & {s}'
1608+
elif c[-1] == 'f':
1609+
if c[-3]: # prefix by var name, if present
1610+
s = f'{c[-3]} & {s}'
1611+
if c[-2]: # vary flag
1612+
s = s + ' & varied'
1613+
s = f'NewVar & {s}'
1614+
else: # unexpected!
1615+
print('Unknown constraint:',c)
1616+
continue
1617+
text += s + '\n'
1618+
1619+
f = G2G.askSaveFile(G2frame,'Constraints','.constr','text constraints file')
1620+
with open(f,'w') as fp:
1621+
fp.write(text)
1622+
print(f'Constraints written to file {fp.name}')
1623+
1624+
def var2key(varObj):
1625+
if varObj.phase and varObj.histogram:
1626+
return 'HAP'
1627+
elif varObj.phase:
1628+
return 'Phase'
1629+
elif varObj.histogram:
1630+
return 'Hist'
1631+
else:
1632+
return 'Global'
1633+
1634+
def ImportConstraints(event):
1635+
G2frame = wx.GetApp().GetTopWindow()
1636+
sub = G2gd.GetGPXtreeItemId(G2frame,G2frame.root,'Constraints')
1637+
Constraints = G2frame.GPXtree.GetItemPyData(sub)
1638+
dlg = wx.FileDialog(G2frame, 'Select a text file with constraints to read',
1639+
style=wx.FD_DEFAULT_STYLE|wx.FD_FILE_MUST_EXIST,
1640+
wildcard="constraints|*.constr")
1641+
try:
1642+
res = dlg.ShowModal()
1643+
if res != wx.ID_OK: return
1644+
f = dlg.GetPath()
1645+
finally:
1646+
dlg.Destroy()
1647+
if not os.path.exists(f):
1648+
print(f'Strange, {f} not found')
1649+
return
1650+
txt = open(f,'r').readlines()
1651+
for i,line in enumerate(txt):
1652+
if line.strip().startswith('#'): continue
1653+
spLine = line.split('&')
1654+
tag = spLine[0].strip()
1655+
if tag == 'Equation':
1656+
val = spLine[1].split('=')[1].strip()
1657+
cons = []
1658+
for e in spLine[1].split('=')[0].split('+'):
1659+
try:
1660+
m,var = e.split('*')
1661+
varObj = G2obj.G2VarObj(var.strip())
1662+
cons += [[float(m),varObj]]
1663+
except:
1664+
print('skipping {line}')
1665+
continue
1666+
# TODO: could do a consistency check to make sure that all
1667+
# vars are of same type. For now only the last one matters.
1668+
key = var2key(varObj)
1669+
Constraints[key].append(cons + [val,None,'c'])
1670+
elif tag == 'Hold':
1671+
cons = []
1672+
for e in spLine[1].split('='): # should only be one
1673+
varObj = G2obj.G2VarObj(e.strip())
1674+
cons += [[0.,varObj]]
1675+
key = var2key(varObj)
1676+
Constraints[key].append(cons + [None,None,'h'])
1677+
elif tag == 'Equivalence':
1678+
cons = []
1679+
for e in spLine[1].split('='):
1680+
try:
1681+
m,var = e.split('*')
1682+
varObj = G2obj.G2VarObj(var.strip())
1683+
cons += [[float(m),varObj]]
1684+
except:
1685+
print('skipping {line}')
1686+
continue
1687+
# TODO: could do a consistency check to make sure that all
1688+
# vars are of same type. For now only the last one matters.
1689+
key = var2key(varObj)
1690+
Constraints[key].append(cons + [None,None,'e'])
1691+
elif tag == 'NewVar':
1692+
cons = []
1693+
name = None
1694+
vary = False
1695+
if len(spLine) >= 3:
1696+
name = spLine[1].strip()
1697+
if len(spLine) >= 4:
1698+
vary = True
1699+
for e in spLine[1].split('+'):
1700+
try:
1701+
m,var = e.split('*')
1702+
varObj = G2obj.G2VarObj(var.strip())
1703+
cons += [[float(m),varObj]]
1704+
except:
1705+
print('skipping {line}')
1706+
continue
1707+
# TODO: could do a consistency check to make sure that all
1708+
# vars are of same type. For now only the last one matters.
1709+
key = var2key(varObj)
1710+
Constraints[key].append(cons + [name,vary,'f'])
1711+
else:
1712+
print(f'line #{i+1} ({line}) not recognized')
1713+
continue
1714+
OnPageChanged(None)
1715+
15801716
#### UpdateConstraints execution starts here ##############################
15811717
G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.ConstraintMenu)
15821718
if Clear:
@@ -1723,6 +1859,8 @@ def OnShowISODISTORT(event):
17231859
G2frame.Bind(wx.EVT_MENU, OnAddAtomEquiv, id=G2G.wxID_EQUIVALANCEATOMS)
17241860
# G2frame.Bind(wx.EVT_MENU, OnAddRiding, id=G2G.wxID_ADDRIDING)
17251861
G2frame.Bind(wx.EVT_MENU, OnShowISODISTORT, id=G2G.wxID_SHOWISO)
1862+
G2frame.Bind(wx.EVT_MENU, ExportConstraints, id=G2G.wxID_CONSTREXPORT)
1863+
G2frame.Bind(wx.EVT_MENU, ImportConstraints, id=G2G.wxID_CONSTRIMPORT)
17261864
# tab commands
17271865
for id in (G2G.wxID_CONSPHASE,
17281866
G2G.wxID_CONSHAP,

GSASII/GSASIIdataGUI.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6751,6 +6751,14 @@ def _makemenu(): # routine to create menu when first used
67516751
# self.ConstraintEdit.Append(id=G2G.wxID_ADDRIDING, kind=wx.ITEM_NORMAL,text='Add H riding constraints',
67526752
# help='Add H atom riding constraints between atom parameter values')
67536753
# self.ConstraintEdit.Enable(G2G.wxID_ADDRIDING,False)
6754+
G2G.Define_wxId('wxID_CONSTREXPORT')
6755+
self.ConstraintEdit.Append(G2G.wxID_CONSTREXPORT,
6756+
'Export constraints',
6757+
'Write a text file with constraints')
6758+
G2G.Define_wxId('wxID_CONSTRIMPORT')
6759+
self.ConstraintEdit.Append(G2G.wxID_CONSTRIMPORT,
6760+
'Import constraints',
6761+
'Read a text file to create new constraints')
67546762
self.ConstraintEdit.Append(G2G.wxID_SHOWISO,'Show New Var modes',
67556763
'Show New Var constraints and dependent vars')
67566764
self.ConstraintEdit.Enable(G2G.wxID_SHOWISO,False)

docs/source/objvarorg.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,13 @@ Phase This specifies a list of constraints on phase
112112
Global This specifies a list of constraints on parameters
113113
that are not tied to a histogram or phase and
114114
are of form ::<var>:n
115+
_seqmode Determines how constraints are interpreted for
116+
sequential fits. Modes are 'auto-wildcard',
117+
'wildcards-only' and 'use-all'
118+
_seqhist A histogram number. In auto-wildcard mode, this
119+
histogram will be replaced with the current
120+
sequential histogram number.
121+
_NewVarOff An offset to be applied to NewVar expressions
115122
========== ====================================================
116123

117124
.. _Constraint_definitions_table:

0 commit comments

Comments
 (0)