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
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
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
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
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