예제 #1
0
    def testGenerator(self):

        # Test generator output
        SphereModel = sasimport('sas.models.SphereModel').SphereModel
        model = SphereModel()
        gen = SASGenerator("sphere", model)

        for pname in model.params:
            defval = model.getParam(pname)
            par = gen.get(pname)
            self.assertEqual(defval, par.getValue())
            # Test setting values
            par.setValue(1.0)
            self.assertEqual(1.0, par.getValue())
            self.assertEqual(1.0, model.getParam(pname))
            par.setValue(defval)
            self.assertEqual(defval, par.getValue())
            self.assertEqual(defval, model.getParam(pname))

        r = numpy.arange(1, 10, 0.1, dtype=float)
        y = gen(r)
        refy = model.evalDistribution(r)
        diff = y - refy
        res = numpy.dot(diff, diff)
        self.assertAlmostEqual(0, res)

        return
예제 #2
0
    def testGenerator2(self):

        # Test generator with a profile
        EllipsoidModel = sasimport('sas.models.EllipsoidModel').EllipsoidModel
        model = EllipsoidModel()
        gen = SASGenerator("ellipsoid", model)

        # Load the data using SAS tools
        Loader = sasimport('sas.dataloader.loader').Loader
        loader = Loader()
        data = datafile("sas_ellipsoid_testdata.txt")
        datainfo = loader.load(data)
        profile = SASProfile(datainfo)

        gen.setProfile(profile)
        gen.scale.value = 1.0
        gen.radius_a.value = 20
        gen.radius_b.value = 400
        gen.background.value = 0.01

        y = gen(profile.xobs)
        diff = profile.yobs - y
        res = numpy.dot(diff, diff)
        self.assertAlmostEqual(0, res)
        return
예제 #3
0
    def testGenerator2(self):

        # Test generator with a profile
        EllipsoidModel = sasimport('sas.models.EllipsoidModel').EllipsoidModel
        model = EllipsoidModel()
        gen = SASGenerator("ellipsoid", model)

        # Load the data using SAS tools
        Loader = sasimport('sas.dataloader.loader').Loader
        loader = Loader()
        data = datafile("sas_ellipsoid_testdata.txt")
        datainfo = loader.load(data)
        profile = SASProfile(datainfo)

        gen.setProfile(profile)
        gen.scale.value = 1.0
        gen.radius_a.value = 20
        gen.radius_b.value = 400
        gen.background.value = 0.01

        y = gen(profile.xobs)
        diff = profile.yobs - y
        res = numpy.dot(diff, diff)
        self.assertAlmostEqual(0, res)
        return
예제 #4
0
    def testGenerator(self):

        # Test generator output
        SphereModel = sasimport('sas.models.SphereModel').SphereModel
        model = SphereModel()
        gen = SASGenerator("sphere", model)

        for pname in model.params:
            defval = model.getParam(pname)
            par = gen.get(pname)
            self.assertEquals(defval, par.getValue())
            # Test setting values
            par.setValue(1.0)
            self.assertEquals(1.0, par.getValue())
            self.assertEquals(1.0, model.getParam(pname))
            par.setValue(defval)
            self.assertEquals(defval, par.getValue())
            self.assertEquals(defval, model.getParam(pname))


        r = numpy.arange(1, 10, 0.1, dtype = float)
        y = gen(r)
        refy = model.evalDistribution(r)
        diff = y - refy
        res = numpy.dot(diff, diff)
        self.assertAlmostEqual(0, res)

        return
예제 #5
0
def makeRecipe(datname):
    """Create a fitting recipe for ellipsoidal SAS data."""

    ## The Profile
    # This will be used to store the observed and calculated I(Q) data.
    profile = Profile()

    # Load data and add it to the Profile. We use a SASParser to load the data
    # properly and pass the metadata along.
    parser = SASParser()
    parser.parseFile(datname)
    profile.loadParsedData(parser)

    ## The ProfileGenerator
    # The SASGenerator is for configuring and calculating a SAS profile. We use
    # a sans model to configure and serve as the calculation engine of the
    # generator. This allows us to use the full sans model creation
    # capabilities, and tie this into SrFit when we want to fit a model to
    # data. The documentation for the various sans models can be found at
    # http://danse.chem.utk.edu/sansview.html.
    from sans.models.EllipsoidModel import EllipsoidModel
    model = EllipsoidModel()
    generator = SASGenerator("generator", model)

    ## The FitContribution
    # Here we associate the Profile and ProfileGenerator, as has been done
    # before.
    contribution = FitContribution("ellipsoid")
    contribution.addProfileGenerator(generator)
    contribution.setProfile(profile, xname="q")

    # We want to fit the log of the signal to the log of the data so that the
    # higher-Q information remains significant. There are no I(Q) uncertainty
    # values with the data, so we do not need to worry about the effect this
    # will have on the estimated parameter uncertainties.
    contribution.setResidualEquation("log(eq) - log(y)")

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

    ## Configure the fit variables
    # The SASGenerator uses the parameters from the params and dispersion
    # attribues of the model. These vary from model to model, but are adopted
    # as SrFit Parameters within the generator. Whereas the dispersion
    # parameters are accessible as, e.g. "radius.width", within the
    # SASGenerator these are named like "radius_width".
    #
    # We want to fit the scale factor, radii and background factors.
    recipe.addVar(generator.scale, 1)
    recipe.addVar(generator.radius_a, 50)
    recipe.addVar(generator.radius_b, 500)
    recipe.addVar(generator.background, 0)

    # Give the recipe away so it can be used!
    return recipe
예제 #6
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