def testParser(self): data = datafile("sas_ascii_test_1.txt") parser = SASParser() parser.parseFile(data) x, y, dx, dy = parser.getData() testx = numpy.array([0.002618, 0.007854, 0.01309, 0.01832, 0.02356, 0.02879, 0.03402, 0.03925, 0.04448, 0.0497]) diff = testx - x res = numpy.dot(diff, diff) self.assertAlmostEqual(0, res) testy = numpy.array([ 0.02198, 0.02201, 0.02695, 0.02645, 0.03024, 0.3927, 7.305, 17.43, 13.43, 8.346]) diff = testy - y res = numpy.dot(diff, diff) self.assertAlmostEqual(0, res) testdy = numpy.array([ 0.002704, 0.001643, 0.002452, 0.001769, 0.001531, 0.1697, 1.006, 0.5351, 0.3677, 0.191]) diff = testdy - dy res = numpy.dot(diff, diff) self.assertAlmostEqual(0, res) testdx = numpy.array([0.0004091, 0.005587, 0.005598, 0.005624, 0.005707, 0.005975, 0.006264, 0.006344, 0.006424, 0.006516]) diff = testdx - dx 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(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
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