コード例 #1
0
def makeRecipeII():
    """Make a recipe for fitting low and high temperature regions.

    We will fit the low and high temperature parts of Debye curve
    simultaneously with the same Debye temperature, but different offsets.

    We will make two FitRecipes using the makeRecipe function from
    debyemodel.py and extract the configured FitContribution from each. We will
    use different fitting ranges for each FitContribution and constrain the
    Debye temperature in each FitContribution to be the same.

    """

    # We'll throw these away. We just want the FitContributions that are
    # configured within the recipes.
    m1 = makeRecipe()
    m2 = makeRecipe()
    # These are the FitContributions (we named them "pb" in the debyemodel
    # example).
    lowT = m1.pb
    highT = m2.pb
    # Let's rename the FitContributions to something more meaningful for this
    # example.
    lowT.name = "lowT"
    highT.name = "highT"

    # Now create a fresh FitRecipe to work with and add to it the two
    # FitContributions.
    recipe = FitRecipe()
    recipe.addContribution(lowT)
    recipe.addContribution(highT)

    # Change the fit ranges of the Profiles embedded within the
    # FitContributions. We want to fit one of the contributions at low
    # temperature, and one at high.
    lowT.profile.setCalculationRange(0, 150)
    highT.profile.setCalculationRange(400, 500)

    # Vary the offset from each FitContribution separately, while keeping the
    # Debye temperatures the same. We give each offset variable a different
    # name in the recipe so it retains its identity.
    recipe.addVar(recipe.lowT.offset, name="lowToffset")
    recipe.addVar(recipe.highT.offset, name="highToffset")
    # We create a new Variable and use the recipe's "constrain" method to
    # associate the Debye temperature parameters with that variable.
    par = recipe.newVar("thetaD", 100)
    recipe.constrain(recipe.lowT.thetaD, "thetaD")
    recipe.constrain(recipe.highT.thetaD, "thetaD")
    return recipe
コード例 #2
0
def makeRecipeII():
    """Make a recipe for fitting low and high temperature regions.

    We will fit the low and high temperature parts of Debye curve
    simultaneously with the same Debye temperature, but different offsets.

    We will make two FitRecipes using the makeRecipe function from
    debyemodel.py and extract the configured FitContribution from each. We will
    use different fitting ranges for each FitContribution and constrain the
    Debye temperature in each FitContribution to be the same.

    """

    # We'll throw these away. We just want the FitContributions that are
    # configured within the recipes.
    m1 = makeRecipe()
    m2 = makeRecipe()
    # These are the FitContributions (we named them "pb" in the debyemodel
    # example).
    lowT = m1.pb
    highT = m2.pb
    # Let's rename the FitContributions to something more meaningful for this
    # example.
    lowT.name = "lowT"
    highT.name = "highT"

    # Now create a fresh FitRecipe to work with and add to it the two
    # FitContributions.
    recipe = FitRecipe()
    recipe.addContribution(lowT)
    recipe.addContribution(highT)

    # Change the fit ranges of the Profiles embedded within the
    # FitContributions. We want to fit one of the contributions at low
    # temperature, and one at high.
    lowT.profile.setCalculationRange(0, 150)
    highT.profile.setCalculationRange(400, 500)

    # Vary the offset from each FitContribution separately, while keeping the
    # Debye temperatures the same. We give each offset variable a different
    # name in the recipe so it retains its identity.
    recipe.addVar(recipe.lowT.offset, name = "lowToffset")
    recipe.addVar(recipe.highT.offset, name = "highToffset")
    # We create a new Variable and use the recipe's "constrain" method to
    # associate the Debye temperature parameters with that variable.
    par = recipe.newVar("thetaD", 100)
    recipe.constrain(recipe.lowT.thetaD, "thetaD")
    recipe.constrain(recipe.highT.thetaD, "thetaD")
    return recipe
コード例 #3
0
def makeRecipe(ciffile, grdata, iqdata):
    """Make complex-modeling recipe where I(q) and G(r) are fit
    simultaneously.

    The fit I(q) is fed into the calculation of G(r), which provides feedback
    for the fit parameters of both.

    """

    # Create a PDF contribution as before
    pdfprofile = Profile()
    pdfparser = PDFParser()
    pdfparser.parseFile(grdata)
    pdfprofile.loadParsedData(pdfparser)
    pdfprofile.setCalculationRange(xmin = 0.1, xmax = 20)

    pdfcontribution = FitContribution("pdf")
    pdfcontribution.setProfile(pdfprofile, xname = "r")

    pdfgenerator = PDFGenerator("G")
    pdfgenerator.setQmax(30.0)
    stru = loadCrystal(ciffile)
    pdfgenerator.setStructure(stru)
    pdfcontribution.addProfileGenerator(pdfgenerator)
    pdfcontribution.setResidualEquation("resv")

    # Create a SAS contribution as well. We assume the nanoparticle is roughly
    # elliptical.
    sasprofile = Profile()
    sasparser = SASParser()
    sasparser.parseFile(iqdata)
    sasprofile.loadParsedData(sasparser)
    if all(sasprofile.dy == 0):
        sasprofile.dy[:] = 1

    sascontribution = FitContribution("sas")
    sascontribution.setProfile(sasprofile)

    from sas.models.EllipsoidModel import EllipsoidModel
    model = EllipsoidModel()
    sasgenerator = SASGenerator("generator", model)
    sascontribution.addProfileGenerator(sasgenerator)
    sascontribution.setResidualEquation("resv")

    # Now we set up a characteristic function calculator that depends on the
    # sas model.
    cfcalculator = SASCF("f", model)

    # Register the calculator with the pdf contribution and define the fitting
    # equation.
    pdfcontribution.registerCalculator(cfcalculator)
    # The PDF for a nanoscale crystalline is approximated by
    # Gnano = f * Gcryst
    pdfcontribution.setEquation("f * G")

    # Moving on
    recipe = FitRecipe()
    recipe.addContribution(pdfcontribution)
    recipe.addContribution(sascontribution)

    # PDF
    phase = pdfgenerator.phase
    for par in phase.sgpars:
        recipe.addVar(par)

    recipe.addVar(pdfgenerator.scale, 1)
    recipe.addVar(pdfgenerator.delta2, 0)

    # SAS
    recipe.addVar(sasgenerator.scale, 1, name = "iqscale")
    recipe.addVar(sasgenerator.radius_a, 10)
    recipe.addVar(sasgenerator.radius_b, 10)

    # Even though the cfcalculator and sasgenerator depend on the same sas
    # model, we must still constrain the cfcalculator Parameters so that it is
    # informed of changes in the refined parameters.
    recipe.constrain(cfcalculator.radius_a, "radius_a")
    recipe.constrain(cfcalculator.radius_b, "radius_b")

    return recipe
コード例 #4
0
def makeRecipe(ciffile, xdatname, ndatname):
    """Create a fitting recipe for crystalline PDF data."""

    ## The Profiles
    # We need a profile for each data set. This means that we will need two
    # FitContributions as well.
    xprofile = Profile()
    nprofile = Profile()

    # Load data and add it to the proper Profile.
    parser = PDFParser()
    parser.parseFile(xdatname)
    xprofile.loadParsedData(parser)
    xprofile.setCalculationRange(xmax = 20)

    parser = PDFParser()
    parser.parseFile(ndatname)
    nprofile.loadParsedData(parser)
    nprofile.setCalculationRange(xmax = 20)

    ## The ProfileGenerators
    # We need one of these for the x-ray data.
    xgenerator = PDFGenerator("G")
    stru = loadCrystal(ciffile)
    xgenerator.setStructure(stru)

    # And we need one for the neutron data. We want to refine the same
    # structure object in each PDFGenerator. This would suggest that we add the
    # same Crystal to each. However, if we do that then we will have two
    # Parameters for each Crystal data member (two Parameters for the "a"
    # lattice parameter, etc.), held in different ObjCrystCrystalParSets, each
    # managed by its own PDFGenerator. Thus, changes made to the Crystal
    # through one PDFGenerator will not be known to the other PDFGenerator
    # since their ObjCrystCrystalParSets don't know about each other. The
    # solution is to share ObjCrystCrystalParSets rather than Crystals. This
    # way there is only one Parameter for each Crystal data member. (An
    # alternative to this is to constrain each structure Parameter to be varied
    # to the same variable. The present approach is easier and less error
    # prone.)
    #
    # Tell the neutron PDFGenerator to use the phase from the x-ray
    # PDFGenerator.
    ngenerator = PDFGenerator("G")
    ngenerator.setPhase(xgenerator.phase)

    ## The FitContributions
    # We associate the x-ray PDFGenerator and Profile in one FitContribution...
    xcontribution = FitContribution("xnickel")
    xcontribution.addProfileGenerator(xgenerator)
    xcontribution.setProfile(xprofile, xname = "r")
    # and the neutron objects in another.
    ncontribution = FitContribution("nnickel")
    ncontribution.addProfileGenerator(ngenerator)
    ncontribution.setProfile(nprofile, xname = "r")

    # This example is different than the previous ones in that we are composing
    # a residual function from other residuals (one for the x-ray contribution
    # and one for the neutron contribution). The relative magnitude of these
    # residuals effectively determines the influence of each contribution over
    # the fit. This is a problem in this case because the x-ray data has
    # uncertainty values associated with it (on the order of 1e-4), and the
    # chi^2 residual is proportional to 1 / uncertainty**2. The neutron has no
    # uncertainty, so it's chi^2 is proportional to 1. Thus, my optimizing
    # chi^2 we would give the neutron data practically no weight in the fit. To
    # get around this, we will optimize a different metric.
    #
    # The contribution's residual can be either chi^2, Rw^2, or custom crafted.
    # In this case, we should minimize Rw^2 of each contribution so that each
    # one can contribute roughly equally to the fit.
    xcontribution.setResidualEquation("resv")
    ncontribution.setResidualEquation("resv")

    # Make the FitRecipe and add the FitContributions.
    recipe = FitRecipe()
    recipe.addContribution(xcontribution)
    recipe.addContribution(ncontribution)

    # Now we vary and constrain Parameters as before.
    recipe.addVar(xgenerator.scale, 1, "xscale")
    recipe.addVar(ngenerator.scale, 1, "nscale")
    recipe.addVar(xgenerator.qdamp, 0.01, "xqdamp")
    recipe.addVar(ngenerator.qdamp, 0.01, "nqdamp")
    # delta2 is a non-structual material propery. Thus, we constrain together
    # delta2 Parameter from each PDFGenerator.
    delta2 = recipe.newVar("delta2", 2)
    recipe.constrain(xgenerator.delta2, delta2)
    recipe.constrain(ngenerator.delta2, delta2)

    # We only need to constrain phase properties once since there is a single
    # ObjCrystCrystalParSet for the Crystal.
    phase = xgenerator.phase
    for par in phase.sgpars:
        recipe.addVar(par)
    recipe.B11_0 = 0.1

    # Give the recipe away so it can be used!
    return recipe
コード例 #5
0
def makeRecipe(niciffile, siciffile, datname):
    """Create a fitting recipe for crystalline PDF data."""

    ## The Profile
    profile = Profile()

    # Load data and add it to the profile
    parser = PDFParser()
    parser.parseFile(datname)
    profile.loadParsedData(parser)
    profile.setCalculationRange(xmax = 20)

    ## The ProfileGenerator
    # In order to fit two phases simultaneously, we must use two PDFGenerators.
    # PDFGenerator is designed to take care of as little information as it
    # must. (Don't do too much, and do it well.) A PDFGenerator can generate
    # the signal from only a single phase at a time. So, we will create one
    # PDFGenerator for each phase and compose them within the same
    # FitContribution. Note that both generators will be associated with the
    # same Profile within the FitContribution, so they will both be
    # automatically configured according to the metadata.
    #
    # The generator for the nickel phase. We call it "G_ni" and will use this
    # name later when we set the fitting equation in the FitContribution.
    generator_ni = PDFGenerator("G_ni")
    stru = CreateCrystalFromCIF(file(niciffile))
    generator_ni.setStructure(stru)
    # The generator for the silicon phase. We call it "G_si".
    generator_si = PDFGenerator("G_si")
    stru = CreateCrystalFromCIF(file(siciffile))
    generator_si.setStructure(stru)

    ## The FitContribution
    # Add both generators to the FitContribution. Add the Profile. This will
    # send the metadata to the generators.
    contribution = FitContribution("nisi")
    contribution.addProfileGenerator(generator_ni)
    contribution.addProfileGenerator(generator_si)
    contribution.setProfile(profile, xname = "r")

    # Write the fitting equation. We want to sum the PDFs from each phase and
    # multiply it by a scaling factor. We also want a certain phase scaling
    # relationship between the PDFs which we will enforce with constraints in
    # the FitRecipe.
    contribution.setEquation("scale * (G_ni +  G_si)")

    # 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(generator_ni.scale, "scale_ni")
    recipe.constrain(generator_si.scale, "1 - scale_ni")
    # We also want the resolution factor to be the same on each.
    recipe.newVar("qdamp", 0.03)
    recipe.constrain(generator_ni.qdamp, "qdamp")
    recipe.constrain(generator_si.qdamp, "qdamp")

    # 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
    phase_ni = generator_ni.phase
    for par in phase_ni.sgpars:
        recipe.addVar(par, name = par.name + "_ni")
    recipe.addVar(generator_ni.delta2, name = "delta2_ni")
    # Next the silicon parameters
    phase_si = generator_si.phase
    for par in phase_si.sgpars:
        recipe.addVar(par, name = par.name + "_si")
    recipe.addVar(generator_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
コード例 #6
0
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
コード例 #7
0
def makeRecipe(ciffile_ni, ciffile_si, xdata_ni, ndata_ni, xdata_si,
        xdata_sini):
    """Create a fitting recipe for crystalline PDF data."""

    ## The Profiles
    # We need a profile for each data set.
    xprofile_ni = makeProfile(xdata_ni)
    xprofile_si = makeProfile(xdata_si)
    nprofile_ni = makeProfile(ndata_ni)
    xprofile_sini = makeProfile(xdata_sini)

    ## The ProfileGenerators
    # We create one for each phase and share the phases.
    xgenerator_ni = PDFGenerator("xG_ni")
    stru = CreateCrystalFromCIF(file(ciffile_ni))
    xgenerator_ni.setStructure(stru)
    phase_ni = xgenerator_ni.phase

    xgenerator_si = PDFGenerator("xG_si")
    stru = CreateCrystalFromCIF(file(ciffile_si))
    xgenerator_si.setStructure(stru)
    phase_si = xgenerator_si.phase

    ngenerator_ni = PDFGenerator("nG_ni")
    ngenerator_ni.setPhase(phase_ni)

    xgenerator_sini_ni = PDFGenerator("xG_sini_ni")
    xgenerator_sini_ni.setPhase(phase_ni)

    xgenerator_sini_si = PDFGenerator("xG_sini_si")
    xgenerator_sini_si.setPhase(phase_si)

    ## The FitContributions
    # We one of these for each data set.
    xcontribution_ni = makeContribution("xnickel", xgenerator_ni, xprofile_ni)
    xcontribution_si = makeContribution("xsilicon", xgenerator_si, xprofile_si)
    ncontribution_ni = makeContribution("nnickel", ngenerator_ni, nprofile_ni)
    xcontribution_sini = makeContribution("xsini", xgenerator_sini_ni,
            xprofile_sini)
    xcontribution_sini.addProfileGenerator(xgenerator_sini_si)
    xcontribution_sini.setEquation("scale * (xG_sini_ni +  xG_sini_si)")

    # As explained in another example, we want to minimize using Rw^2.
    xcontribution_ni.setResidualEquation("resv")
    xcontribution_si.setResidualEquation("resv")
    ncontribution_ni.setResidualEquation("resv")
    xcontribution_sini.setResidualEquation("resv")

    # Make the FitRecipe and add the FitContributions.
    recipe = FitRecipe()
    recipe.addContribution(xcontribution_ni)
    recipe.addContribution(xcontribution_si)
    recipe.addContribution(ncontribution_ni)
    recipe.addContribution(xcontribution_sini)

    # Now we vary and constrain Parameters as before.
    for par in phase_ni.sgpars:
        recipe.addVar(par, name = par.name + "_ni")
    delta2_ni = recipe.newVar("delta2_ni", 2.5)
    recipe.constrain(xgenerator_ni.delta2, delta2_ni)
    recipe.constrain(ngenerator_ni.delta2, delta2_ni)
    recipe.constrain(xgenerator_sini_ni.delta2, delta2_ni)

    for par in phase_si.sgpars:
        recipe.addVar(par, name = par.name + "_si")
    delta2_si = recipe.newVar("delta2_si", 2.5)
    recipe.constrain(xgenerator_si.delta2, delta2_si)
    recipe.constrain(xgenerator_sini_si.delta2, delta2_si)

    # Now the experimental parameters
    recipe.addVar(xgenerator_ni.scale, name = "xscale_ni")
    recipe.addVar(xgenerator_si.scale, name = "xscale_si")
    recipe.addVar(ngenerator_ni.scale, name = "nscale_ni")
    recipe.addVar(xcontribution_sini.scale, 1.0, "xscale_sini")
    recipe.newVar("pscale_sini_ni", 0.8)
    recipe.constrain(xgenerator_sini_ni.scale, "pscale_sini_ni")
    recipe.constrain(xgenerator_sini_si.scale, "1 - pscale_sini_ni")

    # The qdamp parameters are too correlated to vary so we fix them based on
    # previous measurments.
    xgenerator_ni.qdamp.value = 0.055
    xgenerator_si.qdamp.value = 0.051
    ngenerator_ni.qdamp.value = 0.030
    xgenerator_sini_ni.qdamp.value = 0.052
    xgenerator_sini_si.qdamp.value = 0.052

    # Give the recipe away so it can be used!
    return recipe
コード例 #8
0
def makeRecipe(strufile, datname1, datname2):
    """Create a recipe that uses the IntensityGenerator.

    We will create two FitContributions that use the IntensityGenerator from
    npintensitygenerator.py and associate each of these with a Profile, and use
    this to define a FitRecipe.

    Both simulated data sets come from the same structure. We're going to make
    two FitContributions that are identical, except for the profile that is
    held in each. We're going to assure that the structures are identical by
    using the same DiffpyStructureParSet (which is generated by the
    IntensityGenerator when we load the structure) in both generators.

    """

    ## The Profiles
    # Create two Profiles for the two FitContributions.
    profile1 = Profile()
    profile2 = Profile()

    # Load data into the Profiles
    profile1.loadtxt(datname1)
    x, y, u = profile2.loadtxt(datname2)

    ## The ProfileGenerators
    # Create two IntensityGenerators named "I". There will not be a name
    # conflict, since the name is only meaningful within the FitContribution
    # that holds the ProfileGenerator.  Load the structure into one and make
    # sure that the second ProfileGenerator is using the same
    # DiffyStructureParSet.  This will assure that both ProfileGenerators are
    # using the exact same Parameters, and underlying Structure object in the
    # calculation of the profile.
    generator1 = IntensityGenerator("I")
    generator1.setStructure(strufile)
    generator2 = IntensityGenerator("I")
    generator2.addParameterSet(generator1.phase)

    ## The FitContributions
    # Create the FitContributions.
    contribution1 = FitContribution("bucky1")
    contribution1.addProfileGenerator(generator1)
    contribution1.setProfile(profile1, xname = "q")
    contribution2 = FitContribution("bucky2")
    contribution2.addProfileGenerator(generator2)
    contribution2.setProfile(profile2, xname = "q")

    # Now we're ready to define the fitting equation for each FitContribution.
    # The functions registered below will be independent, even though they take
    # the same form and use the same Parameter names.  By default, Parameters
    # in different contributions are different Parameters even if they have the
    # same names.  FitContributions are isolated namespaces than only share
    # information if you tell them to by using addParameter or addParameterSet.
    bkgdstr = "b0 + b1*q + b2*q**2 + b3*q**3 + b4*q**4 + b5*q**5 + b6*q**6 +\
               b7*q**7 +b8*q**8 + b9*q**9"

    contribution1.registerStringFunction(bkgdstr, "bkgd")
    contribution2.registerStringFunction(bkgdstr, "bkgd")

    # We will create the broadening function by registering a python function.
    pi = numpy.pi
    exp = numpy.exp
    def gaussian(q, q0, width):
        return 1/(2*pi*width**2)**0.5 * exp(-0.5 * ((q-q0)/width)**2)

    contribution1.registerFunction(gaussian)
    contribution2.registerFunction(gaussian)
    # Center the gaussian
    contribution1.q0.value = x[len(x) // 2]
    contribution2.q0.value = x[len(x) // 2]

    # Now we can incorporate the scale and bkgd into our calculation. We also
    # convolve the signal with the gaussian to broaden it.
    contribution1.setEquation("scale * convolve(I, gaussian) + bkgd")
    contribution2.setEquation("scale * convolve(I, gaussian) + bkgd")

    # Make a FitRecipe and associate the FitContributions.
    recipe = FitRecipe()
    recipe.addContribution(contribution1)
    recipe.addContribution(contribution2)

    # Specify which Parameters we want to refine. We want to refine the
    # background that we just defined in the FitContributions. We have to do
    # this separately for each FitContribution. We tag the variables so it is
    # easy to retrieve the background variables.
    recipe.addVar(contribution1.b0, 0, name = "b1_0", tag = "bcoeffs1")
    recipe.addVar(contribution1.b1, 0, name = "b1_1", tag = "bcoeffs1")
    recipe.addVar(contribution1.b2, 0, name = "b1_2", tag = "bcoeffs1")
    recipe.addVar(contribution1.b3, 0, name = "b1_3", tag = "bcoeffs1")
    recipe.addVar(contribution1.b4, 0, name = "b1_4", tag = "bcoeffs1")
    recipe.addVar(contribution1.b5, 0, name = "b1_5", tag = "bcoeffs1")
    recipe.addVar(contribution1.b6, 0, name = "b1_6", tag = "bcoeffs1")
    recipe.addVar(contribution1.b7, 0, name = "b1_7", tag = "bcoeffs1")
    recipe.addVar(contribution1.b8, 0, name = "b1_8", tag = "bcoeffs1")
    recipe.addVar(contribution1.b9, 0, name = "b1_9", tag = "bcoeffs1")
    recipe.addVar(contribution2.b0, 0, name = "b2_0", tag = "bcoeffs2")
    recipe.addVar(contribution2.b1, 0, name = "b2_1", tag = "bcoeffs2")
    recipe.addVar(contribution2.b2, 0, name = "b2_2", tag = "bcoeffs2")
    recipe.addVar(contribution2.b3, 0, name = "b2_3", tag = "bcoeffs2")
    recipe.addVar(contribution2.b4, 0, name = "b2_4", tag = "bcoeffs2")
    recipe.addVar(contribution2.b5, 0, name = "b2_5", tag = "bcoeffs2")
    recipe.addVar(contribution2.b6, 0, name = "b2_6", tag = "bcoeffs2")
    recipe.addVar(contribution2.b7, 0, name = "b2_7", tag = "bcoeffs2")
    recipe.addVar(contribution2.b8, 0, name = "b2_8", tag = "bcoeffs2")
    recipe.addVar(contribution2.b9, 0, name = "b2_9", tag = "bcoeffs2")

    # We also want to adjust the scale and the convolution width
    recipe.addVar(contribution1.scale, 1, name = "scale1")
    recipe.addVar(contribution1.width, 0.1, name = "width1")
    recipe.addVar(contribution2.scale, 1, name = "scale2")
    recipe.addVar(contribution2.width, 0.1, name = "width2")

    # We can also refine structural parameters. We only have to do this once,
    # since each generator holds the same DiffpyStructureParSet.
    phase = generator1.phase
    lattice = phase.getLattice()
    a = recipe.addVar(lattice.a)
    # We want to allow for isotropic expansion, so we'll make constraints for
    # that.
    recipe.constrain(lattice.b, a)
    recipe.constrain(lattice.c, a)
    # We want to refine the thermal parameters as well. We will add a new
    # variable that we call "Uiso" and constrain the atomic Uiso values to
    # this. Note that we don't give Uiso an initial value. The initial value
    # will be inferred from the subsequent constraints.
    Uiso = recipe.newVar("Uiso")
    for atom in phase.getScatterers():
        recipe.constrain(atom.Uiso, Uiso)

    # Give the recipe away so it can be used!
    return recipe
コード例 #9
0
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
コード例 #10
0
def makeRecipe(niciffile, siciffile, datname):
    """Create a fitting recipe for crystalline PDF data."""

    ## The Profile
    profile = Profile()

    # Load data and add it to the profile
    parser = PDFParser()
    parser.parseFile(datname)
    profile.loadParsedData(parser)
    profile.setCalculationRange(xmax=20)

    ## The ProfileGenerator
    # In order to fit two phases simultaneously, we must use two PDFGenerators.
    # PDFGenerator is designed to take care of as little information as it
    # must. (Don't do too much, and do it well.) A PDFGenerator can generate
    # the signal from only a single phase at a time. So, we will create one
    # PDFGenerator for each phase and compose them within the same
    # FitContribution. Note that both generators will be associated with the
    # same Profile within the FitContribution, so they will both be
    # automatically configured according to the metadata.
    #
    # The generator for the nickel phase. We call it "G_ni" and will use this
    # name later when we set the fitting equation in the FitContribution.
    generator_ni = PDFGenerator("G_ni")
    stru = CreateCrystalFromCIF(file(niciffile))
    generator_ni.setStructure(stru)
    # The generator for the silicon phase. We call it "G_si".
    generator_si = PDFGenerator("G_si")
    stru = CreateCrystalFromCIF(file(siciffile))
    generator_si.setStructure(stru)

    ## The FitContribution
    # Add both generators to the FitContribution. Add the Profile. This will
    # send the metadata to the generators.
    contribution = FitContribution("nisi")
    contribution.addProfileGenerator(generator_ni)
    contribution.addProfileGenerator(generator_si)
    contribution.setProfile(profile, xname="r")

    # Write the fitting equation. We want to sum the PDFs from each phase and
    # multiply it by a scaling factor. We also want a certain phase scaling
    # relationship between the PDFs which we will enforce with constraints in
    # the FitRecipe.
    contribution.setEquation("scale * (G_ni +  G_si)")

    # 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(generator_ni.scale, "scale_ni")
    recipe.constrain(generator_si.scale, "1 - scale_ni")
    # We also want the resolution factor to be the same on each.
    recipe.newVar("qdamp", 0.03)
    recipe.constrain(generator_ni.qdamp, "qdamp")
    recipe.constrain(generator_si.qdamp, "qdamp")

    # 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
    phase_ni = generator_ni.phase
    for par in phase_ni.sgpars:
        recipe.addVar(par, name=par.name + "_ni")
    recipe.addVar(generator_ni.delta2, name="delta2_ni")
    # Next the silicon parameters
    phase_si = generator_si.phase
    for par in phase_si.sgpars:
        recipe.addVar(par, name=par.name + "_si")
    recipe.addVar(generator_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
コード例 #11
0
ファイル: LinearFit.py プロジェクト: diffpy/cmi_exchange
print("fixed:", rec.fixednames, "-->", rec.fixedvalues)

# The fit can be rerun with a constant variable B.
leastsq(rec.residual, rec.values)
print(FitResults(rec))
plt.plot(linedata.x, linedata.y, 'x', linedata.x, linedata.ycalc, '-')
plt.title('Line fit for variable B fixed to B=0')

# <demo> --- stop ---

# Fixed variables may be released with the "free" function.
# free("all") releases all fixed variables.
rec.free('all')

# Variables may be constrained to a result of an expression.
rec.constrain(rec.A, "2 * B")

# Perform linear fit where slope is twice the offset.
leastsq(rec.residual, rec.values)
print(FitResults(rec))
plt.plot(linedata.x, linedata.y, 'x', linedata.x, linedata.ycalc, '-')
plt.title('Line fit for variable A constrained to A = 2*B')

# <demo> --- stop ---

# Constraint expressions can be removed by calling the unconstrain function.
rec.unconstrain(rec.A)

# Variables may be restrained to a specific range.  Here "ub" is the upper
# boundary and "sig" acts as a standard deviation for ((x - ub)/sig)**2
# penalty function.
コード例 #12
0
ファイル: crystalpdfall.py プロジェクト: rjkoch/diffpy.srfit
def makeRecipe(ciffile_ni, ciffile_si, xdata_ni, ndata_ni, xdata_si,
               xdata_sini):
    """Create a fitting recipe for crystalline PDF data."""

    ## The Profiles
    # We need a profile for each data set.
    xprofile_ni = makeProfile(xdata_ni)
    xprofile_si = makeProfile(xdata_si)
    nprofile_ni = makeProfile(ndata_ni)
    xprofile_sini = makeProfile(xdata_sini)

    ## The ProfileGenerators
    # We create one for each phase and share the phases.
    xgenerator_ni = PDFGenerator("xG_ni")
    stru = loadCrystal(ciffile_ni)
    xgenerator_ni.setStructure(stru)
    phase_ni = xgenerator_ni.phase

    xgenerator_si = PDFGenerator("xG_si")
    stru = loadCrystal(ciffile_si)
    xgenerator_si.setStructure(stru)
    phase_si = xgenerator_si.phase

    ngenerator_ni = PDFGenerator("nG_ni")
    ngenerator_ni.setPhase(phase_ni)

    xgenerator_sini_ni = PDFGenerator("xG_sini_ni")
    xgenerator_sini_ni.setPhase(phase_ni)

    xgenerator_sini_si = PDFGenerator("xG_sini_si")
    xgenerator_sini_si.setPhase(phase_si)

    ## The FitContributions
    # We one of these for each data set.
    xcontribution_ni = makeContribution("xnickel", xgenerator_ni, xprofile_ni)
    xcontribution_si = makeContribution("xsilicon", xgenerator_si, xprofile_si)
    ncontribution_ni = makeContribution("nnickel", ngenerator_ni, nprofile_ni)
    xcontribution_sini = makeContribution("xsini", xgenerator_sini_ni,
                                          xprofile_sini)
    xcontribution_sini.addProfileGenerator(xgenerator_sini_si)
    xcontribution_sini.setEquation("scale * (xG_sini_ni +  xG_sini_si)")

    # As explained in another example, we want to minimize using Rw^2.
    xcontribution_ni.setResidualEquation("resv")
    xcontribution_si.setResidualEquation("resv")
    ncontribution_ni.setResidualEquation("resv")
    xcontribution_sini.setResidualEquation("resv")

    # Make the FitRecipe and add the FitContributions.
    recipe = FitRecipe()
    recipe.addContribution(xcontribution_ni)
    recipe.addContribution(xcontribution_si)
    recipe.addContribution(ncontribution_ni)
    recipe.addContribution(xcontribution_sini)

    # Now we vary and constrain Parameters as before.
    for par in phase_ni.sgpars:
        recipe.addVar(par, name=par.name + "_ni")
    delta2_ni = recipe.newVar("delta2_ni", 2.5)
    recipe.constrain(xgenerator_ni.delta2, delta2_ni)
    recipe.constrain(ngenerator_ni.delta2, delta2_ni)
    recipe.constrain(xgenerator_sini_ni.delta2, delta2_ni)

    for par in phase_si.sgpars:
        recipe.addVar(par, name=par.name + "_si")
    delta2_si = recipe.newVar("delta2_si", 2.5)
    recipe.constrain(xgenerator_si.delta2, delta2_si)
    recipe.constrain(xgenerator_sini_si.delta2, delta2_si)

    # Now the experimental parameters
    recipe.addVar(xgenerator_ni.scale, name="xscale_ni")
    recipe.addVar(xgenerator_si.scale, name="xscale_si")
    recipe.addVar(ngenerator_ni.scale, name="nscale_ni")
    recipe.addVar(xcontribution_sini.scale, 1.0, "xscale_sini")
    recipe.newVar("pscale_sini_ni", 0.8)
    recipe.constrain(xgenerator_sini_ni.scale, "pscale_sini_ni")
    recipe.constrain(xgenerator_sini_si.scale, "1 - pscale_sini_ni")

    # The qdamp parameters are too correlated to vary so we fix them based on
    # previous measurments.
    xgenerator_ni.qdamp.value = 0.055
    xgenerator_si.qdamp.value = 0.051
    ngenerator_ni.qdamp.value = 0.030
    xgenerator_sini_ni.qdamp.value = 0.052
    xgenerator_sini_si.qdamp.value = 0.052

    # Give the recipe away so it can be used!
    return recipe
コード例 #13
0
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
nphfit.addVar(nphase.C1.Biso, name='Biso', value=1.0)

from scipy.optimize import leastsq
leastsq(nphfit.residual, nphfit.values)
results = FitResults(nphfit)

r = pdfcntb.r.value
gobs = pdfcntb.y.value
gcalc = pdfcntb.evaluate()

from naphthalene_functions import differenceplot
differenceplot(r, gobs, gcalc, baseline=-0.75)
show()
コード例 #14
0
def makeRecipe(stru1, stru2, stru3, datname):
    """Create a fitting recipe for crystalline PDF data."""

    ## The Profile
    profile = Profile()

    # Load data and add it to the profile
    parser = PDFParser()
    parser.parseFile(datname)
    profile.loadParsedData(parser)
    profile.setCalculationRange(xmin=1, xmax=20, dx=0.01)

    ## The ProfileGenerator
    generator_ROY_Cryst_B = PDFGenerator("G_ROY_Cryst_B")
    generator_ROY_Cryst_B.setStructure(stru1, periodic=True)
    generator_ROY_Mole_B = DebyePDFGenerator("G_ROY_Mole_B")
    generator_ROY_Mole_B.setStructure(stru2, periodic=False)
    generator_ROY_Intra = DebyePDFGenerator("G_ROY_Intra")
    generator_ROY_Intra.setStructure(stru3, periodic=False)

    ## The FitContribution
    # Add both generators to the FitContribution. Add the Profile. This will
    # send the metadata to the generators.
    contribution = FitContribution("ROY")
    contribution.addProfileGenerator(generator_ROY_Cryst_B)
    contribution.addProfileGenerator(generator_ROY_Mole_B)
    contribution.addProfileGenerator(generator_ROY_Intra)
    contribution.setProfile(profile, xname="r")

    # Write the fitting equation. We want to sum the PDFs from each phase and
    # multiply it by a scaling factor. We also want a certain phase scaling
    # relationship between the PDFs which we will enforce with constraints in
    # the FitRecipe.
    #from diffpy.srfit.pdf.characteristicfunctions import sphericalCF
    #contribution.registerFunction(sphericalCF, name = "f_IMC")
    contribution.setEquation(
        "scale * (G_ROY_Cryst_B - G_ROY_Mole_B + G_ROY_Intra)")

    # Make the FitRecipe and add the FitContribution.
    recipe = FitRecipe()
    recipe.addContribution(contribution)

    qdamp = 0.02902
    generator_ROY_Cryst_B.qdamp.value = qdamp
    generator_ROY_Mole_B.qdamp.value = qdamp
    generator_ROY_Intra.qdamp.value = qdamp

    qbroad = 0.017315
    generator_ROY_Cryst_B.qbroad.value = qbroad
    generator_ROY_Mole_B.qbroad.value = qbroad
    generator_ROY_Intra.qbroad.value = qbroad

    # Vary the gloabal scale as well.
    recipe.addVar(contribution.scale, 1)

    #############################################################################################
    ############### First the ROY_Cryst_B parameters ############################################
    #############################################################################################
    phase_ROY_Cryst_B = generator_ROY_Cryst_B.phase

    lat = phase_ROY_Cryst_B.getLattice()
    atoms = phase_ROY_Cryst_B.getScatterers()

    recipe.newVar("Uiso_Inter", 0.05, tag="T1")
    recipe.newVar("lat_a", 3.9453, tag="lat")
    recipe.newVar("lat_b", 18.685, tag="lat")
    recipe.newVar("lat_c", 16.3948, tag="lat")
    #recipe.newVar("alpha", 90, tag = "lat")
    recipe.newVar("beta", 93.83, tag="lat")
    #recipe.newVar("gamma", 90, tag = "lat")

    recipe.constrain(lat.a, "lat_a")
    recipe.constrain(lat.b, "lat_b")
    recipe.constrain(lat.c, "lat_c")
    #recipe.constrain(lat.alpha, "alpha")
    recipe.constrain(lat.beta, "beta")
    #recipe.constrain(lat.gamma, "gamma")

    for atom in atoms:
        if atom.element.title() == "N":
            recipe.constrain(atom.Uiso, "Uiso_Inter")

        elif atom.element.title() == "O":
            recipe.constrain(atom.Uiso, "Uiso_Inter")

        elif atom.element.title() == "C":
            recipe.constrain(atom.Uiso, "Uiso_Inter")

        elif atom.element.title() == "H":
            recipe.constrain(atom.Uiso, "Uiso_Inter")

        elif atom.element.title() == "S":
            recipe.constrain(atom.Uiso, "Uiso_Inter")

    generator_ROY_Cryst_B.delta2.value = 0
    #    recipe.addVar(generator_IMC_Cryst_B.delta2, name = "delta2_IMC_Cryst_B", value =
    #            0, tag = "delta")

    #############################################################################################
    ############### Second the ROY_Mole_B parameters ############################################
    #############################################################################################
    phase_ROY_Mole_B = generator_ROY_Mole_B.phase
    generator_ROY_Mole_B.setQmin(0.0)
    generator_ROY_Mole_B.setQmax(24.0)
    recipe.newVar("zoom_Mole_B", 1, tag="lat2")

    lat = phase_ROY_Mole_B.getLattice()
    recipe.constrain(lat.a, "zoom_Mole_B")
    recipe.constrain(lat.b, "zoom_Mole_B")
    recipe.constrain(lat.c, "zoom_Mole_B")
    # Constrain fractional xyz parameters
    atoms = phase_ROY_Mole_B.getScatterers()
    # Constrain ADPs
    #recipe.newVar("Uiso_Inter", 0.05, tag = "T2")

    for atom in atoms:
        if atom.element.title() == "C":
            recipe.constrain(atom.Uiso, "Uiso_Inter")

        elif atom.element.title() == "O":
            recipe.constrain(atom.Uiso, "Uiso_Inter")

        elif atom.element.title() == "N":
            recipe.constrain(atom.Uiso, "Uiso_Inter")

        elif atom.element.title() == "H":
            recipe.constrain(atom.Uiso, "Uiso_Inter")

        elif atom.element.title() == "S":
            recipe.constrain(atom.Uiso, "Uiso_Inter")

    generator_ROY_Mole_B.delta2.value = 0

    #    recipe.addVar(generator_IMC_Mole_B.delta2, name = "delta2_IMC_Mole_B", value
    #            = 5.66086478091, tag = "delta")

    #############################################################################################
    ############### Third the intra molecule parameters##########################################
    #############################################################################################
    phase_ROY_Intra = generator_ROY_Intra.phase
    generator_ROY_Intra.setQmin(0.0)
    generator_ROY_Intra.setQmax(24.0)
    recipe.newVar("zoom_Intra", 1, tag="lat3")

    lat = phase_ROY_Intra.getLattice()
    recipe.constrain(lat.a, "zoom_Intra")
    recipe.constrain(lat.b, "zoom_Intra")
    recipe.constrain(lat.c, "zoom_Intra")
    # Constrain fractional xyz parameters
    atoms = phase_ROY_Intra.getScatterers()
    # Constrain ADPs
    recipe.newVar("Uiso_Intra", 0.005, tag="T2")

    for atom in atoms:
        if atom.element.title() == "C":
            recipe.constrain(atom.Uiso, "Uiso_Intra")

        elif atom.element.title() == "O":
            recipe.constrain(atom.Uiso, "Uiso_Intra")

        elif atom.element.title() == "N":
            recipe.constrain(atom.Uiso, "Uiso_Intra")

        elif atom.element.title() == "H":
            recipe.constrain(atom.Uiso, "Uiso_Intra")

        elif atom.element.title() == "S":
            recipe.constrain(atom.Uiso, "Uiso_Intra")

    generator_ROY_Intra.delta2.value = 0

    # Give the recipe away so it can be used!
    return recipe
コード例 #15
0
pdfcntb.setEquation('scale * (nphmol + widecrystal - widemolecule)')

nphfit = FitRecipe()
nphfit.clearFitHooks()
nphfit.addContribution(pdfcntb)

nphfit.addVar(pdfcntb.scale, name='scale')
pcrystal = pdfcntb.widecrystal.phase
# unit cell parameters
nphfit.addVar(pcrystal.a)
nphfit.addVar(pcrystal.b)
nphfit.addVar(pcrystal.c)
# cell-angle beta is in radians in ObjCryst Crystal
# we will refine angle in degrees.
nphfit.newVar('beta', value=np.degrees(pcrystal.beta.value))
nphfit.constrain(pcrystal.beta, 'radians(beta)')
# all carbon species have the same displacement parameter,
# it is sufficient to add constraint for the C1 atom
pmol = pdfcntb.nphmol.phase
nphfit.addVar(pmol.C1.Biso, name='Biso', value=1.0)

# create new variable for intermolecular displacements.
# constrain the fwhm of a Gaussian peak from 2 atoms accordingly.
nphfit.newVar('Binter', value=1.5)
nphfit.constrain(pdfcntb.widecrystal.fwhm, 'sqrt(2 * log(2) * Binter) / pi')
nphfit.constrain(pdfcntb.widemolecule.fwhm, 'sqrt(2 * log(2) * Binter) / pi')

leastsq(nphfit.residual, nphfit.values)
results = FitResults(nphfit)

r = pdfcntb.r.value
コード例 #16
0
def makeRecipe(strufile, datname1, datname2):
    """Create a recipe that uses the IntensityGenerator.

    We will create two FitContributions that use the IntensityGenerator from
    npintensitygenerator.py and associate each of these with a Profile, and use
    this to define a FitRecipe.

    Both simulated data sets come from the same structure. We're going to make
    two FitContributions that are identical, except for the profile that is
    held in each. We're going to assure that the structures are identical by
    using the same DiffpyStructureParSet (which is generated by the
    IntensityGenerator when we load the structure) in both generators.

    """

    ## The Profiles
    # Create two Profiles for the two FitContributions.
    profile1 = Profile()
    profile2 = Profile()

    # Load data into the Profiles
    profile1.loadtxt(datname1)
    x, y, u = profile2.loadtxt(datname2)

    ## The ProfileGenerators
    # Create two IntensityGenerators named "I". There will not be a name
    # conflict, since the name is only meaningful within the FitContribution
    # that holds the ProfileGenerator.  Load the structure into one and make
    # sure that the second ProfileGenerator is using the same
    # DiffyStructureParSet.  This will assure that both ProfileGenerators are
    # using the exact same Parameters, and underlying Structure object in the
    # calculation of the profile.
    generator1 = IntensityGenerator("I")
    generator1.setStructure(strufile)
    generator2 = IntensityGenerator("I")
    generator2.addParameterSet(generator1.phase)

    ## The FitContributions
    # Create the FitContributions.
    contribution1 = FitContribution("bucky1")
    contribution1.addProfileGenerator(generator1)
    contribution1.setProfile(profile1, xname="q")
    contribution2 = FitContribution("bucky2")
    contribution2.addProfileGenerator(generator2)
    contribution2.setProfile(profile2, xname="q")

    # Now we're ready to define the fitting equation for each FitContribution.
    # The functions registered below will be independent, even though they take
    # the same form and use the same Parameter names.  By default, Parameters
    # in different contributions are different Parameters even if they have the
    # same names.  FitContributions are isolated namespaces than only share
    # information if you tell them to by using addParameter or addParameterSet.
    bkgdstr = "b0 + b1*q + b2*q**2 + b3*q**3 + b4*q**4 + b5*q**5 + b6*q**6 +\
               b7*q**7 +b8*q**8 + b9*q**9"

    contribution1.registerStringFunction(bkgdstr, "bkgd")
    contribution2.registerStringFunction(bkgdstr, "bkgd")

    # We will create the broadening function by registering a python function.
    pi = numpy.pi
    exp = numpy.exp

    def gaussian(q, q0, width):
        return 1 / (2 * pi * width**2)**0.5 * exp(-0.5 * ((q - q0) / width)**2)

    contribution1.registerFunction(gaussian)
    contribution2.registerFunction(gaussian)
    # Center the gaussian
    contribution1.q0.value = x[len(x) / 2]
    contribution2.q0.value = x[len(x) / 2]

    # Now we can incorporate the scale and bkgd into our calculation. We also
    # convolve the signal with the gaussian to broaden it.
    contribution1.setEquation("scale * convolve(I, gaussian) + bkgd")
    contribution2.setEquation("scale * convolve(I, gaussian) + bkgd")

    # Make a FitRecipe and associate the FitContributions.
    recipe = FitRecipe()
    recipe.addContribution(contribution1)
    recipe.addContribution(contribution2)

    # Specify which Parameters we want to refine. We want to refine the
    # background that we just defined in the FitContributions. We have to do
    # this separately for each FitContribution. We tag the variables so it is
    # easy to retrieve the background variables.
    recipe.addVar(contribution1.b0, 0, name="b1_0", tag="bcoeffs1")
    recipe.addVar(contribution1.b1, 0, name="b1_1", tag="bcoeffs1")
    recipe.addVar(contribution1.b2, 0, name="b1_2", tag="bcoeffs1")
    recipe.addVar(contribution1.b3, 0, name="b1_3", tag="bcoeffs1")
    recipe.addVar(contribution1.b4, 0, name="b1_4", tag="bcoeffs1")
    recipe.addVar(contribution1.b5, 0, name="b1_5", tag="bcoeffs1")
    recipe.addVar(contribution1.b6, 0, name="b1_6", tag="bcoeffs1")
    recipe.addVar(contribution1.b7, 0, name="b1_7", tag="bcoeffs1")
    recipe.addVar(contribution1.b8, 0, name="b1_8", tag="bcoeffs1")
    recipe.addVar(contribution1.b9, 0, name="b1_9", tag="bcoeffs1")
    recipe.addVar(contribution2.b0, 0, name="b2_0", tag="bcoeffs2")
    recipe.addVar(contribution2.b1, 0, name="b2_1", tag="bcoeffs2")
    recipe.addVar(contribution2.b2, 0, name="b2_2", tag="bcoeffs2")
    recipe.addVar(contribution2.b3, 0, name="b2_3", tag="bcoeffs2")
    recipe.addVar(contribution2.b4, 0, name="b2_4", tag="bcoeffs2")
    recipe.addVar(contribution2.b5, 0, name="b2_5", tag="bcoeffs2")
    recipe.addVar(contribution2.b6, 0, name="b2_6", tag="bcoeffs2")
    recipe.addVar(contribution2.b7, 0, name="b2_7", tag="bcoeffs2")
    recipe.addVar(contribution2.b8, 0, name="b2_8", tag="bcoeffs2")
    recipe.addVar(contribution2.b9, 0, name="b2_9", tag="bcoeffs2")

    # We also want to adjust the scale and the convolution width
    recipe.addVar(contribution1.scale, 1, name="scale1")
    recipe.addVar(contribution1.width, 0.1, name="width1")
    recipe.addVar(contribution2.scale, 1, name="scale2")
    recipe.addVar(contribution2.width, 0.1, name="width2")

    # We can also refine structural parameters. We only have to do this once,
    # since each generator holds the same DiffpyStructureParSet.
    phase = generator1.phase
    lattice = phase.getLattice()
    a = recipe.addVar(lattice.a)
    # We want to allow for isotropic expansion, so we'll make constraints for
    # that.
    recipe.constrain(lattice.b, a)
    recipe.constrain(lattice.c, a)
    # We want to refine the thermal parameters as well. We will add a new
    # variable that we call "Uiso" and constrain the atomic Uiso values to
    # this. Note that we don't give Uiso an initial value. The initial value
    # will be inferred from the subsequent constraints.
    Uiso = recipe.newVar("Uiso")
    for atom in phase.getScatterers():
        recipe.constrain(atom.Uiso, Uiso)

    # Give the recipe away so it can be used!
    return recipe
コード例 #17
0
def makeRecipe(molecule, datname):
    """Create a recipe that uses the DebyePDFGenerator."""

    ## The Profile
    profile = Profile()

    # Load data and add it to the profile
    profile.loadtxt(datname)
    profile.setCalculationRange(xmin=1.2, xmax=8)

    ## The ProfileGenerator
    # Create a DebyePDFGenerator named "G".
    generator = DebyePDFGenerator("G")
    generator.setStructure(molecule)
    # These are metadata needed by the generator
    generator.setQmin(0.68)
    generator.setQmax(22)

    ## The FitContribution
    contribution = FitContribution("bucky")
    contribution.addProfileGenerator(generator)
    contribution.setProfile(profile, xname = "r")

    # Make a FitRecipe.
    recipe = FitRecipe()
    recipe.addContribution(contribution)

    # Specify which parameters we want to refine. We'll be using the
    # MoleculeParSet within the generator, so let's get a handle to it. See the
    # diffpy.srfit.structure.objcryststructure module for more information
    # about the MoleculeParSet hierarchy.
    c60 = generator.phase

    # First, the isotropic thermal displacement factor.
    Biso = recipe.newVar("Biso")
    for atom in c60.getScatterers():

        # We have defined a 'center' atom that is a dummy, which means that it
        # has no scattering power. It is only used as a reference point for
        # our bond length. We don't want to constrain it.
        if not atom.isDummy():
            recipe.constrain(atom.Biso, Biso)

    # We need to let the molecule expand. If we were modeling it as a crystal,
    # we could let the unit cell expand. For instruction purposes, we use a
    # Molecule to model C60, and molecules have different modeling options than
    # crystals. To make the molecule expand from a central point, we will
    # constrain the distance from each atom to a dummy center atom that was
    # created with the molecule, and allow that distance to vary. (We could
    # also let the nearest-neighbor bond lengths vary, but that would be much
    # more difficult to set up.)
    center = c60.center
    # Create a new Parameter that represents the radius of the molecule. Note
    # that we don't give it an initial value. Since the variable is being
    # directly constrained to further below, its initial value will be inferred
    # from the constraint.
    radius = recipe.newVar("radius")
    for i, atom in enumerate(c60.getScatterers()):

        if atom.isDummy():
            continue

        # This creates a Parameter that moves the second atom according to the
        # bond length. Note that each Parameter needs a unique name.
        par = c60.addBondLengthParameter("rad%i"%i, center, atom)
        recipe.constrain(par, radius)

    # Add the correlation term, scale. The scale is too short to effectively
    # determine qdamp.
    recipe.addVar(generator.delta2, 2)
    recipe.addVar(generator.scale, 1.3e4)

    # Give the recipe away so it can be used!
    return recipe
コード例 #18
0
def makeRecipe(ciffile, xdatname, ndatname):
    """Create a fitting recipe for crystalline PDF data."""

    ## The Profiles
    # We need a profile for each data set. This means that we will need two
    # FitContributions as well.
    xprofile = Profile()
    nprofile = Profile()

    # Load data and add it to the proper Profile.
    parser = PDFParser()
    parser.parseFile(xdatname)
    xprofile.loadParsedData(parser)
    xprofile.setCalculationRange(xmax = 20)

    parser = PDFParser()
    parser.parseFile(ndatname)
    nprofile.loadParsedData(parser)
    nprofile.setCalculationRange(xmax = 20)

    ## The ProfileGenerators
    # We need one of these for the x-ray data.
    xgenerator = PDFGenerator("G")
    stru = CreateCrystalFromCIF(file(ciffile))
    xgenerator.setStructure(stru)

    # And we need one for the neutron data. We want to refine the same
    # structure object in each PDFGenerator. This would suggest that we add the
    # same Crystal to each. However, if we do that then we will have two
    # Parameters for each Crystal data member (two Parameters for the "a"
    # lattice parameter, etc.), held in different ObjCrystCrystalParSets, each
    # managed by its own PDFGenerator. Thus, changes made to the Crystal
    # through one PDFGenerator will not be known to the other PDFGenerator
    # since their ObjCrystCrystalParSets don't know about each other. The
    # solution is to share ObjCrystCrystalParSets rather than Crystals. This
    # way there is only one Parameter for each Crystal data member. (An
    # alternative to this is to constrain each structure Parameter to be varied
    # to the same variable. The present approach is easier and less error
    # prone.)
    #
    # Tell the neutron PDFGenerator to use the phase from the x-ray
    # PDFGenerator.
    ngenerator = PDFGenerator("G")
    ngenerator.setPhase(xgenerator.phase)

    ## The FitContributions
    # We associate the x-ray PDFGenerator and Profile in one FitContribution...
    xcontribution = FitContribution("xnickel")
    xcontribution.addProfileGenerator(xgenerator)
    xcontribution.setProfile(xprofile, xname = "r")
    # and the neutron objects in another.
    ncontribution = FitContribution("nnickel")
    ncontribution.addProfileGenerator(ngenerator)
    ncontribution.setProfile(nprofile, xname = "r")

    # This example is different than the previous ones in that we are composing
    # a residual function from other residuals (one for the x-ray contribution
    # and one for the neutron contribution). The relative magnitude of these
    # residuals effectively determines the influence of each contribution over
    # the fit. This is a problem in this case because the x-ray data has
    # uncertainty values associated with it (on the order of 1e-4), and the
    # chi^2 residual is proportional to 1 / uncertainty**2. The neutron has no
    # uncertainty, so it's chi^2 is proportional to 1. Thus, my optimizing
    # chi^2 we would give the neutron data practically no weight in the fit. To
    # get around this, we will optimize a different metric.
    #
    # The contribution's residual can be either chi^2, Rw^2, or custom crafted.
    # In this case, we should minimize Rw^2 of each contribution so that each
    # one can contribute roughly equally to the fit.
    xcontribution.setResidualEquation("resv")
    ncontribution.setResidualEquation("resv")

    # Make the FitRecipe and add the FitContributions.
    recipe = FitRecipe()
    recipe.addContribution(xcontribution)
    recipe.addContribution(ncontribution)

    # Now we vary and constrain Parameters as before.
    recipe.addVar(xgenerator.scale, 1, "xscale")
    recipe.addVar(ngenerator.scale, 1, "nscale")
    recipe.addVar(xgenerator.qdamp, 0.01, "xqdamp")
    recipe.addVar(ngenerator.qdamp, 0.01, "nqdamp")
    # delta2 is a non-structual material propery. Thus, we constrain together
    # delta2 Parameter from each PDFGenerator.
    delta2 = recipe.newVar("delta2", 2)
    recipe.constrain(xgenerator.delta2, delta2)
    recipe.constrain(ngenerator.delta2, delta2)

    # We only need to constrain phase properties once since there is a single
    # ObjCrystCrystalParSet for the Crystal.
    phase = xgenerator.phase
    for par in phase.sgpars:
        recipe.addVar(par)
    recipe.B11_0 = 0.1

    # Give the recipe away so it can be used!
    return recipe
コード例 #19
0
def makeRecipe():
    """Make a FitRecipe for fitting three double-gaussian curves to data.

    The separation and amplitude ratio of the double peaks follows a specific
    relationship.  The peaks are broadend according to their position and they
    sit on top of a background. We are seeking the absolute locations of the
    peaks as well as their amplitudes.

    The independent variable is t. The relationship between the double
    peaks is
    sin(t2) / l2 = sin(t1) / l1
    amplitude(peak2) = r * amplitude(peak1)
    The values of l1, l2 and r come from experiment. For this example, we
    use l1 = 1.012, l2 = 1.0 and r = 0.23.

    """

    ## The Profile
    # Create a Profile to hold the experimental and calculated signal.
    profile = Profile()
    x, y, dy = profile.loadtxt("data/threedoublepeaks.dat")

    # Create the contribution
    contribution = FitContribution("peaks")
    contribution.setProfile(profile, xname = "t")
    pi = numpy.pi
    exp = numpy.exp

    # This is a building-block of our profile function
    def gaussian(t, mu, sig):
        return 1/(2*pi*sig**2)**0.5 * exp(-0.5 * ((t-mu)/sig)**2)

    contribution.registerFunction(gaussian, name = "peakshape")

    def delta(t, mu):
        """Calculate a delta-function.

        We don't have perfect precision, so we must make this a very thin
        Gaussian.

        """
        sig = t[1] - t[0]
        return gaussian(t, mu, sig)

    contribution.registerFunction(delta)

    # Here is another one
    bkgdstr = "b0 + b1*t + b2*t**2 + b3*t**3 + b4*t**4 + b5*t**5 + b6*t**6"

    contribution.registerStringFunction(bkgdstr, "bkgd")

    # Now define our fitting equation. We will hardcode the peak ratios.
    contribution.setEquation(
        "A1 * ( convolve( delta(t, mu11), peakshape(t, c, sig11) ) \
         + 0.23*convolve( delta(t, mu12), peakshape(t, c, sig12) ) ) + \
         A2 * ( convolve( delta(t, mu21), peakshape(t, c, sig21) ) \
         + 0.23*convolve( delta(t, mu22), peakshape(t, c, sig22) ) ) + \
         A3 * ( convolve( delta(t, mu31), peakshape(t, c, sig31) ) \
         + 0.23*convolve( delta(t, mu32), peakshape(t, c, sig32) ) ) + \
         bkgd")

    # c is the center of the gaussian.
    contribution.c.value =  x[len(x)/2]

    ## The FitRecipe
    # The FitRecipe lets us define what we want to fit. It is where we can
    # create variables, constraints and restraints.
    recipe = FitRecipe()

    # Here we tell the FitRecipe to use our FitContribution. When the FitRecipe
    # calculates its residual function, it will call on the FitContribution to
    # do part of the work.
    recipe.addContribution(contribution)

    # Vary the amplitudes for each double peak
    recipe.addVar(contribution.A1, 100)
    recipe.addVar(contribution.A2, 100)
    recipe.addVar(contribution.A3, 100)

    # Vary the position of the first of the double peaks
    recipe.addVar(contribution.mu11, 13.0)
    recipe.addVar(contribution.mu21, 24.0)
    recipe.addVar(contribution.mu31, 33.0)

    # Constrain the position of the second double peak
    from numpy import sin, arcsin
    def peakloc(mu):
        """Calculate the location of the second peak given the first."""
        l1 = 1.012
        l2 = 1.0
        return 180 / pi * arcsin( pi / 180 * l2 * sin(mu) / l1 )

    recipe.registerFunction(peakloc)
    recipe.constrain(contribution.mu12, "peakloc(mu11)")
    recipe.constrain(contribution.mu22, "peakloc(mu21)")
    recipe.constrain(contribution.mu32, "peakloc(mu31)")

    # Vary the width of the peaks. We know the functional form of the peak
    # broadening.
    sig0 = recipe.newVar("sig0", 0.001)
    dsig = recipe.newVar("dsig", 4)

    def sig(sig0, dsig, mu):
        """Calculate the peak broadening with respect to position."""
        return sig0 * (1 - dsig * mu**2);

    recipe.registerFunction(sig)
    recipe.fix("mu")
    # Now constrain the peak widths to this
    recipe.sig0.value = 0.001
    recipe.dsig.value = 4.0
    recipe.constrain(contribution.sig11, "sig(sig0, dsig, mu11)")
    recipe.constrain(contribution.sig12, "sig(sig0, dsig, mu12)",
            ns = {"mu12" : contribution.mu12} )
    recipe.constrain(contribution.sig21, "sig(sig0, dsig, mu21)")
    recipe.constrain(contribution.sig22, "sig(sig0, dsig, mu22)",
            ns = {"mu22" : contribution.mu22} )
    recipe.constrain(contribution.sig31, "sig(sig0, dsig, mu31)")
    recipe.constrain(contribution.sig32, "sig(sig0, dsig, mu32)",
            ns = {"mu32" : contribution.mu32} )

    # Also the background
    recipe.addVar(contribution.b0, 0, tag = "bkgd")
    recipe.addVar(contribution.b1, 0, tag = "bkgd")
    recipe.addVar(contribution.b2, 0, tag = "bkgd")
    recipe.addVar(contribution.b3, 0, tag = "bkgd")
    recipe.addVar(contribution.b4, 0, tag = "bkgd")
    recipe.addVar(contribution.b5, 0, tag = "bkgd")
    recipe.addVar(contribution.b6, 0, tag = "bkgd")
    return recipe
コード例 #20
0
print("fixed:", rec.fixednames, "-->", rec.fixedvalues)

# The fit can be rerun with a constant variable B.
leastsq(rec.residual, rec.values)
print(FitResults(rec))
plt.plot(linedata.x, linedata.y, 'x', linedata.x, linedata.ycalc, '-')
plt.title('Line fit for variable B fixed to B=0')

# <demo> --- stop ---

# Fixed variables may be released with the "free" function.
# free("all") releases all fixed variables.
rec.free('all')

# Variables may be constrained to a result of an expression.
rec.constrain(rec.A, "2 * B")

# Perform linear fit where slope is twice the offset.
leastsq(rec.residual, rec.values)
print(FitResults(rec))
plt.plot(linedata.x, linedata.y, 'x', linedata.x, linedata.ycalc, '-')
plt.title('Line fit for variable A constrained to A = 2*B')

# <demo> --- stop ---

# Constraint expressions can be removed by calling the unconstrain function.
rec.unconstrain(rec.A)

# Variables may be restrained to a specific range.  Here "ub" is the upper
# boundary and "sig" acts as a standard deviation for ((x - ub)/sig)**2
# penalty function.
コード例 #21
0
def makeRecipe(stru1, stru2, datname):
    """Create a fitting recipe for crystalline PDF data."""

    ## The Profile
    profile = Profile()

    # Load data and add it to the profile
    parser = PDFParser()
    parser.parseFile(datname)
    profile.loadParsedData(parser)
    profile.setCalculationRange(xmin=1.5, xmax = 45, dx = 0.1)

    ## The ProfileGenerator
    # In order to fit the core and shell phases simultaneously, we must use two
    # PDFGenerators.
    #
    # The generator for the CdS core. We call it "G_CdS" and will use this name
    # later when we set the fitting equation in the FitContribution.
    generator_cds = PDFGenerator("G_CdS")
    generator_cds.setStructure(stru1)
    generator_cds.setQmax(26)
    generator_cds.qdamp.value = 0.0396
    # The generator for the ZnS shell. We call it "G_ZnS".
    generator_zns = PDFGenerator("G_ZnS")
    generator_zns.setStructure(stru2)
    generator_zns.setQmax(26)
    generator_zns.qdamp.value = 0.0396

    ## The FitContribution
    # Add both generators and the profile to the FitContribution.
    contribution = FitContribution("cdszns")
    contribution.addProfileGenerator(generator_cds)
    contribution.addProfileGenerator(generator_zns)
    contribution.setProfile(profile, xname = "r")

    # Set up the characteristic functions. We use a spherical CF for the core
    # and a spherical shell CF for the shell. Since this is set up as two
    # phases, we implicitly assume that the core-shell correlations contribute
    # very little to the PDF.
    from diffpy.srfit.pdf.characteristicfunctions import sphericalCF, shellCF
    contribution.registerFunction(sphericalCF, name = "f_CdS")
    contribution.registerFunction(shellCF, name = "f_ZnS")

    # Write the fitting equation. We want to sum the PDFs from each phase and
    # multiply it by a scaling factor.
    contribution.setEquation("scale * (f_CdS * G_CdS +  f_ZnS * G_ZnS)")

    # Make the FitRecipe and add the FitContribution.
    recipe = FitRecipe()
    recipe.addContribution(contribution)

    # Vary the inner radius and thickness of the shell. Constrain the core
    # diameter to twice the shell radius.
    recipe.addVar(contribution.radius, 15)
    recipe.addVar(contribution.thickness, 11)
    recipe.constrain(contribution.psize, "2 * radius")

    ## 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_CdS", 0.7)
    recipe.constrain(generator_cds.scale, "scale_CdS")
    recipe.constrain(generator_zns.scale, "1 - scale_CdS")
    # We also want the resolution factor to be the same on each.

    # Vary the gloabal scale as well.
    recipe.addVar(contribution.scale, 0.3)

    # Now we can configure the structural parameters. We tag the different
    # structural variables so we can easily turn them on and off in the
    # subsequent refinement.
    phase_cds = generator_cds.phase
    for par in phase_cds.sgpars.latpars:
        recipe.addVar(par, name = par.name + "_cds", tag = "lat")
    for par in phase_cds.sgpars.adppars:
        recipe.addVar(par, 1, name = par.name + "_cds", tag = "adp")
    recipe.addVar(phase_cds.sgpars.xyzpars.z_1, name = "z_1_cds", tag = "xyz")
    # Since we know these have stacking disorder, constrain the B33 adps for
    # each atom type.
    recipe.constrain("B33_1_cds", "B33_0_cds")
    recipe.addVar(generator_cds.delta2, name = "delta2_cds", value = 5)

    phase_zns = generator_zns.phase
    for par in phase_zns.sgpars.latpars:
        recipe.addVar(par, name = par.name + "_zns", tag = "lat")
    for par in phase_zns.sgpars.adppars:
        recipe.addVar(par, 1, name = par.name + "_zns", tag = "adp")
    recipe.addVar(phase_zns.sgpars.xyzpars.z_1, name = "z_1_zns", tag = "xyz")
    recipe.constrain("B33_1_zns", "B33_0_zns")
    recipe.addVar(generator_zns.delta2, name = "delta2_zns", value = 2.5)

    # Give the recipe away so it can be used!
    return recipe
コード例 #22
0
ファイル: coreshellnp.py プロジェクト: mmckerns/diffpy.srfit
def makeRecipe(stru1, stru2, datname):
    """Create a fitting recipe for crystalline PDF data."""

    ## The Profile
    profile = Profile()

    # Load data and add it to the profile
    parser = PDFParser()
    parser.parseFile(datname)
    profile.loadParsedData(parser)
    profile.setCalculationRange(xmin=1.5, xmax=45, dx=0.1)

    ## The ProfileGenerator
    # In order to fit the core and shell phases simultaneously, we must use two
    # PDFGenerators.
    #
    # The generator for the CdS core. We call it "G_CdS" and will use this name
    # later when we set the fitting equation in the FitContribution.
    generator_cds = PDFGenerator("G_CdS")
    generator_cds.setStructure(stru1)
    generator_cds.setQmax(26)
    generator_cds.qdamp.value = 0.0396
    # The generator for the ZnS shell. We call it "G_ZnS".
    generator_zns = PDFGenerator("G_ZnS")
    generator_zns.setStructure(stru2)
    generator_zns.setQmax(26)
    generator_zns.qdamp.value = 0.0396

    ## The FitContribution
    # Add both generators and the profile to the FitContribution.
    contribution = FitContribution("cdszns")
    contribution.addProfileGenerator(generator_cds)
    contribution.addProfileGenerator(generator_zns)
    contribution.setProfile(profile, xname="r")

    # Set up the characteristic functions. We use a spherical CF for the core
    # and a spherical shell CF for the shell. Since this is set up as two
    # phases, we implicitly assume that the core-shell correlations contribute
    # very little to the PDF.
    from diffpy.srfit.pdf.characteristicfunctions import sphericalCF, shellCF
    contribution.registerFunction(sphericalCF, name="f_CdS")
    contribution.registerFunction(shellCF, name="f_ZnS")

    # Write the fitting equation. We want to sum the PDFs from each phase and
    # multiply it by a scaling factor.
    contribution.setEquation("scale * (f_CdS * G_CdS +  f_ZnS * G_ZnS)")

    # Make the FitRecipe and add the FitContribution.
    recipe = FitRecipe()
    recipe.addContribution(contribution)

    # Vary the inner radius and thickness of the shell. Constrain the core
    # diameter to twice the shell radius.
    recipe.addVar(contribution.radius, 15)
    recipe.addVar(contribution.thickness, 11)
    recipe.constrain(contribution.psize, "2 * radius")

    ## 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_CdS", 0.7)
    recipe.constrain(generator_cds.scale, "scale_CdS")
    recipe.constrain(generator_zns.scale, "1 - scale_CdS")
    # We also want the resolution factor to be the same on each.

    # Vary the gloabal scale as well.
    recipe.addVar(contribution.scale, 0.3)

    # Now we can configure the structural parameters. We tag the different
    # structural variables so we can easily turn them on and off in the
    # subsequent refinement.
    phase_cds = generator_cds.phase
    for par in phase_cds.sgpars.latpars:
        recipe.addVar(par, name=par.name + "_cds", tag="lat")
    for par in phase_cds.sgpars.adppars:
        recipe.addVar(par, 1, name=par.name + "_cds", tag="adp")
    recipe.addVar(phase_cds.sgpars.xyzpars.z_1, name="z_1_cds", tag="xyz")
    # Since we know these have stacking disorder, constrain the B33 adps for
    # each atom type.
    recipe.constrain("B33_1_cds", "B33_0_cds")
    recipe.addVar(generator_cds.delta2, name="delta2_cds", value=5)

    phase_zns = generator_zns.phase
    for par in phase_zns.sgpars.latpars:
        recipe.addVar(par, name=par.name + "_zns", tag="lat")
    for par in phase_zns.sgpars.adppars:
        recipe.addVar(par, 1, name=par.name + "_zns", tag="adp")
    recipe.addVar(phase_zns.sgpars.xyzpars.z_1, name="z_1_zns", tag="xyz")
    recipe.constrain("B33_1_zns", "B33_0_zns")
    recipe.addVar(generator_zns.delta2, name="delta2_zns", value=2.5)

    # Give the recipe away so it can be used!
    return recipe
コード例 #23
0
def makeRecipe(stru1, stru2, stru3, datname):
    """Create a fitting recipe for crystalline PDF data."""

    ## The Profile
    profile = Profile()

    # Load data and add it to the profile
    parser = PDFParser()
    parser.parseFile(datname)
    profile.loadParsedData(parser)
    profile.setCalculationRange(xmin=1, xmax = 40, dx = 0.01)

    ## The ProfileGenerator
    generator_MEF_Cryst_B = PDFGenerator("G_MEF_Cryst_B")
    generator_MEF_Cryst_B.setStructure(stru1, periodic = True)
    generator_MEF_Mole_B = DebyePDFGenerator("G_MEF_Mole_B")
    generator_MEF_Mole_B.setStructure(stru2, periodic = False)
    generator_MEF_Intra = DebyePDFGenerator("G_MEF_Intra")
    generator_MEF_Intra.setStructure(stru3, periodic = False)

    ## The FitContribution
    # Add both generators to the FitContribution. Add the Profile. This will
    # send the metadata to the generators.
    contribution = FitContribution("MEF")
    contribution.addProfileGenerator(generator_MEF_Cryst_B)
    contribution.addProfileGenerator(generator_MEF_Mole_B)
    contribution.addProfileGenerator(generator_MEF_Intra)
    contribution.setProfile(profile, xname = "r")
    #write down the fit equation:
    #(G_MEF_Cryst_B - G_MEF_Mole_B) gives the intermolecular PDF, using a larger atomic displacement parameter
    #G_MEF_Intra gives intramolecular PDF, using a smaller atomic displacement parameter.
    #The sum of both parts gives the total PDF.
    contribution.setEquation("scale * (G_MEF_Cryst_B - G_MEF_Mole_B + G_MEF_Intra)")

    # Make the FitRecipe and add the FitContribution.
    recipe = FitRecipe()
    recipe.addContribution(contribution)

    qdamp = 0.02902
    generator_MEF_Cryst_B.qdamp.value = qdamp
    generator_MEF_Mole_B.qdamp.value = qdamp
    generator_MEF_Intra.qdamp.value = qdamp

    # Vary the gloabal scale as well.
    recipe.addVar(contribution.scale, 1) 

#############################################################################################
############### First the MEF_Cryst_B parameters ############################################
#############################################################################################
    phase_MEF_Cryst_B = generator_MEF_Cryst_B.phase

    lat = phase_MEF_Cryst_B.getLattice()
    atoms = phase_MEF_Cryst_B.getScatterers()
    
    recipe.newVar("Uiso_Inter", 0.05, tag = "T1")
    recipe.newVar("lat_a", 14.556, tag = "lat")
    recipe.newVar("lat_b", 6.811, tag = "lat")
    recipe.newVar("lat_c", 7.657, tag = "lat")
    recipe.newVar("alpha", 119.57, tag = "lat")
    recipe.newVar("beta", 103.93, tag = "lat")
    recipe.newVar("gamma", 91.30, tag = "lat")

    recipe.constrain(lat.a, "lat_a")
    recipe.constrain(lat.b, "lat_b")
    recipe.constrain(lat.c, "lat_c")
    recipe.constrain(lat.alpha, "alpha")
    recipe.constrain(lat.beta, "beta")
    recipe.constrain(lat.gamma, "gamma")
    
    for atom in atoms:
    	if atom.element.title() == "N":
             recipe.constrain(atom.Uiso, "Uiso_Inter")
             
    	elif atom.element.title() == "O":
             recipe.constrain(atom.Uiso, "Uiso_Inter")

    	elif atom.element.title() == "C":
             recipe.constrain(atom.Uiso, "Uiso_Inter")

    	elif atom.element.title() == "H":
             recipe.constrain(atom.Uiso, "Uiso_Inter")

    generator_MEF_Cryst_B.delta2.value = 0


#############################################################################################
############### Second the MEF_Mole_B parameters ############################################
#############################################################################################
    phase_MEF_Mole_B = generator_MEF_Mole_B.phase
    generator_MEF_Mole_B.setQmin(0.0)
    generator_MEF_Mole_B.setQmax(24.0)
    recipe.newVar("zoom_Mole_B", 1, tag = "lat2") 

    lat = phase_MEF_Mole_B.getLattice()
    recipe.constrain(lat.a, "zoom_Mole_B")
    recipe.constrain(lat.b, "zoom_Mole_B")
    recipe.constrain(lat.c, "zoom_Mole_B")
   # Constrain fractional xyz parameters
    atoms = phase_MEF_Mole_B.getScatterers()
   # Constrain ADPs

    for atom in atoms:
    	if atom.element.title() == "C":
             recipe.constrain(atom.Uiso, "Uiso_Inter")

    	elif atom.element.title() == "O":
             recipe.constrain(atom.Uiso, "Uiso_Inter")

    	elif atom.element.title() == "N":
             recipe.constrain(atom.Uiso, "Uiso_Inter")

    	elif atom.element.title() == "H":
             recipe.constrain(atom.Uiso, "Uiso_Inter")

    generator_MEF_Mole_B.delta2.value = 0

#############################################################################################
############### Third the intra molecule parameters##########################################
#############################################################################################
    phase_MEF_Intra = generator_MEF_Intra.phase
    generator_MEF_Intra.setQmin(0.0)
    generator_MEF_Intra.setQmax(24.0)
    recipe.newVar("zoom_Intra", 1, tag = "lat3") 

    lat = phase_MEF_Intra.getLattice()
    recipe.constrain(lat.a, "zoom_Intra")
    recipe.constrain(lat.b, "zoom_Intra")
    recipe.constrain(lat.c, "zoom_Intra")
   # Constrain fractional xyz parameters
    atoms = phase_MEF_Intra.getScatterers()
   # Constrain ADPs
    recipe.newVar("Uiso_Intra", 0.005, tag = "T2") 
    
    for atom in atoms:
    	if atom.element.title() == "C":
             recipe.constrain(atom.Uiso, "Uiso_Intra")

    	elif atom.element.title() == "O":
             recipe.constrain(atom.Uiso, "Uiso_Intra")

    	elif atom.element.title() == "N":
             recipe.constrain(atom.Uiso, "Uiso_Intra")

    	elif atom.element.title() == "H":
             recipe.constrain(atom.Uiso, "Uiso_Intra")

    generator_MEF_Intra.delta2.value = 0

    # Give the recipe away so it can be used!
    return recipe
コード例 #24
0
ファイル: fitCdSeNP.py プロジェクト: DanOlds/diffpy_examples
cdsePDF.CdSe.setQmin(1.0)

# The Qmax used in PDF transformation should also be specfied
cdsePDF.CdSe.setQmax(20.0)

# We create the variables of ADP and assign the initial value to them. In this
# example, we use isotropic ADP for all atoms
CdBiso = cdseFit.newVar("Cd_Biso", value=1.0)
SeBiso = cdseFit.newVar("Se_Biso", value=1.0)

# For all atoms in the structure model, we constrain their Biso according to
# their species
atoms = cdsePDF.CdSe.phase.getScatterers()
for atom in atoms:
    if atom.element == 'Cd':
        cdseFit.constrain(atom.Biso, CdBiso)
    elif atom.element == 'Se':
        cdseFit.constrain(atom.Biso, SeBiso)

# Now we create a zoomscale factor which stretches the structure model, this is
# useful when you want to fit the bond length. Note that the relative position
# of atoms are not changed during the refinements
zoomscale = cdseFit.newVar('zoomscale', value=1.0)

# Here is a simple we to assign the zoomscale to the structure. Note that this
# only works for NON-PERIODIC structure
lattice = cdsePDF.CdSe.phase.getLattice()
cdseFit.constrain(lattice.a, zoomscale)
cdseFit.constrain(lattice.b, zoomscale)
cdseFit.constrain(lattice.c, zoomscale)
コード例 #25
0
def makeRecipe(strufile, datname):
    """Create a recipe that uses the IntensityGenerator.

    This will create a FitContribution that uses the IntensityGenerator,
    associate this with a Profile, and use this to define a FitRecipe.

    """

    ## The Profile
    # Create a Profile. This will hold the experimental and calculated signal.
    profile = Profile()

    # Load data and add it to the profile
    x, y, u = profile.loadtxt(datname)

    ## The ProfileGenerator
    # Create an IntensityGenerator named "I". This will be the name we use to
    # refer to the generator from within the FitContribution equation.  We also
    # need to load the model structure we're using.
    generator = IntensityGenerator("I")
    generator.setStructure(strufile)

    ## The FitContribution
    # Create a FitContribution, that will associate the Profile with the
    # ProfileGenerator.  The ProfileGenerator will be accessible as an
    # attribute of the FitContribution by its name ("I").  We also want to tell
    # the FitContribution to name the x-variable of the profile "q", so we can
    # use it in equations with this name.
    contribution = FitContribution("bucky")
    contribution.addProfileGenerator(generator)
    contribution.setProfile(profile, xname = "q")

    # Now we're ready to define the fitting equation for the FitContribution.
    # We need to modify the intensity calculation, and we'll do that from
    # within the fitting equation for the sake of instruction. We want to
    # modify the calculation in three ways.  We want to scale it, add a
    # polynomial background, and broaden the peaks.
    #
    # There is added benefit for defining these operations outside of the
    # IntensityGenerator. By combining the different parts of the calculation
    # within the fitting equation, the time-consuming iofq calculation is only
    # performed when a structural Parameter is changed. If only non-structural
    # parameters are changed, such as the background and broadening Parameters,
    # then then previously computed iofq value will be used to compute the
    # contribution equation.  The benefit in this is very apparent when
    # refining the recipe with the LM optimizer, which only changes two
    # variables at a time most of the time. Note in the refinement output how
    # many times the residual is calculated, versus how many times iofq is
    # called when using the scipyOptimize function.

    # We will define the background as a string.

    bkgdstr = "b0 + b1*q + b2*q**2 + b3*q**3 + b4*q**4 + b5*q**5 + b6*q**6 +\
               b7*q**7 + b8*q**8 + b9*q**9"

    # This creates a callable equation named "bkgd" within the FitContribution,
    # and turns the polynomial coefficients into Parameters.
    eq = contribution.registerStringFunction(bkgdstr, "bkgd")

    # We will create the broadening function that we need by creating a python
    # function and registering it with the FitContribution.
    pi = numpy.pi
    exp = numpy.exp
    def gaussian(q, q0, width):
        return 1/(2*pi*width**2)**0.5 * exp(-0.5 * ((q-q0)/width)**2)

    # This registers the python function and extracts the name and creates
    # Parameters from the arguments.
    contribution.registerFunction(gaussian)

    # Center the Gaussian so it is not truncated.
    contribution.q0.value = x[len(x)/2]

    # Now we can incorporate the scale and bkgd into our calculation. We also
    # convolve the signal with the Gaussian to broaden it. Recall that we don't
    # need to supply arguments to the registered functions unless we want to
    # make changes to their input values.
    contribution.setEquation("scale * convolve(I, gaussian) + bkgd")

    # Make the FitRecipe and add the FitContribution.
    recipe = FitRecipe()
    recipe.addContribution(contribution)

    # Specify which parameters we want to refine.
    recipe.addVar(contribution.b0, 0)
    recipe.addVar(contribution.b1, 0)
    recipe.addVar(contribution.b2, 0)
    recipe.addVar(contribution.b3, 0)
    recipe.addVar(contribution.b4, 0)
    recipe.addVar(contribution.b5, 0)
    recipe.addVar(contribution.b6, 0)
    recipe.addVar(contribution.b7, 0)
    recipe.addVar(contribution.b8, 0)
    recipe.addVar(contribution.b9, 0)

    # We also want to adjust the scale and the convolution width
    recipe.addVar(contribution.scale, 1)
    recipe.addVar(contribution.width, 0.1)

    # We can also refine structural parameters. Here we extract the
    # DiffpyStructureParSet from the intensity generator and use the parameters
    # like we would any others.
    phase = generator.phase

    # We want to allow for isotropic expansion, so we'll constrain the lattice
    # parameters to the same value (the lattice is cubic). Note that we
    # constrain to the "a" Parameter directly. In previous examples, we
    # constrained to a Variable by name. This has the same effect.
    lattice = phase.getLattice()
    a = lattice.a
    recipe.addVar(a)
    recipe.constrain(lattice.b, a)
    recipe.constrain(lattice.c, a)
    # We want to refine the thermal parameters as well. We will add a new
    # Variable that we call "Uiso" and constrain the atomic Uiso values to
    # this. Note that we don't give Uiso an initial value. The initial value
    # will be inferred from the following constraints.
    Uiso = recipe.newVar("Uiso")
    for atom in phase.getScatterers():
        recipe.constrain(atom.Uiso, Uiso)

    # Give the recipe away so it can be used!
    return recipe
コード例 #26
0
ファイル: nppdfsas.py プロジェクト: cfarrow/diffpy.srfit
def makeRecipe(ciffile, grdata, iqdata):
    """Make complex-modeling recipe where I(q) and G(r) are fit
    simultaneously.

    The fit I(q) is fed into the calculation of G(r), which provides feedback
    for the fit parameters of both.
    
    """

    # Create a PDF contribution as before
    pdfprofile = Profile()
    pdfparser = PDFParser()
    pdfparser.parseFile(grdata)
    pdfprofile.loadParsedData(pdfparser)
    pdfprofile.setCalculationRange(xmin = 0.1, xmax = 20)

    pdfcontribution = FitContribution("pdf")
    pdfcontribution.setProfile(pdfprofile, xname = "r")

    pdfgenerator = PDFGenerator("G")
    pdfgenerator.setQmax(30.0)
    stru = CreateCrystalFromCIF(file(ciffile))
    pdfgenerator.setStructure(stru)
    pdfcontribution.addProfileGenerator(pdfgenerator)
    pdfcontribution.setResidualEquation("resv")

    # Create a SAS contribution as well. We assume the nanoparticle is roughly
    # elliptical.
    sasprofile = Profile()
    sasparser = SASParser()
    sasparser.parseFile(iqdata)
    sasprofile.loadParsedData(sasparser)

    sascontribution = FitContribution("sas")
    sascontribution.setProfile(sasprofile)

    from sans.models.EllipsoidModel import EllipsoidModel
    model = EllipsoidModel()
    sasgenerator = SASGenerator("generator", model)
    sascontribution.addProfileGenerator(sasgenerator)
    sascontribution.setResidualEquation("resv")

    # Now we set up a characteristic function calculator that depends on the
    # sas model.
    cfcalculator = SASCF("f", model)

    # Register the calculator with the pdf contribution and define the fitting
    # equation.
    pdfcontribution.registerCalculator(cfcalculator)
    # The PDF for a nanoscale crystalline is approximated by
    # Gnano = f * Gcryst
    pdfcontribution.setEquation("f * G")

    # Moving on
    recipe = FitRecipe()
    recipe.addContribution(pdfcontribution)
    recipe.addContribution(sascontribution)

    # PDF
    phase = pdfgenerator.phase
    for par in phase.sgpars:
        recipe.addVar(par)

    recipe.addVar(pdfgenerator.scale, 1)
    recipe.addVar(pdfgenerator.delta2, 0)

    # SAS
    recipe.addVar(sasgenerator.scale, 1, name = "iqscale")
    recipe.addVar(sasgenerator.radius_a, 10)
    recipe.addVar(sasgenerator.radius_b, 10)

    # Even though the cfcalculator and sasgenerator depend on the same sas
    # model, we must still constrain the cfcalculator Parameters so that it is
    # informed of changes in the refined parameters.
    recipe.constrain(cfcalculator.radius_a, "radius_a")
    recipe.constrain(cfcalculator.radius_b, "radius_b")

    return recipe
コード例 #27
0
ファイル: npintensity.py プロジェクト: cfarrow/diffpy.srfit
def makeRecipe(strufile, datname):
    """Create a recipe that uses the IntensityGenerator.

    This will create a FitContribution that uses the IntensityGenerator,
    associate this with a Profile, and use this to define a FitRecipe.

    """

    ## The Profile
    # Create a Profile. This will hold the experimental and calculated signal.
    profile = Profile()

    # Load data and add it to the profile
    x, y, u = profile.loadtxt(datname)

    ## The ProfileGenerator
    # Create an IntensityGenerator named "I". This will be the name we use to
    # refer to the generator from within the FitContribution equation.  We also
    # need to load the model structure we're using.
    generator = IntensityGenerator("I")
    generator.setStructure(strufile)
    
    ## The FitContribution
    # Create a FitContribution, that will associate the Profile with the
    # ProfileGenerator.  The ProfileGenerator will be accessible as an
    # attribute of the FitContribution by its name ("I").  We also want to tell
    # the FitContribution to name the x-variable of the profile "q", so we can
    # use it in equations with this name.
    contribution = FitContribution("bucky")
    contribution.addProfileGenerator(generator)
    contribution.setProfile(profile, xname = "q")

    # Now we're ready to define the fitting equation for the FitContribution.
    # We need to modify the intensity calculation, and we'll do that from
    # within the fitting equation for the sake of instruction. We want to
    # modify the calculation in three ways.  We want to scale it, add a
    # polynomial background, and broaden the peaks. 
    #
    # There is added benefit for defining these operations outside of the
    # IntensityGenerator. By combining the different parts of the calculation
    # within the fitting equation, the time-consuming iofq calculation is only
    # performed when a structural Parameter is changed. If only non-structural
    # parameters are changed, such as the background and broadening Parameters,
    # then then previously computed iofq value will be used to compute the
    # contribution equation.  The benefit in this is very apparent when
    # refining the recipe with the LM optimizer, which only changes two
    # variables at a time most of the time. Note in the refinement output how
    # many times the residual is calculated, versus how many times iofq is
    # called when using the scipyOptimize function.

    # We will define the background as a string.

    bkgdstr = "b0 + b1*q + b2*q**2 + b3*q**3 + b4*q**4 + b5*q**5 + b6*q**6 +\
               b7*q**7 + b8*q**8 + b9*q**9"

    # This creates a callable equation named "bkgd" within the FitContribution,
    # and turns the polynomial coefficients into Parameters.
    eq = contribution.registerStringFunction(bkgdstr, "bkgd")

    # We will create the broadening function that we need by creating a python
    # function and registering it with the FitContribution.
    pi = numpy.pi
    exp = numpy.exp
    def gaussian(q, q0, width):
        return 1/(2*pi*width**2)**0.5 * exp(-0.5 * ((q-q0)/width)**2)

    # This registers the python function and extracts the name and creates
    # Parameters from the arguments.
    contribution.registerFunction(gaussian)

    # Center the Gaussian so it is not truncated.
    contribution.q0.value = x[len(x)/2]

    # Now we can incorporate the scale and bkgd into our calculation. We also
    # convolve the signal with the Gaussian to broaden it. Recall that we don't
    # need to supply arguments to the registered functions unless we want to
    # make changes to their input values.
    contribution.setEquation("scale * convolve(I, gaussian) + bkgd")

    # Make the FitRecipe and add the FitContribution.
    recipe = FitRecipe()
    recipe.addContribution(contribution)

    # Specify which parameters we want to refine.
    recipe.addVar(contribution.b0, 0)
    recipe.addVar(contribution.b1, 0)
    recipe.addVar(contribution.b2, 0)
    recipe.addVar(contribution.b3, 0)
    recipe.addVar(contribution.b4, 0)
    recipe.addVar(contribution.b5, 0)
    recipe.addVar(contribution.b6, 0)
    recipe.addVar(contribution.b7, 0)
    recipe.addVar(contribution.b8, 0)
    recipe.addVar(contribution.b9, 0)

    # We also want to adjust the scale and the convolution width
    recipe.addVar(contribution.scale, 1)
    recipe.addVar(contribution.width, 0.1)

    # We can also refine structural parameters. Here we extract the
    # DiffpyStructureParSet from the intensity generator and use the parameters
    # like we would any others.
    phase = generator.phase

    # We want to allow for isotropic expansion, so we'll constrain the lattice
    # parameters to the same value (the lattice is cubic). Note that we
    # constrain to the "a" Parameter directly. In previous examples, we
    # constrained to a Variable by name. This has the same effect.
    lattice = phase.getLattice()
    a = lattice.a
    recipe.addVar(a)
    recipe.constrain(lattice.b, a)
    recipe.constrain(lattice.c, a)
    # We want to refine the thermal paramters as well. We will add a new
    # Variable that we call "Uiso" and constrain the atomic Uiso values to
    # this. Note that we don't give Uiso an initial value. The initial value
    # will be inferred from the following constraints.
    Uiso = recipe.newVar("Uiso")
    for atom in phase.getScatterers():
        recipe.constrain(atom.Uiso, Uiso)

    # Give the recipe away so it can be used!
    return recipe
コード例 #28
0
pdfcntb.setEquation('scale * (nphmol + widecrystal - widemolecule)')

nphfit = FitRecipe()
nphfit.clearFitHooks()
nphfit.addContribution(pdfcntb)

nphfit.addVar(pdfcntb.scale, name='scale')
pcrystal = pdfcntb.widecrystal.phase
# unit cell parameters
nphfit.addVar(pcrystal.a)
nphfit.addVar(pcrystal.b)
nphfit.addVar(pcrystal.c)
# cell-angle beta is in radians in ObjCryst Crystal
# we will refine angle in degrees.
nphfit.newVar('beta', value=np.degrees(pcrystal.beta.value))
nphfit.constrain(pcrystal.beta, 'radians(beta)')
# all carbon species have the same displacement parameter,
# it is sufficient to add constraint for the C1 atom
pmol = pdfcntb.nphmol.phase
nphfit.addVar(pmol.C1.Biso, name='Biso', value=1.0)

# create new variable for intermolecular displacements.
# constrain the fwhm of a Gaussian peak from 2 atoms accordingly.
nphfit.newVar('Binter', value=1.5)
nphfit.constrain(pdfcntb.widecrystal.fwhm, 'sqrt(2 * log(2) * Binter) / pi')
nphfit.constrain(pdfcntb.widemolecule.fwhm, 'sqrt(2 * log(2) * Binter) / pi')

leastsq(nphfit.residual, nphfit.values)
results = FitResults(nphfit)

r = pdfcntb.r.value