How to refine atomic positions and add restraints with Diffpy

621 views
Skip to first unread message

Maria Diaz Lopez

unread,
Oct 30, 2015, 11:25:34 AM10/30/15
to diffpy-users

Hi all,


Many thanks for this forum and all the valuable advises that can be found in it.  I am a new to Diffpy and would like to ask a couple of questions:

1.         

            1.    To do my first refinement I have used ‘fitNi.py’ and ‘fitCdSeNP. py ’ where I substituted the data and structure files for my own ones. I was wondering what are the lines to be added in the .py file in order to refine the atomic positions?

In the fitNi.py file I can see the lines below which account for the lattice parameters, ADPs, scale factor and delta 2, but I could not find one for atomic positions.

for par in spaceGroupParams.latpars:

    niFit.addVar(par)

for par in spaceGroupParams.adppars:

    niFit.addVar(par, value=0.005,)

niFit.addVar(niPDF.scale, 1)

niFit.addVar(niPDF.nickel.delta2, 1)

 

      2.       Also, I would like to restraint certain parameters to a given range, e.g. restrain the occupancies from 0 to 1. What should I comment on my .py script to restraint refined values to a given range?


Many thanks for all your time and consideration and looking forward to your response.


Best,

 

Maria

Pavol Juhas

unread,
Nov 1, 2015, 11:33:36 PM11/1/15
to diffpy...@googlegroups.com
On Fri, Oct 30, 2015 at 07:02:11AM -0700, Maria Diaz Lopez wrote:
...
> Many thanks for this forum and all the valuable advises that can be found
> in it. I am a new to Diffpy and would like to ask a couple of questions:

Hi Maria,

Welcome to the diffpy-users list!

> 1. To do my first refinement I have used ‘fitNi.py’ and ‘fitCdSeNP.
> py ’ where I substituted the data and structure files for my own
> ones. I was wondering what are the lines to be added in the .py file
> in order to refine the atomic positions?
>
> In the fitNi.py file I can see the lines below which account for the
> lattice parameters, ADPs, scale factor and delta 2, but I could not
> find one for atomic positions.
>
> for par in spaceGroupParams.latpars:
> niFit.addVar(par)

Symmetry parameters for atomic coordinates are in
spaceGroupParams.xyzpars so they could be constrained with

for par in spaceGroupParams.xyzpars:
niFit.addVar(par)

where the names and values of symmetry parameters are in
spaceGroupParams.xyzpars.names and spaceGroupParams.xyzpars.values.
However for nickel they are both empty, because all atoms in the fcc
lattice are symmetry-related and at fixed special positions. One
way to try out the xyzpars is to run the example with a
lower-symmetry space group, for example, "P4".

Another option of controlling atom coordinates (when not using the
space group constraints) is to descend into the fit-object hierarchy,
for example,

niFit.nickel.nickel.phase.Ni0.x

stands for the x-coordinate of the first atom in the nickel unit cell.
You can use `niFit.show()` to display a full hierarchy of parameters
available in the NiFit object. Several coordinates can be constrained
with a for loop as follows:

# variables to be linked to the x-coordinates:
varnames = ['x0', 'x1', 'x2', 'x3']
atompars = niFit.nickel.nickel.phase.atoms
for n, a in zip(varnames, atompars):
niFit.addVar(a.x, name=n)

...
> 2. Also, I would like to restraint certain parameters to a given
> range, e.g. restrain the occupancies from 0 to 1. What should
> I comment on my .py script to restraint refined values to a given
> range?

The top-level FitRecipe object has a "restrain" function, which can
define soft restraints for upper and lower boundaries of some
variable. There is an example in the LinearFit IPython notebook,
input 27 at
https://github.com/diffpy/cmi_exchange/blob/master/cmi_scripts/linearfit/LinearFit.ipynb,
but this defines only the upper bound "ub". The lower bound is
specified with the "lb" argument, so the code to restrict some occ
variable within the 0, 1 bounds would be

orst = fit.restrain(fit.occ, lb=0, ub=1, sig=0.001)

It is useful to save the restraint object in the orst variable, because
that allows to adjust the restraint later - e.g., change its sig
parameter, or to remove it altogether with `fit.unrestrain(orst)`.

As with any restrained optimizations, one needs to be careful if the
refined values indeed originate from the fitted experimental data or
from the imposed restraints.

Hope this helps,

Pavol

Maria Diaz Lopez

unread,
Nov 3, 2015, 12:12:53 PM11/3/15
to diffpy-users
Hi Pavol, 

Many thanks for your response. May I know what are the options for refining the atomic occupancies  with and without the space gorup info?

Thanks again, 

Maria

Pavol Juhas

unread,
Nov 10, 2015, 3:06:32 AM11/10/15
to diffpy...@googlegroups.com
On Tue, Nov 03, 2015 at 08:53:27AM -0800, Maria Diaz Lopez wrote:
...
> Many thanks for your response. May I know what are the options for refining
> the atomic occupancies with and without the space gorup info?

Hi Maria, I am sorry about taking so long to respond. There is no
direct support for occupancy constraints in the constrainAsSpaceGroup
function. The diffpy Structure representation expands asymmetric
unit to a full unit cell, so you probably need to constrain all
equivalent sites to the same occupancy. This can be done by
checking the atom labels at the expanded sites. If NaCl.cif file has
"Na1" and "Cl1" sites in the asymmetric unit, the labels in the
diffpy.Structure object would be "Na1" for the original site and
"Na1_i" for its symmetry images:


from diffpy.Structure import loadStructure
nacl = loadStructure('NaCl.cif')
print(nacl.label)
# chararray(['Na1', 'Na1_2', 'Na1_3', 'Na1_4', 'Cl1', ...


When some structure is added to a PDF contribution, the srfit
generates a set of parameters for all of its structure values, which
can be then constrained or restrained. Most srfit objects have
a show() function to displays a hierarchy of their parameters:

salt = PDFContribution('salt')
salt.addStructure('nacl', nacl)
salt.show()

salt # the total PDF contribution
...
nacl # contribution from one phase
...
phase
Cl1m1 # parameters for the Cl1 site
...
occ 1.0 # occ is an alias for occupancy
occupancy 1.0


To refine atom occupancies we need to link the relevant structure
parameters to some variables in the top-level Fit recipe:


recipe = FitRecipe()
recipe.addContribution(salt)
# define 2 variables for site occupancies
oNa = recipe.newVar("oNa", value=1.0)
oCl = recipe.newVar("oCl", value=1.0)
# loop over atom-related structure parameters `ap`
for ap in salt.nacl.phase.atoms:
lb = ap.atom.label # recover the atom label
if lb.startswith('Na1'):
# constrain to oNa for the Na1 site and its symmetry images
recipe.constrain(ap.occupancy, oNa)
if lb.startswith('Cl1'):
# constrain to oCl for the Cl1 site and its images
recipe.constrain(ap.occupancy, oCl)


After this the FitRecipe variables oNa, oCl should control all sodium
and chlorine occupancies. The code above is untested and should just
illustrate one way of constraining the occupancies. I admit it is
quite steep to become familiar with the fit-parameter names and
hierarchy. A helpful approach is to start with a partial script and
explore the fit objects with IPython tab completion or with
"help(obj)" or "obj.show()".

Before spending a lot of time on fit scripts, I would recommend to
do a few quick PDF simulations to make sure there is a clear
response in the PDF signal to occupancy changes. In my experience
such response is usually limited to the first few PDF peaks and at
longer distances the peaks remain quite constant.

Good luck, I hope this helps,

Pavol

ali dordaee

unread,
Mar 10, 2021, 3:41:28 PM3/10/21
to diffpy-users
 In this same cluster I have a question about a 2-step refinement I have for myself. In my way of refinement I wanna first attribute an amount for U_iso which is fixed; Let's say 0.003 and fixed! I use addVar as the template does and give my fixed amounts easily in the first step. 
 In step 2, I want to release those fixed adps to get refined and I do not know what is the proper command to do so!

  I have no idea how to unfix ADP's in step 2, after I already made them fixed in the first step. I would be so grateful for your guidance.

 bests, 

ali dordaee

unread,
Mar 12, 2021, 9:25:29 AM3/12/21
to diffpy-users

 When I want to delete Uiso_0 (I mean my ADP's), I use following command:
for par in spaceGroupParams.adppars:
    auFit.delVar(par)

But the following error happens:
'ParameterProxy(Uiso_0)' is not part of the FitRecipe

 If "ParameterProxy(Uiso_0)" is not part of the FitRecipe, how can I learn part of what it is? and how can I delete or change the already existing ADP's? 

 Thanks in advance for your guidance,
Reply all
Reply to author
Forward
0 new messages