diff --git a/jarvis/__init__.py b/jarvis/__init__.py index 9b62ab0b..c93e8609 100644 --- a/jarvis/__init__.py +++ b/jarvis/__init__.py @@ -1,6 +1,6 @@ """Version number.""" -__version__ = "2024.4.30" +__version__ = "2024.5.10" import os diff --git a/jarvis/core/atoms.py b/jarvis/core/atoms.py index 53633158..7c6ca144 100644 --- a/jarvis/core/atoms.py +++ b/jarvis/core/atoms.py @@ -23,6 +23,7 @@ from sklearn.metrics import mean_absolute_error import zipfile import json +from math import cos, pi, sin amu_gm = 1.66054e-24 ang_cm = 1e-8 @@ -867,6 +868,128 @@ def get_neighbors_cutoffs(self, max_cut=10, r=5, bond_tol=0.15): pass return rcut1, rcut2, neighbors + def rotate_pos(self, phi=0.0, theta=90.0, psi=0.0, center=(0, 0, 0)): + """Rotate atom sites via Euler angles (in degrees). + + See e.g http://mathworld.wolfram.com/EulerAngles.html for explanation. + Adapted from + https://wiki.fysik.dtu.dk/ase/_modules/ase/atoms.html#Atoms.rotate + center : + The point to rotate about. A sequence of length 3 with the + coordinates. + phi : + The 1st rotation angle around the z axis. + theta : + Rotation around the x axis. + psi : + 2nd rotation around the z axis. + + """ + phi *= pi / 180 + theta *= pi / 180 + psi *= pi / 180 + + rcoords = self.cart_coords - center + D = np.array( + ( + (cos(phi), sin(phi), 0.0), + (-sin(phi), cos(phi), 0.0), + (0.0, 0.0, 1.0), + ) + ) + # Second Euler rotation about x: + C = np.array( + ( + (1.0, 0.0, 0.0), + (0.0, cos(theta), sin(theta)), + (0.0, -sin(theta), cos(theta)), + ) + ) + # Third Euler rotation, 2nd rotation about z: + B = np.array( + ( + (cos(psi), sin(psi), 0.0), + (-sin(psi), cos(psi), 0.0), + (0.0, 0.0, 1.0), + ) + ) + # Total Euler rotation + A = np.dot(B, np.dot(C, D)) + # Do the rotation + rcoords = np.dot(A, np.transpose(rcoords)) + positions = np.transpose(rcoords) + center + + return Atoms( + lattice_mat=self.lattice_mat, + elements=self.elements, + coords=positions, + cartesian=True, + props=self.props, + ) + + def rotate_cell(self, phi=0.0, theta=90.0, psi=0.0, center=(0, 0, 0)): + """Rotate atom cell via Euler angles (in degrees). + + See e.g http://mathworld.wolfram.com/EulerAngles.html for explanation. + Adapted from + https://wiki.fysik.dtu.dk/ase/_modules/ase/atoms.html#Atoms.rotate + center : + The point to rotate about. A sequence of length 3 with the + coordinates. + phi : + The 1st rotation angle around the z axis. + theta : + Rotation around the x axis. + psi : + 2nd rotation around the z axis. + + """ + phi *= pi / 180 + theta *= pi / 180 + psi *= pi / 180 + + # First move the molecule to the origin In contrast to MATLAB, + # numpy broadcasts the smaller array to the larger row-wise, + # so there is no need to play with the Kronecker product. + # rcoords = atoms.cart_coords - center + # First Euler rotation about z in matrix form + D = np.array( + ( + (cos(phi), sin(phi), 0.0), + (-sin(phi), cos(phi), 0.0), + (0.0, 0.0, 1.0), + ) + ) + # Second Euler rotation about x: + C = np.array( + ( + (1.0, 0.0, 0.0), + (0.0, cos(theta), sin(theta)), + (0.0, -sin(theta), cos(theta)), + ) + ) + # Third Euler rotation, 2nd rotation about z: + B = np.array( + ( + (cos(psi), sin(psi), 0.0), + (-sin(psi), cos(psi), 0.0), + (0.0, 0.0, 1.0), + ) + ) + # Total Euler rotation + A = np.dot(B, np.dot(C, D)) + # Do the rotation + r_lattice_mat = np.dot(A, self.lattice_mat) + # Move back to the roactation point + # positions = np.transpose(rcoords) + center + return Atoms( + lattice_mat=r_lattice_mat, + elements=self.elements, + coords=self.frac_coords, + cartesian=False, + props=self.props, + ) + def atomwise_angle_and_radial_distribution( self, r=5, bond_tol=0.15, c_size=10, verbose=False ): @@ -1335,6 +1458,7 @@ def hook(model, input, output): def get_mineral_prototype_name( self, prim=True, include_c_over_a=False, digits=3 ): + """Get mineral_prototype_name.""" from jarvis.analysis.structure.spacegroup import Spacegroup3D spg = Spacegroup3D(self) @@ -1524,9 +1648,9 @@ def describe( list(set(spg._dataset["wyckoffs"])) ) struct_info["natoms_primitive"] = spg.primitive_atoms.num_atoms - struct_info[ - "natoms_conventional" - ] = spg.conventional_standard_structure.num_atoms + struct_info["natoms_conventional"] = ( + spg.conventional_standard_structure.num_atoms + ) info["chemical_info"] = chem_info info["structure_info"] = struct_info line = "The number of atoms are: " + str( @@ -2276,18 +2400,18 @@ def to_optimade( info_at["cartesian_site_positions"] = atoms.cart_coords[order].tolist() info_at["nperiodic_dimensions"] = 3 # info_at["species"] = atoms.elements - info_at[ - "species" - ] = self.get_optimade_species() # dict(atoms.composition.to_dict()) + info_at["species"] = ( + self.get_optimade_species() + ) # dict(atoms.composition.to_dict()) info_at["elements_ratios"] = list( atoms.composition.atomic_fraction.values() ) info_at["structure_features"] = [] info_at["last_modified"] = str(now) # info_at["more_data_available"] = True - info_at[ - "chemical_formula_descriptive" - ] = atoms.composition.reduced_formula + info_at["chemical_formula_descriptive"] = ( + atoms.composition.reduced_formula + ) info_at["dimension_types"] = [1, 1, 1] info["attributes"] = info_at return info diff --git a/jarvis/core/composition.py b/jarvis/core/composition.py index 223adb11..3c91ec93 100644 --- a/jarvis/core/composition.py +++ b/jarvis/core/composition.py @@ -156,10 +156,14 @@ def formula(self): form = "" for specie, count in self._content.items(): if float(count).is_integer(): - form = form + str(specie) + str(int(count)) + # form = form + str(specie) + str(int(count)) + if count == 1: + form = form + specie + else: + form = form + specie + str(int(count)) else: form = form + str(specie) + str(count) - return form.replace("1", "") + return form # .replace("1", "") @property def atomic_fraction(self): diff --git a/jarvis/core/element_names.json b/jarvis/core/element_names.json new file mode 100644 index 00000000..07c12a1b --- /dev/null +++ b/jarvis/core/element_names.json @@ -0,0 +1,120 @@ +{ + "H": "Hydrogen", + "He": "Helium", + "Li": "Lithium", + "Be": "Beryllium", + "B": "Boron", + "C": "Carbon", + "N": "Nitrogen", + "O": "Oxygen", + "F": "Fluorine", + "Ne": "Neon", + "Na": "Sodium", + "Mg": "Magnesium", + "Al": "Aluminum", + "Si": "Silicon", + "P": "Phosphorus", + "S": "Sulfur", + "Cl": "Chlorine", + "Ar": "Argon", + "K": "Potassium", + "Ca": "Calcium", + "Sc": "Scandium", + "Ti": "Titanium", + "V": "Vanadium", + "Cr": "Chromium", + "Mn": "Manganese", + "Fe": "Iron", + "Co": "Cobalt", + "Ni": "Nickel", + "Cu": "Copper", + "Zn": "Zinc", + "Ga": "Gallium", + "Ge": "Germanium", + "As": "Arsenic", + "Se": "Selenium", + "Br": "Bromine", + "Kr": "Krypton", + "Rb": "Rubidium", + "Sr": "Strontium", + "Y": "Yttrium", + "Zr": "Zirconium", + "Nb": "Niobium", + "Mo": "Molybdenum", + "Tc": "Technetium", + "Ru": "Ruthenium", + "Rh": "Rhodium", + "Pd": "Palladium", + "Ag": "Silver", + "Cd": "Cadmium", + "In": "Indium", + "Sn": "Tin", + "Sb": "Antimony", + "Te": "Tellurium", + "I": "Iodine", + "Xe": "Xenon", + "Cs": "Cesium", + "Ba": "Barium", + "La": "Lanthanum", + "Ce": "Cerium", + "Pr": "Praseodymium", + "Nd": "Neodymium", + "Pm": "Promethium", + "Sm": "Samarium", + "Eu": "Europium", + "Gd": "Gadolinium", + "Tb": "Terbium", + "Dy": "Dysprosium", + "Ho": "Holmium", + "Er": "Erbium", + "Tm": "Thulium", + "Yb": "Ytterbium", + "Lu": "Lutetium", + "Hf": "Hafnium", + "Ta": "Tantalum", + "W": "Tungsten", + "Re": "Rhenium", + "Os": "Osmium", + "Ir": "Iridium", + "Pt": "Platinum", + "Au": "Gold", + "Hg": "Mercury", + "Tl": "Thallium", + "Pb": "Lead", + "Bi": "Bismuth", + "Po": "Polonium", + "At": "Astatine", + "Rn": "Radon", + "Fr": "Francium", + "Ra": "Radium", + "Ac": "Actinium", + "Th": "Thorium", + "Pa": "Protactinium", + "U": "Uranium", + "Np": "Neptunium", + "Pu": "Plutonium", + "Am": "Americium", + "Cm": "Curium", + "Bk": "Berkelium", + "Cf": "Californium", + "Es": "Einsteinium", + "Fm": "Fermium", + "Md": "Mendelevium", + "No": "Nobelium", + "Lr": "Lawrencium", + "Rf": "Rutherfordium", + "Db": "Dubnium", + "Sg": "Seaborgium", + "Bh": "Bohrium", + "Hs": "Hassium", + "Mt": "Meitnerium", + "Ds": "Darmstadtium", + "Rg": "Roentgenium", + "Cn": "Copernicium", + "Nh": "Nihonium", + "Fl": "Flerovium", + "Mc": "Moscovium", + "Lv": "Livermorium", + "Ts": "Tennessine", + "Og": "Oganesson" +} diff --git a/jarvis/core/specie.py b/jarvis/core/specie.py index d3d898c5..f2a767e8 100644 --- a/jarvis/core/specie.py +++ b/jarvis/core/specie.py @@ -28,6 +28,14 @@ el_chrg_json.close() cgcnn_feature_json = os.path.join(os.path.dirname(__file__), "atom_init.json") +element_full_name = os.path.join( + os.path.dirname(__file__), "element_names.json" +) + + +def get_element_full_names(): + return loadjson(element_full_name) + def get_descrp_arr_name(elm="Al"): """ diff --git a/jarvis/db/figshare.py b/jarvis/db/figshare.py index 4e414b28..283bcd4c 100644 --- a/jarvis/db/figshare.py +++ b/jarvis/db/figshare.py @@ -421,6 +421,27 @@ def get_db_info(): "Obtaining m3gnet_mpf dataset 168917...", "https://github.com/materialsvirtuallab/m3gnet", ], + # https://doi.org/10.6084/m9.figshare.23267852 + "m3gnet_mpf_1.5mil": [ + "https://figshare.com/ndownloader/files/47281519", + "id_prop.json", + "Obtaining m3gnet_mpf dataset 1.5mil...", + "https://github.com/materialsvirtuallab/m3gnet", + ], + # https://doi.org/10.6084/m9.figshare.23531523 + "mxene275": [ + "https://figshare.com/ndownloader/files/41266233", + "mxene275.json", + "Obtaining mxene dataset 275...", + "https://cmr.fysik.dtu.dk/c2db/c2db.html", + ], + # https://doi.org/10.6084/m9.figshare.26117998 + "cccbdb": [ + "https://figshare.com/ndownloader/files/47283808", + "cccbdb.json", + "Obtaining CCCBDB dataset 1333...", + "https://cccbdb.nist.gov/", + ], # https://doi.org/10.6084/m9.figshare.13154159 "raw_files": [ "https://ndownloader.figshare.com/files/25295732", diff --git a/jarvis/tests/testfiles/core/test_atoms.py b/jarvis/tests/testfiles/core/test_atoms.py index d044e1c3..43f20781 100644 --- a/jarvis/tests/testfiles/core/test_atoms.py +++ b/jarvis/tests/testfiles/core/test_atoms.py @@ -132,6 +132,8 @@ def test_basic_atoms(): rem = (Si.make_supercell([2, 2, 2]).remove_site_by_index(site=0)).num_atoms prim = Si.get_primitive_atoms print(prim.cart_coords) + #print(prim.get_pos()) + #print(prim.get_cell()) conv = Si.get_conventional_atoms spgn = Si.get_spacegroup comp = compare_atoms(atoms1=prim, atoms2=conv) diff --git a/setup.py b/setup.py index 984a9304..db1c57df 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="jarvis-tools", - version="2024.4.30", + version="2024.5.10", long_description=long_d, install_requires=[ "numpy>=1.20.1", @@ -24,6 +24,8 @@ "toolz>=0.9.0", "xmltodict>=0.11.0", "tqdm>=4.41.1", + "scikit-learn", + "inflect", # "mkdocs-material>=9.0.5", # "markdown>=3.2.1", # "absl-py==1.4.0", @@ -34,6 +36,7 @@ "magpie.json", "element_charge.json", "atom_init.json", + "element_names.json", "mineral_name_prototype.json.zip", ], "jarvis.tasks.lammps.templates": [ @@ -59,7 +62,6 @@ "dgl", "keras", "tensorflow", - "scikit-learn", "flask", "pandas", ],