Hi Nils
There are a couple of way to do it, but only in Diffpy-CMI, not in PDFgui. Usually when I restrain atomic positions I do something like this:
#Import the phase from the PDFgenerator
phase_X = pdfgenerator_X.phase
sgpars_X = phase_X.sgpars
#Global limits for the fractional coordinates.
pos_restrainO = 0.1
pos_restrainFe= 0.2
for par in sgpars_X.xyzpars:
lclabel = par.par.obj.GetName().lower()
lcsymbol = lclabel.rstrip(string.digits)
# name the variables
tags = ['xyz', 'xyz_' + lclabel, 'xyz_' + lcsymbol]
recipe.addVar(par, name=name, tags=tags)
if name.count('x_o') == 1:
recipe.restrain(name, lb = par.par.value - 1, ub = par.par.value + 1, sig = 0.0005)
if name.count('y_o') == 1:
recipe.restrain(name, lb = par.par.value - 1, ub = par.par.value + 1, sig = 0.0005)
if name.count('z_o') == 1:
recipe.restrain(name, lb = par.par.value - 0.1, ub = par.par.value + 0.1, sig = 0.0005)
if name.count('x_Fe) == 1:
recipe.restrain(name, lb = par.par.value - pos_restrainM, ub = par.par.value + pos_restrainM, sig = 0.0005)
if name.count('y_Fe') == 1:
recipe.restrain(name, lb = par.par.value - pos_restrainM, ub = par.par.value + pos_restrainM, sig = 0.0005)
if name.count('z_Fe') == 1:
recipe.restrain(name, lb = par.par.value - 0.1, ub = par.par.value + 0.1, sig = 0.0005)
This should restrain all the Fe coordinates and O to the set values. Remember they are fractional coordinates, so 0.1 will be a different value in Å along the a and c axis in your cell. I think this should do the trick.
If you want to restrain the the distance between two atoms you could do something like this:
phase_crystal1 = pdfgenerator_crystal1.phase
sgpars_crystal1 = phase_crystal1.sgpars
for par in sgpars_crystal1.xyzpars:
lclabel = par.par.obj.GetName().lower()
lcsymbol = lclabel.rstrip(string.digits)
# name the variables
tags = ['xyz', 'xyz_' + lclabel, 'xyz_' + lcsymbol]
recipe.addVar(par, name=name, tags=tags)
recipe.newVar('Dummy_variablex')
recipe.newVar('Dummy_variabley')
recipe.newVar('Dummy_variablez')
recipe.constrain('(xFe1**2-xO1**2)**(1/2)', 'Dummy variablex')
recipe.constrain('(yFe1**2-yO1**2)**(1/2)', 'Dummy variabley')
recipe.constrain('(zFe1**2-zO1**2)**(1/2)', 'Dummy variablez')
recipe.constrain('Dummy_variablex', lb = 2.0, ub = 3.0, sig = 0.0005)
recipe.constrain('Dummy_variabley', lb = 2.0, ub = 3.0, sig = 0.0005)
recipe.constrain('Dummy_variablez', lb = 2.0, ub = 3.0, sig = 0.0005)
I think this works, but I have not tried it out so there are likely a mistake somewhere. The idea is to create a variable which is always equal to the the x (y or z) distance between the atoms of interest and the restrain the dummy variable to be between some values, in this case 2 and 3. I am not 100 % it makes sense to do it like this, this is just off top of my head. I am quite sure I mix up some geometry, but it should work if you get the right equations in the constrain and the right number in the restrain.
Hope this helps!
Mikkel