def make_generator( config: GenConfig) -> Union[PDFGenerator, DebyePDFGenerator]: """ Build a generator according to the information in the GenConfig. Parameters ---------- config : GenConfig A configuration instance for generator building. Returns ------- generator: PDFGenerator or DebyePDFGenerator A generator built from GenConfig. """ name = config.name stru: Structure = loadStructure(config.stru_file) ncpu = config.ncpu if config.debye: generator = DebyePDFGenerator(name) else: generator = PDFGenerator(name) generator.setStructure(stru, periodic=config.periodic) if ncpu: pool = multiprocessing.Pool(ncpu) generator.parallel(ncpu, mapfunc=pool.imap_unordered) else: pass return generator
def make_generator(genconfig: GenConfig) -> Union[PDFGenerator, DebyePDFGenerator]: """ Build a generator according to the information in the GenConfig. Parameters ---------- genconfig : GenConfig A configuration instance for generator building. Returns ------- generator: PDFGenerator or DebyePDFGenerator A generator built from GenConfig. """ generator = DebyePDFGenerator(genconfig.name) if genconfig.debye else PDFGenerator(genconfig.name) generator.setStructure(genconfig.structure, periodic=genconfig.structure) ncpu = genconfig.ncpu if ncpu: pool = multiprocessing.Pool(ncpu) generator.parallel(ncpu, mapfunc=pool.imap_unordered) return generator
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
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
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