def test_ConstrainAsSpaceGroup_args(self): """Test the arguments processing of constrainAsSpaceGroup function. """ from diffpy.srfit.structure.sgconstraints import constrainAsSpaceGroup from diffpy.Structure.SpaceGroups import GetSpaceGroup stru = makeLaMnO3_P1() parset = DiffpyStructureParSet("LaMnO3", stru) sgpars = constrainAsSpaceGroup(parset, "P b n m") sg = GetSpaceGroup('P b n m') parset2 = DiffpyStructureParSet("LMO", makeLaMnO3_P1()) sgpars2 = constrainAsSpaceGroup(parset2, sg) list(sgpars) list(sgpars2) self.assertEqual(sgpars.names, sgpars2.names) return
def test_ConstrainAsSpaceGroup_args(self): """Test the arguments processing of constrainAsSpaceGroup function. """ from diffpy.srfit.structure.sgconstraints import constrainAsSpaceGroup from diffpy.Structure.SpaceGroups import GetSpaceGroup stru = makeLaMnO3_P1() parset = DiffpyStructureParSet("LaMnO3", stru) sgpars = constrainAsSpaceGroup(parset, "P b n m") sg = GetSpaceGroup('P b n m') parset2 = DiffpyStructureParSet("LMO", makeLaMnO3_P1()) sgpars2 = constrainAsSpaceGroup(parset2, sg) list(sgpars) list(sgpars2) self.assertEquals(sgpars.names, sgpars2.names) return
def test_DiffPy_constrainAsSpaceGroup(self): """Test the constrainAsSpaceGroup function.""" from diffpy.srfit.structure.diffpyparset import DiffpyStructureParSet from diffpy.srfit.structure.sgconstraints import constrainAsSpaceGroup stru = makeLaMnO3_P1() parset = DiffpyStructureParSet("LaMnO3", stru) sgpars = constrainAsSpaceGroup(parset, "P b n m", scatterers = parset.getScatterers()[::2], constrainadps = True) # Make sure that the new parameters were created for par in sgpars: self.assertNotEqual(None, par) self.assertNotEqual(None, par.getValue() ) # Test the unconstrained atoms for scatterer in parset.getScatterers()[1::2]: self.assertFalse(scatterer.x.const) self.assertFalse(scatterer.y.const) self.assertFalse(scatterer.z.const) self.assertFalse(scatterer.U11.const) self.assertFalse(scatterer.U22.const) self.assertFalse(scatterer.U33.const) self.assertFalse(scatterer.U12.const) self.assertFalse(scatterer.U13.const) self.assertFalse(scatterer.U23.const) self.assertEqual(0, len(scatterer._constraints)) proxied = [p.par for p in sgpars] def _consttest(par): return par.const def _constrainedtest(par): return par.constrained def _proxytest(par): return par in proxied def _alltests(par): return _consttest(par) or _constrainedtest(par) or _proxytest(par) for idx, scatterer in enumerate(parset.getScatterers()[::2]): # Under this scheme, atom 6 is free to vary test = False for par in [scatterer.x, scatterer.y, scatterer.z]: test |= _alltests(par) self.assertTrue(test) test = False for par in [scatterer.U11, scatterer.U22, scatterer.U33, scatterer.U12, scatterer.U13, scatterer.U23]: test |= _alltests(par) self.assertTrue(test) return
def testConstrainAsSpaceGroup(self): """Test the constrainAsSpaceGroup function.""" from diffpy.srfit.structure.sgconstraints import constrainAsSpaceGroup stru = makeLaMnO3_P1() parset = DiffpyStructureParSet("LaMnO3", stru) sgpars = constrainAsSpaceGroup(parset, "P b n m", scatterers = parset.getScatterers()[::2], constrainadps = True) # Make sure that the new parameters were created for par in sgpars: self.assertNotEquals(None, par) self.assertNotEquals(None, par.getValue() ) # Test the unconstrained atoms for scatterer in parset.getScatterers()[1::2]: self.assertFalse(scatterer.x.const) self.assertFalse(scatterer.y.const) self.assertFalse(scatterer.z.const) self.assertFalse(scatterer.U11.const) self.assertFalse(scatterer.U22.const) self.assertFalse(scatterer.U33.const) self.assertFalse(scatterer.U12.const) self.assertFalse(scatterer.U13.const) self.assertFalse(scatterer.U23.const) self.assertEquals(0, len(scatterer._constraints)) proxied = [p.par for p in sgpars] def _consttest(par): return par.const def _constrainedtest(par): return par.constrained def _proxytest(par): return par in proxied def _alltests(par): return _consttest(par) or _constrainedtest(par) or _proxytest(par) for idx, scatterer in enumerate(parset.getScatterers()[::2]): # Under this scheme, atom 6 is free to vary test = False for par in [scatterer.x, scatterer.y, scatterer.z]: test |= _alltests(par) self.assertTrue(test) test = False for par in [scatterer.U11, scatterer.U22, scatterer.U33, scatterer.U12, scatterer.U13, scatterer.U23]: test |= _alltests(par) self.assertTrue(test) return
def constrainAsSpaceGroup(self, generator, spacegroup, lat=True, xyz=False, adp=False, addphasename=False): ''' constrain phase using space group param generator: generator.phase in recipe to constrain param spacegroup: space group in number or string "87" or "F m 3 m" param lat: bool, constrain lattice parameters param xyz: bool, constrain xyz of atoms param adp: bool, constrain adp of atoms param addphasename: bool, if add phase name to name of variable ''' from diffpy.srfit.structure.sgconstraints import constrainAsSpaceGroup, _constrainAsSpaceGroup from diffpy.Structure.spacegroupmod import SpaceGroup generator = self.returnGenerator(generator) recipe = self.recipe phase = generator.phase phasename = generator.name if isinstance(phase, DiffpyStructureParSet): if isinstance(spacegroup, SpaceGroup): sgpars = _constrainAsSpaceGroup(phase, spacegroup) else: sgpars = constrainAsSpaceGroup(phase, spacegroup) elif isinstance(phase, ObjCrystCrystalParSet): sgpars = phase.sgpars if lat: for par in sgpars.latpars: parname = par.name parname = phasename + '_' + \ parname if addphasename else parname self.addVar(par, parname, par.value, tags=['lat']) if xyz: for par in sgpars.xyzpars: element = getElement(par.par.obj) parname = '_'.join([element, par.name]) parname = phasename + '_' + \ parname if addphasename else parname self.addVar( par, parname, par.value, tags=['xyz', element + '_xyz']) if adp: for par in sgpars.adppars: element = getElement(par.par.obj) parname = '_'.join([element, par.name]) parname = phasename + '_' + \ parname if addphasename else parname self.addVar( par, parname, par.value, tags=['adp', element + '_adp'])
def get_sgpars(parset: Union[ObjCrystCrystalParSet, DiffpyStructureParSet], sg: Union[int, str] = None): """Constrain the structure by space group and get the independent parameters.""" if isinstance(parset, ObjCrystCrystalParSet): if sg is not None: print( "ObjCrystCrystalParSet does not accept explicit space group constrain. " "Implicit space group is used.") sgpars = parset.sgpars elif isinstance(parset, DiffpyStructureParSet): if sg is None: sg = 'P1' print("No explicit space group for DiffpyStructureParSet. " "Use 'P1' symmetry.") sgpars = constrainAsSpaceGroup(parset, sg, constrainadps=False) else: raise ValueError("{} does not allow space group constrain.".format( type(parset))) return sgpars
def sgconstrain(recipe: MyRecipe, gen_name: str, con_name: str = None, sg: Union[int, str] = None, dv: Dict[str, float] = None, scatterers: List = None, constrainxyz=False) -> None: """ Constrain the generator by space group. The constrained parameters are scale, delta2, lattice parameters, ADPs and xyz coordinates. The lattice constants and xyz coordinates are constrained by space group while the ADPs are constrained by elements. All paramters will be added as '{par.name}_{gen.name}' The default values, ranges and tags for parameters: scale: 0, (0, inf), scale_{gen.name} delta2: 0, (0, 5), delta2_{gen.name} lat: par.value, (par.value +/- 10%), lat_{gen.name} adp: 0.006, (0.001, 0.02), adp_{gen.name} xyz: par.value, (par.value +/- 0.1), xyz_{gen.name} Parameters ---------- recipe The recipe to add variables. gen_name The name of the PDFGenerator to constrain. con_name The name of the FitContribution where the PDFGenerator is in. If None, get it according to the name of the first ConConfig in 'recipe.configs'. Default None. sg The space group. The expression can be the string or integer. If None, use the space group in GenConfig. Default None. dv The default value of the constrained parameters. If None, the default values will be used. Default None. scatterers The argument scatters of the constrainAsSpaceGroup. If None, None will be used. Default None. constrainxyz Whether to constrain xyz coordinates. Returns ------- None """ def get_config(): if con_name is None: return recipe.configs[0] for config in recipe.configs: if config.name == con_name: return config else: raise ValueError( f"No ConConfig in recipe '{recipe.name}' match the '{con_name}'." ) def get_sg(): config = get_config() for genconfig in config.phases: if genconfig.name == gen_name: return genconfig.sg else: raise ValueError( f"No GenConfig in the FitContribution '{config.name}' match the '{gen_name}'." ) # get sg if sg is None: sg = get_sg() # set default of variables dv = dv if dv else {} con = getattr(recipe, con_name) if con_name else getattr( recipe, recipe.configs[0].name) gen = getattr(con, gen_name) # add scale name = f'scale_{gen.name}' recipe.addVar(gen.scale, name=name, value=dv.get(name, 0.)).boundRange(0., np.inf) # add delta2 name = f'delta2_{gen.name}' recipe.addVar(gen.delta2, name=name, value=dv.get(name, 0.)).boundRange(0., 5.) # constrain by spacegroup sgpars = constrainAsSpaceGroup(gen.phase, sg, constrainadps=False, scatterers=scatterers) print( f"Constrain '{gen.name}' by space group '{sg}' without constraining ADPs." ) # add latpars for par in sgpars.latpars: name = f'{par.name}_{gen.name}' tag = f'lat_{gen.name}' recipe.addVar(par, name=name, value=dv.get(name, par.value), tag=tag).boundWindow(par.value * 0.1) # constrain adps atoms = gen.phase.getScatterers() elements = Counter([atom.element for atom in atoms]).keys() adp = { element: recipe.newVar(f'Uiso_{element}_{gen.name}', value=dv.get(f'Uiso_{element}_{gen.name}', 0.006), tag=f'adp_{gen.name}').boundRange(0.001, 0.02) for element in elements } for atom in atoms: recipe.constrain(atom.Uiso, adp[atom.element]) # add xyzpars if constrainxyz: for par in sgpars.xyzpars: name = f'{par.name}_{gen.name}' tag = f'xyz_{gen.name}' recipe.addVar(par, name=name, value=dv.get(name, par.value), tag=tag).boundWindow(0.1) return
def sgconstrain(recipe: MyRecipe, gen: Union[PDFGenerator, DebyePDFGenerator], sg: Union[int, str], dv: Dict[str, float] = None, scatterers: List = None) -> None: """ Constrain the generator by space group. The constrained parameters are scale, delta2, lattice parameters, ADPs and xyz coordinates. The lattice constants and xyz coordinates are constrained by space group while the ADPs are constrained by elements. All paramters will be added as '{par.name}_{gen.name}' The default values, ranges and tags for parameters: scale: 0, (0, inf), scale_{gen.name} delta2: 0, (0, inf), delta2_{gen.name} lat: par.value, (par.value +/- 20%), lat_{gen.name} adp: 0.006, (0, inf), adp_{gen.name} xyz: par.value, (par.value +/- 0.2), xyz_{gen.name} Parameters ---------- recipe The recipe to add variables. gen The generator to constrain. sg The space group. The expression can be the string or integer. dv The default value of the constrained parameters. scatterers The argument scatters of the constrainAsSpaceGroup. Returns ------- None """ dv = dv if dv else {} # add scale name = f'scale_{gen.name}' recipe.addVar(gen.scale, name=name, value=dv.get(name, 0.)).boundRange(0., np.inf) # add delta2 name = f'delta2_{gen.name}' recipe.addVar(gen.delta2, name=name, value=dv.get(name, 0.)).boundRange(0., np.inf) # constrain lat sgpars = constrainAsSpaceGroup(gen.phase, sg, constrainadps=False, scatterers=scatterers) for par in sgpars.latpars: name = f'{par.name}_{gen.name}' tag = f'lat_{gen.name}' recipe.addVar(par, name=name, value=dv.get(name, par.value), tag=tag).boundWindow(par.value * 0.2) # constrain adp atoms = gen.phase.getScatterers() elements = Counter([atom.element for atom in atoms]).keys() adp = { element: recipe.newVar(f'Uiso_{element}_{gen.name}', value=dv.get(f'Uiso_{element}_{gen.name}', 0.006), tag=f'adp_{gen.name}').boundRange(0., np.inf) for element in elements } for atom in atoms: recipe.constrain(atom.Uiso, adp[atom.element]) # constrain xyz for par in sgpars.xyzpars: name = f'{par.name}_{gen.name}' tag = f'xyz_{gen.name}' recipe.addVar(par, name=name, value=dv.get(name, par.value), tag=tag).boundWindow(0.2) return