def test_rdf_and_peaks(self): ## Test diamond rdf, bin_radius = RadialDistributionFunction().featurize(self.diamond) # Make sure it the last bin is cutoff-bin_max self.assertAlmostEquals(bin_radius.max(), 19.9) # Verify bin sizes self.assertEquals(len(rdf), len(bin_radius)) self.assertEquals(len(rdf), 200) # Make sure it gets all of the peaks self.assertEquals(np.count_nonzero(rdf), 116) # Check the values for a few individual peaks self.assertAlmostEqual(rdf[int(round(1.5 / 0.1))], 15.12755155) self.assertAlmostEqual(rdf[int(round(2.9 / 0.1))], 12.53193948) self.assertAlmostEqual(rdf[int(round(19.9 / 0.1))], 0.822126129) # Make sure it finds the locations of non-zero peaks correctly peaks = RadialDistributionFunctionPeaks().featurize(rdf, bin_radius) self.assertEquals(len(peaks), 2) self.assertAlmostEquals(2.5, peaks[0]) self.assertAlmostEquals(1.5, peaks[1]) # Repeat test with NaCl (omitting comments). Altering cutoff distance rdf, bin_radius = RadialDistributionFunction().featurize(self.nacl, cutoff=10) self.assertAlmostEquals(bin_radius.max(), 9.9) self.assertEquals(len(rdf), len(bin_radius)) self.assertEquals(len(rdf), 100) self.assertEquals(np.count_nonzero(rdf), 11) self.assertAlmostEqual(rdf[int(round(2.8 / 0.1))], 27.09214168) self.assertAlmostEqual(rdf[int(round(4.0 / 0.1))], 26.83338723) self.assertAlmostEqual(rdf[int(round(9.8 / 0.1))], 3.024406467) peaks = RadialDistributionFunctionPeaks().featurize(rdf, bin_radius) self.assertEquals(len(peaks), 2) self.assertAlmostEquals(2.8, peaks[0]) self.assertAlmostEquals(4.0, peaks[1]) # Repeat test with CsCl. Altering cutoff distance and bin_size rdf, bin_radius = RadialDistributionFunction().featurize(self.cscl, cutoff=8, bin_size=0.5) self.assertAlmostEquals(bin_radius.max(), 7.5) self.assertEquals(len(rdf), len(bin_radius)) self.assertEquals(len(rdf), 16) self.assertEquals(np.count_nonzero(rdf), 5) self.assertAlmostEqual(rdf[int(round(3.5 / 0.5))], 6.741265585) self.assertAlmostEqual(rdf[int(round(4.0 / 0.5))], 3.937582548) self.assertAlmostEqual(rdf[int(round(7.0 / 0.5))], 1.805505363) peaks = RadialDistributionFunctionPeaks().featurize(rdf, bin_radius, n_peaks=3) self.assertEquals(len(peaks), 3) self.assertAlmostEquals(3.5, peaks[0]) self.assertAlmostEquals(6.5, peaks[1]) self.assertAlmostEquals(5, 5, peaks[2])
def test_rdf_and_peaks(self): ## Test diamond rdforig = RadialDistributionFunction().featurize( self.diamond) rdf = rdforig[0] # Make sure it the last bin is cutoff-bin_max self.assertAlmostEqual(max(rdf['distances']), 19.9) # Verify bin sizes self.assertEqual(len(rdf['distribution']), 200) # Make sure it gets all of the peaks self.assertEqual(np.count_nonzero(rdf['distribution']), 116) # Check the values for a few individual peaks self.assertAlmostEqual( rdf['distribution'][int(round(1.5 / 0.1))], 15.12755155) self.assertAlmostEqual( rdf['distribution'][int(round(2.9 / 0.1))], 12.53193948) self.assertAlmostEqual( rdf['distribution'][int(round(19.9 / 0.1))], 0.822126129) # Repeat test with NaCl (omitting comments). Altering cutoff distance rdforig = RadialDistributionFunction(cutoff=10).featurize(self.nacl) rdf = rdforig[0] self.assertAlmostEqual(max(rdf['distances']), 9.9) self.assertEqual(len(rdf['distribution']), 100) self.assertEqual(np.count_nonzero(rdf['distribution']), 11) self.assertAlmostEqual( rdf['distribution'][int(round(2.8 / 0.1))], 27.09214168) self.assertAlmostEqual( rdf['distribution'][int(round(4.0 / 0.1))], 26.83338723) self.assertAlmostEqual( rdf['distribution'][int(round(9.8 / 0.1))], 3.024406467) # Repeat test with CsCl. Altering cutoff distance and bin_size rdforig = RadialDistributionFunction( cutoff=8, bin_size=0.5).featurize(self.cscl) rdf = rdforig[0] self.assertAlmostEqual(max(rdf['distances']), 7.5) self.assertEqual(len(rdf['distribution']), 16) self.assertEqual(np.count_nonzero(rdf['distribution']), 5) self.assertAlmostEqual( rdf['distribution'][int(round(3.5 / 0.5))], 6.741265585) self.assertAlmostEqual( rdf['distribution'][int(round(4.0 / 0.5))], 3.937582548) self.assertAlmostEqual( rdf['distribution'][int(round(7.0 / 0.5))], 1.805505363)
def featurize_structure(df: pd.DataFrame) -> pd.DataFrame: """ Decorate input `pandas.DataFrame` of structures with structural features from matminer. Currently applies the set of all matminer structure features. Args: df (pandas.DataFrame): the input dataframe with `"structure"` column containing `pymatgen.Structure` objects. Returns: pandas.DataFrame: the decorated DataFrame. """ logging.info("Applying structure featurizers...") df = df.copy() structure_features = [ DensityFeatures(), GlobalSymmetryFeatures(), RadialDistributionFunction(), CoulombMatrix(), PartialRadialDistributionFunction(), SineCoulombMatrix(), EwaldEnergy(), BondFractions(), StructuralHeterogeneity(), MaximumPackingEfficiency(), ChemicalOrdering(), XRDPowderPattern(), BagofBonds() ] featurizer = MultipleFeaturizer([feature.fit(df["structure"]) for feature in structure_features]) df = featurizer.featurize_dataframe(df, "structure", multiindex=True, ignore_errors=True) df.columns = df.columns.map('|'.join).str.strip('|') dist = df["RadialDistributionFunction|radial distribution function"][0]['distances'][:50] for i, d in enumerate(dist): _rdf_key = "RadialDistributionFunction|radial distribution function|d_{:.2f}".format(d) df[_rdf_key] = df["RadialDistributionFunction|radial distribution function"].apply(lambda x: x['distribution'][i]) df = df.drop("RadialDistributionFunction|radial distribution function", axis=1) _crystal_system = { "cubic": 1, "tetragonal": 2, "orthorombic": 3, "hexagonal": 4, "trigonal": 5, "monoclinic": 6, "triclinic": 7 } df["GlobalSymmetryFeatures|crystal_system"] = df["GlobalSymmetryFeatures|crystal_system"].map(_crystal_system) df["GlobalSymmetryFeatures|is_centrosymmetric"] = df["GlobalSymmetryFeatures|is_centrosymmetric"].map(int) return clean_df(df)
def add_cs_features(df,rdf_flag=False): df["composition"] = str_to_composition(df["pretty_formula"]) df["composition_oxid"] = composition_to_oxidcomposition(df["composition"]) df["structure"] = dict_to_object(df["structure"]) vo = ValenceOrbital() df = vo.featurize_dataframe(df,"composition") ox = OxidationStates() df = ox.featurize_dataframe(df, "composition_oxid") # structure features den = DensityFeatures() df = den.featurize_dataframe(df, "structure") if rdf_flag: rdf = RadialDistributionFunction(cutoff=15.0,bin_size=0.2) df = rdf.featurize_dataframe(df, "structure") return df
class DeBreuck2020Featurizer(modnet.featurizers.MODFeaturizer): """ Featurizer presets used for the paper 'Machine learning materials properties for small datasets' by Pierre-Paul De Breuck, Geoffroy Hautier & Gian-Marco Rignanese, arXiv:2004.14766 (2020). Uses most of the featurizers implemented by matminer at the time of writing with their default hyperparameters and presets. """ from matminer.featurizers.composition import ( AtomicOrbitals, AtomicPackingEfficiency, BandCenter, # CohesiveEnergy, - This descriptor was not used in the paper preset # ElectronAffinity, - This descriptor was not used in the paper preset ElectronegativityDiff, ElementFraction, ElementProperty, IonProperty, Miedema, OxidationStates, Stoichiometry, TMetalFraction, ValenceOrbital, YangSolidSolution, ) from matminer.featurizers.structure import ( # BagofBonds, - This descriptor was not used in the paper preset BondFractions, ChemicalOrdering, CoulombMatrix, DensityFeatures, EwaldEnergy, GlobalSymmetryFeatures, MaximumPackingEfficiency, # PartialRadialDistributionFunction, RadialDistributionFunction, SineCoulombMatrix, StructuralHeterogeneity, XRDPowderPattern, ) from matminer.featurizers.site import ( AGNIFingerprints, AverageBondAngle, AverageBondLength, BondOrientationalParameter, ChemEnvSiteFingerprint, CoordinationNumber, CrystalNNFingerprint, GaussianSymmFunc, GeneralizedRadialDistributionFunction, LocalPropertyDifference, OPSiteFingerprint, VoronoiFingerprint, ) composition_featurizers = ( AtomicOrbitals(), AtomicPackingEfficiency(), BandCenter(), ElementFraction(), ElementProperty.from_preset("magpie"), IonProperty(), Miedema(), Stoichiometry(), TMetalFraction(), ValenceOrbital(), YangSolidSolution(), ) oxide_composition_featurizers = ( ElectronegativityDiff(), OxidationStates(), ) structure_featurizers = ( DensityFeatures(), GlobalSymmetryFeatures(), RadialDistributionFunction(), CoulombMatrix(), # PartialRadialDistributionFunction(), SineCoulombMatrix(), EwaldEnergy(), BondFractions(), StructuralHeterogeneity(), MaximumPackingEfficiency(), ChemicalOrdering(), XRDPowderPattern(), # BagofBonds(), ) site_featurizers = ( AGNIFingerprints(), AverageBondAngle(VoronoiNN()), AverageBondLength(VoronoiNN()), BondOrientationalParameter(), ChemEnvSiteFingerprint.from_preset("simple"), CoordinationNumber(), CrystalNNFingerprint.from_preset("ops"), GaussianSymmFunc(), GeneralizedRadialDistributionFunction.from_preset("gaussian"), LocalPropertyDifference(), OPSiteFingerprint(), VoronoiFingerprint(), ) def featurize_composition(self, df): """ Applies the preset composition featurizers to the input dataframe, renames some fields and cleans the output dataframe. """ df = super().featurize_composition(df) _orbitals = {"s": 1, "p": 2, "d": 3, "f": 4} df['AtomicOrbitals|HOMO_character'] = df[ 'AtomicOrbitals|HOMO_character'].map(_orbitals) df['AtomicOrbitals|LUMO_character'] = df[ 'AtomicOrbitals|LUMO_character'].map(_orbitals) df['AtomicOrbitals|HOMO_element'] = df[ 'AtomicOrbitals|HOMO_element'].apply( lambda x: -1 if not isinstance(x, str) else Element(x).Z) df['AtomicOrbitals|LUMO_element'] = df[ 'AtomicOrbitals|LUMO_element'].apply( lambda x: -1 if not isinstance(x, str) else Element(x).Z) df = df.replace([np.inf, -np.inf, np.nan], 0) return modnet.featurizers.clean_df(df) def featurize_structure(self, df): """ Applies the preset structural featurizers to the input dataframe, renames some fields and cleans the output dataframe. """ df = super().featurize_structure(df) dist = df[ "RadialDistributionFunction|radial distribution function"].iloc[0][ 'distances'][:50] for i, d in enumerate(dist): _rdf_key = "RadialDistributionFunction|radial distribution function|d_{:.2f}".format( d) df[_rdf_key] = df[ "RadialDistributionFunction|radial distribution function"].apply( lambda x: x['distribution'][i]) df = df.drop("RadialDistributionFunction|radial distribution function", axis=1) _crystal_system = { "cubic": 1, "tetragonal": 2, "orthorombic": 3, "hexagonal": 4, "trigonal": 5, "monoclinic": 6, "triclinic": 7 } def _int_map(x): if x == np.nan: return 0 elif x: return 1 else: return 0 df["GlobalSymmetryFeatures|crystal_system"] = df[ "GlobalSymmetryFeatures|crystal_system"].map(_crystal_system) df["GlobalSymmetryFeatures|is_centrosymmetric"] = df[ "GlobalSymmetryFeatures|is_centrosymmetric"].map(_int_map) return modnet.featurizers.clean_df(df) def featurize_site(self, df): """ Applies the preset site featurizers to the input dataframe, renames some fields and cleans the output dataframe. """ # rename some features for backwards compatibility with pretrained models aliases = { "GeneralizedRadialDistributionFunction": "GeneralizedRDF", "AGNIFingerprints": "AGNIFingerPrint", "BondOrientationalParameter": "BondOrientationParameter", "GaussianSymmFunc": "ChemEnvSiteFingerprint|GaussianSymmFunc", } df = super().featurize_site(df, aliases=aliases) df = df.loc[:, (df != 0).any(axis=0)] return modnet.featurizers.clean_df(df)
class FUTURE_PROSPECTS_2021(featurizer.extendedMODFeaturizer): from matminer.featurizers.composition import ( AtomicOrbitals, AtomicPackingEfficiency, BandCenter, CohesiveEnergy, ElectronAffinity, ElectronegativityDiff, ElementFraction, ElementProperty, IonProperty, Miedema, OxidationStates, Stoichiometry, TMetalFraction, ValenceOrbital, YangSolidSolution, ) from matminer.featurizers.structure import ( BagofBonds, BondFractions, ChemicalOrdering, CoulombMatrix, DensityFeatures, EwaldEnergy, GlobalSymmetryFeatures, MaximumPackingEfficiency, PartialRadialDistributionFunction, RadialDistributionFunction, SineCoulombMatrix, StructuralHeterogeneity, XRDPowderPattern, ) from matminer.featurizers.site import ( AGNIFingerprints, AverageBondAngle, AverageBondLength, BondOrientationalParameter, ChemEnvSiteFingerprint, CoordinationNumber, CrystalNNFingerprint, GaussianSymmFunc, GeneralizedRadialDistributionFunction, LocalPropertyDifference, OPSiteFingerprint, VoronoiFingerprint, ) from matminer.featurizers.dos import ( DOSFeaturizer, SiteDOS, Hybridization, DosAsymmetry, ) from matminer.featurizers.bandstructure import ( BandFeaturizer, BranchPointEnergy ) composition_featurizers = ( AtomicOrbitals(), AtomicPackingEfficiency(), BandCenter(), ElementFraction(), ElementProperty.from_preset("magpie"), IonProperty(), Miedema(), Stoichiometry(), TMetalFraction(), ValenceOrbital(), YangSolidSolution(), ) oxid_composition_featurizers = ( ElectronegativityDiff(), OxidationStates(), ) structure_featurizers = ( DensityFeatures(), GlobalSymmetryFeatures(), RadialDistributionFunction(), CoulombMatrix(), #PartialRadialDistributionFunction(), #Introduces a large amount of features SineCoulombMatrix(), EwaldEnergy(), BondFractions(), StructuralHeterogeneity(), MaximumPackingEfficiency(), ChemicalOrdering(), XRDPowderPattern(), ) site_featurizers = ( AGNIFingerprints(), AverageBondAngle(VoronoiNN()), AverageBondLength(VoronoiNN()), BondOrientationalParameter(), ChemEnvSiteFingerprint.from_preset("simple"), CoordinationNumber(), CrystalNNFingerprint.from_preset("ops"), GaussianSymmFunc(), GeneralizedRadialDistributionFunction.from_preset("gaussian"), LocalPropertyDifference(), OPSiteFingerprint(), VoronoiFingerprint(), ) dos_featurizers = ( DOSFeaturizer(), SiteDOS(), Hybridization() ) band_featurizers = ( BandFeaturizer(), BranchPointEnergy() ) def __init__(self, n_jobs=None): self._n_jobs = n_jobs def featurize_composition(self, df): """Applies the preset composition featurizers to the input dataframe, renames some fields and cleans the output dataframe. """ df = super().featurize_composition(df) _orbitals = {"s": 1, "p": 2, "d": 3, "f": 4} df["AtomicOrbitals|HOMO_character"] = df["AtomicOrbitals|HOMO_character"].map( _orbitals ) df["AtomicOrbitals|LUMO_character"] = df["AtomicOrbitals|LUMO_character"].map( _orbitals ) df["AtomicOrbitals|HOMO_element"] = df["AtomicOrbitals|HOMO_element"].apply( lambda x: -1 if not isinstance(x, str) else Element(x).Z ) df["AtomicOrbitals|LUMO_element"] = df["AtomicOrbitals|LUMO_element"].apply( lambda x: -1 if not isinstance(x, str) else Element(x).Z ) return clean_df(df) def featurize_structure(self, df): """Applies the preset structural featurizers to the input dataframe, renames some fields and cleans the output dataframe. """ df = super().featurize_structure(df) dist = df["RadialDistributionFunction|radial distribution function"].iloc[0][ "distances" ][:50] for i, d in enumerate(dist): _rdf_key = "RadialDistributionFunction|radial distribution function|d_{:.2f}".format( d ) df[_rdf_key] = df[ "RadialDistributionFunction|radial distribution function" ].apply(lambda x: x["distribution"][i]) df = df.drop("RadialDistributionFunction|radial distribution function", axis=1) _crystal_system = { "cubic": 1, "tetragonal": 2, "orthorombic": 3, "hexagonal": 4, "trigonal": 5, "monoclinic": 6, "triclinic": 7, } def _int_map(x): if x == np.nan: return 0 elif x: return 1 else: return 0 df["GlobalSymmetryFeatures|crystal_system"] = df[ "GlobalSymmetryFeatures|crystal_system" ].map(_crystal_system) df["GlobalSymmetryFeatures|is_centrosymmetric"] = df[ "GlobalSymmetryFeatures|is_centrosymmetric" ].map(_int_map) return clean_df(df) def featurize_dos(self, df): """Applies the presetdos featurizers to the input dataframe, renames some fields and cleans the output dataframe. """ df = super().featurize_dos(df) hotencodeColumns = ["DOSFeaturizer|vbm_specie_1","DOSFeaturizer|cbm_specie_1"] one_hot = pd.get_dummies(df[hotencodeColumns]) df = df.drop(hotencodeColumns, axis = 1).join(one_hot) _orbitals = {"s": 1, "p": 2, "d": 3, "f": 4} df["DOSFeaturizer|vbm_character_1"] = df[ "DOSFeaturizer|vbm_character_1" ].map(_orbitals) df["DOSFeaturizer|cbm_character_1"] = df[ "DOSFeaturizer|cbm_character_1" ].map(_orbitals) # Splitting one feature into several floating features # e.g. number;number;number into three columns splitColumns = ["DOSFeaturizer|cbm_location_1", "DOSFeaturizer|vbm_location_1"] for column in splitColumns: try: newColumns = df[column].str.split(";", n = 2, expand = True) for i in range(0,3): df[column + "_" + str(i)] = np.array(newColumns[i]).astype(np.float) except: continue df = df.drop(splitColumns, axis=1) df = df.drop(["dos"], axis=1) return clean_df(df) def featurize_bandstructure(self, df): """Applies the preset band structure featurizers to the input dataframe, renames some fields and cleans the output dataframe. """ df = super().featurize_bandstructure(df) def _int_map(x): if str(x) == "False": return 0 elif str(x) == "True": return 1 df["BandFeaturizer|is_gap_direct"] = df[ "BandFeaturizer|is_gap_direct" ].map(_int_map) df = df.drop(["bandstructure"], axis=1) return clean_df(df) def featurize_site(self, df): """Applies the preset site featurizers to the input dataframe, renames some fields and cleans the output dataframe. """ aliases = { "GeneralizedRadialDistributionFunction": "GeneralizedRDF", "AGNIFingerprints": "AGNIFingerPrint", "BondOrientationalParameter": "BondOrientationParameter", "GaussianSymmFunc": "ChemEnvSiteFingerprint|GaussianSymmFunc", } df = super().featurize_site(df, aliases=aliases) df = df.loc[:, (df != 0).any(axis=0)] return clean_df(df)
import numpy as np from matminer.featurizers.structure import RadialDistributionFunction cen_structures = np.load('centrosymmetric_insulators.npy', allow_pickle=True) #create rdf representations rdf = RadialDistributionFunction() #r_cut=2.0,periodic=True,normalize=True) cen_rdf = [] for item in cen_structures: cen_rdf.append(rdf.featurize(item)) np.save('centrosymmetric_rdf_representation.npy', cen_rdf) non_cen_structures = np.load('non_centrosymmetric_insulators.npy', allow_pickle=True) non_cen_rdf = [] for item in non_cen_structures: non_cen_rdf.append(rdf.featurize(item)) np.save('non_centrosymmetric_rdf_representation.npy', non_cen_rdf)
structlist.append([Structure.from_file(directoryname + i) ]) #Converts CIF to pymatgen structure object namelist.append(os.path.splitext(i)[0]) #Collects all the structure names structs.append(Structure.from_file(directoryname + i)) #Creates Pandas dataframe with data being a list of structures and the row name being the structure name dftest = pd.DataFrame(data=structlist, index=namelist, columns=namecolumns) p = PartialRadialDistributionFunction() p.fit(np.asarray(structs)) c = CoulombMatrix() c.fit(np.asarray(structs)) erdf = ElectronicRadialDistributionFunction() erdf.cutoff = 10 #longest diagonal of lattice...I picked a number semi-arbitrarily #Featurizes the structures featurizer = MultipleFeaturizer([ ElementProperty.from_preset('magpie'), OxidationStates(), AtomicOrbitals(), BandCenter(), ElectronegativityDiff(), DensityFeatures(), RadialDistributionFunction(), p, c, erdf ]) r = (featurizer.featurize_many(dftest, ['structure']) ) #Featurizes entire Pandas Dataframe #Yay it runs!