def makeRecipe(ciffile, datname): """Create a fitting recipe for crystalline PDF data.""" # Work directly with a custom PDFContribution to load the data contribution = PDFContribution("nickel") contribution.loadData(datname) contribution.setCalculationRange(xmin=1, xmax=20, dx=0.1) # and the phase stru = Structure() stru.read(ciffile) contribution.addStructure("nickel", stru) ## Make the FitRecipe and add the FitContribution. recipe = FitRecipe() recipe.addContribution(contribution) ## Configure the fit variables phase = contribution.nickel.phase from diffpy.srfit.structure import constrainAsSpaceGroup sgpars = constrainAsSpaceGroup(phase, "Fm-3m") for par in sgpars.latpars: recipe.addVar(par) for par in sgpars.adppars: recipe.addVar(par, 0.005) recipe.addVar(contribution.scale, 1) recipe.addVar(contribution.qdamp, 0.03, fixed=True) recipe.addVar(contribution.nickel.delta2, 5) # Give the recipe away so it can be used! return recipe
def test_getQmax(self): """check PDFContribution.getQmax() """ from diffpy.Structure import Structure # cover all code branches in PDFContribution._getMetaValue # (1) contribution metadata pc1 = self.pc self.assertIsNone(pc1.getQmax()) pc1.setQmax(17) self.assertEqual(17, pc1.getQmax()) # (2) contribution metadata pc2 = PDFContribution('pdf') pc2.addStructure('empty', Structure()) pc2.empty.setQmax(18) self.assertEqual(18, pc2.getQmax()) # (3) profile metadata pc3 = PDFContribution('pdf') pc3.profile.meta['qmax'] = 19 self.assertEqual(19, pc3.getQmax()) return
basisvecs=2.5 * np.array([[1, 0, 0]]), kvecs=np.array([[0, 0, 1.5]]), ffparamkey='Mn2') # Create and prep the magnetic structure mstr = MagStructure() mstr.loadSpecies(mn2p) mstr.makeAll() # Set up the mPDF calculator mc = MPDFcalculator(magstruc=mstr, gaussPeakWidth=0.2) ### DO THE STRUCTURAL FIT USING SRFIT # Construct the atomic PDF contribution MnOPDF = PDFContribution("MnO") # Load the data and set the r-range over which we'll fit MnOPDF.loadData(dataFile) MnOPDF.setCalculationRange(xmin=0.01, xmax=20, dx=0.01) # Add the structure from our cif file to the contribution MnOPDF.addStructure("MnO", mnostructure) # The FitRecipe does the work of calculating the PDF with the fit variable # that we give it. MnOFit = FitRecipe() # give the PDFContribution to the FitRecipe MnOFit.addContribution(MnOPDF)
def makeRecipe(niciffile, siciffile, datname): """Create a fitting recipe for crystalline PDF data.""" # Load data and add it to the profile contribution = PDFContribution("nisi") contribution.loadData(datname) contribution.setCalculationRange(xmax=20) stru = CreateCrystalFromCIF(file(niciffile)) contribution.addStructure("ni", stru) stru = CreateCrystalFromCIF(file(siciffile)) contribution.addStructure("si", stru) # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() recipe.addContribution(contribution) ## Configure the fit variables # Start by configuring the scale factor and resolution factors. # We want the sum of the phase scale factors to be 1. recipe.newVar("scale_ni", 0.1) recipe.constrain(contribution.ni.scale, "scale_ni") recipe.constrain(contribution.si.scale, "1 - scale_ni") # We also want the resolution factor to be the same on each. This is done # for free by the PDFContribution. We simply need to add it to the recipe. recipe.addVar(contribution.qdamp, 0.03) # Vary the gloabal scale as well. recipe.addVar(contribution.scale, 1) # Now we can configure the structural parameters. Since we're using # ObjCrystCrystalParSets, the space group constraints are automatically # applied to each phase. We must selectively vary the free parameters. # # First the nickel parameters. # Note that ni is the name of the PDFGenerator that was automatically # created by the PDFContribution. We selected this name in addStructure # above. phase_ni = contribution.ni.phase for par in phase_ni.sgpars: recipe.addVar(par, name=par.name + "_ni") recipe.addVar(contribution.ni.delta2, name="delta2_ni") # Next the silicon parameters phase_si = contribution.si.phase for par in phase_si.sgpars: recipe.addVar(par, name=par.name + "_si") recipe.addVar(contribution.si.delta2, name="delta2_si") # We have prior information from the earlier examples so we'll use it here # in the form of restraints. # # The nickel lattice parameter was measured to be 3.527. The uncertainty # values are invalid for that measurement, since the data from which it is # derived has no uncertainty. Thus, we will tell the recipe to scale the # residual, which means that it will be weighted as much as the average # data point during the fit. recipe.restrain("a_ni", lb=3.527, ub=3.527, scaled=True) # Now we do the same with the delta2 and Biso parameters (remember that # Biso = 8*pi**2*Uiso) recipe.restrain("delta2_ni", lb=2.22, ub=2.22, scaled=True) recipe.restrain("Biso_0_ni", lb=0.454, ub=0.454, scaled=True) # # We can do the same with the silicon values. We haven't done a thorough # job of measuring the uncertainties in the results, so we'll scale these # as well. recipe.restrain("a_si", lb=5.430, ub=5.430, scaled=True) recipe.restrain("delta2_si", lb=3.54, ub=3.54, scaled=True) recipe.restrain("Biso_0_si", lb=0.645, ub=0.645, scaled=True) # Give the recipe away so it can be used! return recipe
from scipy.optimize.minpack import leastsq # DiffPy-CMI modules for building a fitting recipe from diffpy.Structure import loadStructure from diffpy.srfit.pdf import PDFContribution from diffpy.srfit.fitbase import FitRecipe, FitResults # Files containing our experimental data and structure file dataFile = "ni-q27r100-neutron.gr" structureFile = "ni.cif" spaceGroup = "Fm-3m" # The first thing to construct is a contribution. Since this is a simple # example, the contribution will simply contain our PDF data and an associated # structure file. We'll give it the name "nickel" niPDF = PDFContribution("nickel") # Load the data and set the r-range over which we'll fit niPDF.loadData(dataFile) niPDF.setCalculationRange(xmin=1, xmax=20, dx=0.01) # Add the structure from our cif file to the contribution niStructure = loadStructure(structureFile) niPDF.addStructure("nickel", niStructure) # The FitRecipe does the work of calculating the PDF with the fit variable # that we give it. niFit = FitRecipe() # give the PDFContribution to the FitRecipe niFit.addContribution(niPDF)
def setUp(self): global PDFContribution from diffpy.srfit.pdf import PDFContribution self.pc = PDFContribution('pdf') return
def make_recipe(self, structure, sg): """ Construct PDF with diffpy. """ # construct a PDFContribution object pdf = PDFContribution("Contribution") # read experimental data try: pdf.loadData(self.input_file) except: print_failure('Failed to parse ' + self.input_file + '. Exiting...') exit() print('Constructing PDF object for', structure.title) pdf.setCalculationRange(self.xmin, self.xmax, self.dx) pdf.addStructure("Contribution", structure) # create FitRecipe to calculate PDF with chosen fit variable fit = FitRecipe() fit.addContribution(pdf) # configure variables and add to recipe if sg != 'xxx' and sg is not None: print(sg) spacegroup_params = constrainAsSpaceGroup(pdf.Contribution.phase, sg) else: cart_lat = abc2cart([[ structure.lattice.a, structure.lattice.b, structure.lattice.c ], [ structure.lattice.alpha, structure.lattice.beta, structure.lattice.gamma ]]) positions_frac = structure.xyz atomic_numbers = [] for atom in structure.element: atomic_numbers.append(get_atomic_number(atom)) cell = (cart_lat, positions_frac, atomic_numbers) sg = int( spg.get_spacegroup(cell, symprec=1e-2).split(' ')[1].replace( '(', '').replace(')', '')) spacegroup_params = constrainAsSpaceGroup(pdf.Contribution.phase, sg) # print('Space group parameters:') # print(', '.join([param.name for param in spacegroup_params])) # iterate through spacegroup params and activate them for param in spacegroup_params.latpars: fit.addVar(param) for param in spacegroup_params.xyzpars: fit.addVar(param, fixed=True) # these next parameters are taken from Martin's PDFht.py, # though I have a feeling that was not their origin... # set initial ADP parameters for param in spacegroup_params.adppars: fit.addVar(param, value=0.03, fixed=True) # overall scale of PDF and delta2 parameter for correlated motion - from PDFht.py fit.addVar(pdf.scale, 1, fixed=True) fit.restrain(pdf.scale, lb=0, ub=0.1, scaled=True) fit.addVar(pdf.Contribution.delta2, 5, fixed=True) fit.restrain(pdf.Contribution.delta2, lb=1, ub=10, scaled=True) # fix Qdamp based on information about "our beamline": yep, no idea fit.addVar(pdf.qdamp, 0.03, fixed=True) fit.restrain(pdf.qdamp, lb=0, ub=0.1, scaled=True) return fit
def make(self, crystal, r, g, dg=None, meta=None): """ Construct new srfit recipe from CIF structure and PDF data Parameters ---------- crystal : pyobjcryst.Crystal The CIF structure to be fitted to the PDF data in-place. r : array_like The r-grid of the fitted PDF dataset in Angstroms. g : array_like The fitted PDF values per each `r` point. dg : array_like, optional The estimated standard deviations at each of `g` values. When unspecified, *dg* is assumed 1 leading to underestimated standard errors of the refined variables. meta : dict, optional A dictionary of extra metadata to be used when constructing `PDFContribution` in the srfit recipe. The common recognized keys are ``stype`` for radiation type ("X" or "N"), ``qmax`` for the Q-range used in the experiment, ``delta1``, ``delta2``, ``qbroad`` for peak sharpening and broadening factors and ``qdamp`` for the Q-resolution related signal dampening. Returns ------- recipe : FitRecipe The new FitRecipe for in-place fitting of `crystal` to PDF data. """ if not isinstance(crystal, Crystal): emsg = "crystal must be of the pyobjcryst.Crystal type." raise TypeError(emsg) cpdf = PDFContribution('cpdf') cpdf.profile.setObservedProfile(r, g, dg) m = {} if meta is None else dict(meta) cpdf.profile.meta.update(m) cpdf.addStructure('cif', crystal) cpdf.setCalculationRange(self.rmin, self.rmax) if self.nyquist: if not 'qmax' in m: emsg = "Nyquist spacing requires 'qmax' metadata." raise ValueError(emsg) assert m['qmax'] == cpdf.cif.getQmax() cpdf.setCalculationRange(dx=numpy.pi / m['qmax']) # create FitRecipe recipe = FitRecipe() recipe.clearFitHooks() recipe.addContribution(cpdf) recipe.addVar(cpdf.scale) # get symmetry allowed structure parameters sgpars = cpdf.cif.phase.sgpars # constrain available lattice parameters for p in sgpars.latpars: recipe.addVar(p, tags=['phase', 'lattice']) # constrain free atom positions for p in sgpars.xyzpars: recipe.addVar(p, tags=['phase', 'positions']) # constrain adps isosymbol = sgpars.isosymbol fbbiso = self.fbbiso # make a dummy diffpy.structure.Atom with isotropic Biso = fbbiso afbiso = _dummyAtomWithBiso(crystal, self.fbbiso) tags = ['phase', 'adps'] for p in sgpars.adppars: if p.name.startswith(isosymbol): recipe.addVar(p, value=p.value or fbbiso, tags=tags) continue # we have anisotropic site here, but constrain as isotropic # if so requested if self.isotropy: # extract site index for this sg parameter. Use it to get # the parameter for its Biso value. idx = int(p.name.split('_')[-1]) psite = cpdf.cif.phase.scatterers[idx] pbiso = psite.Biso n = isosymbol + '_{}'.format(idx) v = pbiso.value or fbbiso # avoid applying duplicate constrain to pbiso if recipe.get(n) is None: recipe.addVar(pbiso, name=n, value=v, tags=tags) continue # here we constrain an anisotropic site. # make sure its ADPs are nonzero. spa = p.par.obj if not all((spa.B11, spa.B22, spa.B33)): spa.B11 = afbiso.B11 spa.B22 = afbiso.B22 spa.B33 = afbiso.B33 spa.B12 = afbiso.B12 spa.B13 = afbiso.B13 spa.B23 = afbiso.B23 recipe.addVar(p, tags=tags) # constrain delta2, qdamp and qbroad p = cpdf.cif.delta2 v = p.value or self.fbdelta2 recipe.addVar(p, value=v, tag='phase') p = cpdf.qdamp v = p.value or self.fbqdamp recipe.addVar(p, value=v, tag='experiment') p = cpdf.qbroad v = p.value or self.fbqbroad recipe.addVar(p, value=v, tag='experiment') return recipe
# A least squares fitting algorithm from scipy from scipy.optimize.minpack import leastsq # DiffPy-CMI modules for building a fitting recipe from diffpy.Structure import loadStructure from diffpy.srfit.pdf import PDFContribution from diffpy.srfit.fitbase import FitRecipe, FitResults # Files containing our experimental data and structure file dataFile = "cdse.gr" structureFile = "cdse.xyz" # The first thing to construct is a contribution. Since this is a simple # example, the contribution will simply contain our PDF data and an associated # structure file. We'll give it the name "cdse" cdsePDF = PDFContribution("CdSe") # Load the data and set the r-range over which we'll fit cdsePDF.loadData(dataFile) cdsePDF.setCalculationRange(xmin=1, xmax=20, dx=0.01) # Add the structure from our xyz file to the contribution, since the structure # model is non-periodic, we need to specify the periodic=False here to get the # right PDF cdseStructure = loadStructure(structureFile) cdsePDF.addStructure("CdSe", cdseStructure, periodic=False) # The FitRecipe does the work of managing one or more contributions # that are optimized together. In addition, FitRecipe configures # fit variables that are tied to the model parameters and thus # controls the calculated profiles.
import numpy as np from pyobjcryst import loadCrystal from diffpy.srfit.pdf import PDFContribution from diffpy.srfit.fitbase import Profile, FitRecipe, FitResults nphcrystal = loadCrystal('naphthalene.cif') pdfcntb = PDFContribution('pdfcntb') pdfcntb.loadData('naphthalene.gr') pdfcntb.qdamp = 0.06 pdfcntb.setCalculationRange(1.1, 25) pdfcntb.addStructure('nph', nphcrystal) nphfit = FitRecipe() nphfit.clearFitHooks() nphfit.addContribution(pdfcntb) nphfit.addVar(pdfcntb.scale, name='scale') nphfit.addVar(pdfcntb.nph.delta2, value=1.0) nphase = pdfcntb.nph.phase # unit cell parameters nphfit.addVar(nphase.a) nphfit.addVar(nphase.b) nphfit.addVar(nphase.c) # cell-angle beta is in radians in ObjCryst Crystal # we will refine angle in degrees. nphfit.newVar('beta', value=np.degrees(nphase.beta.value)) nphfit.constrain(nphase.beta, 'radians(beta)') # all carbon species have the same displacement parameter, # it is sufficient to add constraint for the C1 atom
def setUp(self): self.pc = PDFContribution('pdf') return