def get_structure_from_url(url): from pymatflow.structure.crystal import crystal from pymatflow.base.atom import Atom result = _get_from_url(url) out = [] for item in result["data"]: a = crystal() a.cell = item["unit_cell"] latcell = np.array(a.cell) convmat_frac_to_cartesian = latcell.T a.atoms = [] for atm in item["sites"]: name = atm.split()[0] cartesian = list( convmat_frac_to_cartesian.dot( np.array([ float(atm.split()[2]), float(atm.split()[3]), float(atm.split()[4]) ]))) a.atoms.append( Atom(name=name, x=cartesian[0], y=cartesian[1], z=cartesian[2])) out.append(a) return out
def main(): parser = argparse.ArgumentParser() parser.add_argument("-i", "--input", type=str, required=True, help="input structure file") args = parser.parse_args() # if no argument passed to matflow if len(sys.argv) == 1: # display help message when no args provided parser.print_help() sys.exit(1) a = read_structure(filepath=args.input) for i in range(1, 10): supercell = a.build_supercell([i, i, i]) new_structure = crystal() new_structure.get_cell_atoms(cell=supercell["cell"], atoms=supercell["atoms"]) # calculate the madelung constant # get center atom all_x = [atoms.x for atom in new_structure.atoms] all_y = [atoms.y for atom in new_structure.atoms] all_z = [atoms.z for atom in new_structure.atoms]
def interpolate(initial, final, nimage, moving_atom): """ :param initial -> instance of pymatflow.structure.crystal.crystal() :param final -> instance of pymatflow.structure.crystal.crystal() :param nimage -> number of intermediate images(not including initial and final image) :param moving_atom -> the index of moving atoms (index starts from 0) :return images -> a list of instance of pymatflow.structure.crystal.crystal() as inter images Feature: only interpolate(linearly) the specified moving atoms. other atoms may have different positions between initial and final image, however we use the coordinate of the initial image as the cooresponding coordinate for the inter image. """ # use fractional coordinates to interpolate the images initial.natom = len(initial.atoms) final.natom = len(final.atoms) initial_frac = initial.get_fractional() final_frac = final.get_fractional() #images = [] images_frac = [] for i in range(nimage): #images.append(copy.deepcopy(initial)) images_frac.append(copy.deepcopy(initial_frac)) for i in moving_atom: dx = final_frac[i][1] - initial_frac[i][1] dy = final_frac[i][2] - initial_frac[i][2] dz = final_frac[i][3] - initial_frac[i][3] for j in range(nimage): x = initial_frac[i][1] + j * dx / (nimage + 1) y = initial_frac[i][2] + j * dy / (nimage + 1) z = initial_frac[i][3] + j * dz / (nimage + 1) #print("fractional x, y, z: %f %f %f\n" % (x, y, z)) images_frac[j][i][1] = x images_frac[j][i][2] = y images_frac[j][i][3] = z # transform from images_frac to images # convert frac to cartesian again images = [] latcell = np.array(initial.cell) convmat = latcell.T from pymatflow.base.atom import Atom from pymatflow.structure.crystal import crystal for i in range(nimage): img = crystal() img.atoms = [] img.cell = initial.cell for atom in images_frac[i]: cartesian = list(convmat.dot(np.array([atom[1], atom[2], atom[3]]))) img.atoms.append( Atom(name=atom[0], x=cartesian[0], y=cartesian[1], z=cartesian[2])) images.append(img) # return images
def get_final_structure_from_aurl(aurl): """ Note: get final structure(relaxed using vasp) from aurl, aurl is in format like this: aflowlib.duke.edu:AFLOWDATA/LIB3_RAW/Bi_dRh_pvTi_sv/T0003.ABC:LDAU2 aflowlib.duke.edu:AFLOWDATA/ICSD_WEB/CUB/Cl1Na1_ICSD_622368 """ out = crystal() geometry = urlopen("http://" + aurl.replace(":AFLOWDATA", "/AFLOWDATA") + "/?geometry").read().decode("utf-8") a, b, c, alpha, beta, gamma = [ float(item) for item in geometry.replace("\n", "").split(",") ] alpha = alpha / 180 * np.pi beta = beta / 180 * np.pi gamma = gamma / 180 * np.pi out.cell = [] out.cell.append([a, 0, 0]) out.cell.append([np.cos(gamma) * b, np.sin(gamma) * b, 0]) new_c1 = np.cos(beta) new_c2 = (np.cos(alpha - np.cos(beta) * np.cos(gamma))) / np.sin(gamma) new_c3_square = 1.0 - new_c1 * new_c1 - new_c2 * new_c2 new_c3 = np.sqrt(new_c3_square) out.cell.append([new_c1 * c, new_c2 * c, new_c3 * c]) elements_list = [] composition = urlopen("http://" + aurl.replace(":AFLOWDATA", "/AFLOWDATA") + "/?composition").read().decode("utf-8") species = urlopen("http://" + aurl.replace(":AFLOWDATA", "/AFLOWDATA") + "/?species").read().decode("utf-8") for i, number in enumerate(composition.replace("\n", "").split(",")): for j in range(int(number)): elements_list.append(species.replace("\n", "").split(",")[i]) # convmat_frac_to_cartesian = np.array(out.cell).T out.atoms = [] positions_fractional = urlopen( "http://" + aurl.replace(":AFLOWDATA", "/AFLOWDATA") + "/?positions_fractional").read().decode("utf-8") for i, item in enumerate( positions_fractional.replace("\n", "").split(";")): cartesian = convmat_frac_to_cartesian.dot( [float(k) for k in item.split(",")]) out.atoms.append( Atom(name=elements_list[i], x=cartesian[0], y=cartesian[1], z=cartesian[2])) # return out
def set_frac_min_to_zero(structure): """ :return an object of crystal() Note: set the fractional coordinate minimum to zero, this is a way of standardize the cif file """ from pymatflow.structure.crystal import crystal from pymatflow.base.atom import Atom # now calc the fractional coordinates atoms_frac = [] latcell = np.array(structure.cell) convmat = np.linalg.inv(latcell.T) for i in range(len(structure.atoms)): atom = [] atom.append(structure.atoms[i].name) atom = atom + list( convmat.dot( np.array([ structure.atoms[i].x, structure.atoms[i].y, structure.atoms[i].z ]))) atoms_frac.append(atom) # set the minimum of fractional coord to to 0 min_frac_x = min(atoms_frac[:][1]) min_frac_y = min(atoms_frac[:][2]) min_frac_z = min(atoms_frac[:][3]) for i in range(len(atoms_frac)): atoms_frac[i][1] -= min_frac_x atoms_frac[i][2] -= min_frac_y atoms_frac[i][3] -= min_frac_z # now convert coord of atom in atoms_frac_within_new_cell to cartesian out = crystal() out.atoms = [] out.cell = structure.cell latcell = np.array(out.cell) convmat_frac_to_cartesian = latcell.T for atom in atoms_frac: cartesian = list( convmat_frac_to_cartesian.dot(np.array([atom[1], atom[2], atom[3]]))) out.atoms.append( Atom(name=atom[0], x=cartesian[0], y=cartesian[1], z=cartesian[2])) # return out
def set_frac_within_zero_and_one(structure): """ :return an object of crystal() Note: set the fractional coordinate within the range of 0 and 1, this is a way of standardize the cif file """ from pymatflow.structure.crystal import crystal from pymatflow.base.atom import Atom # now calc the fractional coordinates atoms_frac = [] latcell = np.array(structure.cell) convmat = np.linalg.inv(latcell.T) for i in range(len(structure.atoms)): atom = [] atom.append(structure.atoms[i].name) atom = atom + list( convmat.dot( np.array([ structure.atoms[i].x, structure.atoms[i].y, structure.atoms[i].z ]))) atoms_frac.append(atom) # set the fractional coordinates within 0 and 1 for i in range(len(atoms_frac)): for j in range(1, 4): while atoms_frac[i][j] >= 1: atoms_frac[i][j] -= 1 while atoms_frac[i][j] < 0: atoms_frac[i][j] += 1 # now convert coord of atom in atoms_frac_within_new_cell to cartesian out = crystal() out.atoms = [] out.cell = structure.cell latcell = np.array(out.cell) convmat_frac_to_cartesian = latcell.T for atom in atoms_frac: cartesian = list( convmat_frac_to_cartesian.dot(np.array([atom[1], atom[2], atom[3]]))) out.atoms.append( Atom(name=atom[0], x=cartesian[0], y=cartesian[1], z=cartesian[2])) # return out
def read_structure(filepath): """ read in input structure :param filepath: file path for the input structure file it will judge the file type by the suffix of the file :return a: an instance of pymatflow.structure.crystal """ if filepath.split(".")[-1] == "xyz": from pymatflow.structure.crystal import crystal a = crystal() a.from_xyz_file(filepath) elif filepath.split(".")[-1] == "cif": from pymatflow.structure.crystal import crystal import pymatflow.third.aseio as aseio a = crystal() a.cell, a.atoms = aseio.read_cif(filepath) elif filepath.split(".")[-1] == "xsd": from pymatflow.structure.crystal import crystal import pymatflow.third.aseio as aseio a = crystal() a.cell, a.atoms = aseio.read_xsd(filepath) elif filepath.split(".")[-1] == "xsf": from pymatflow.structure.crystal import crystal import pymatflow.third.aseio as aseio a = crystal() a.cell, a.atoms = aseio.read_xsf(filepath) elif filepath.split(".")[-1] == "cfg": from pymatflow.structure.crystal import crystal import pymatflow.third.aseio as aseio a = crystal() a.cell, a.atoms = aseio.read_cfg(filepath) elif os.path.basename(filepath) == "POSCAR" or os.path.basename( filepath) == "CONTCAR": from pymatflow.structure.crystal import crystal import pymatflow.third.aseio as aseio a = crystal() a.cell, a.atoms = aseio.read_poscar(filepath) elif filepath.split(".")[-1] == "lammps" or filepath.split( ".")[-1] == "lmp": from pymatflow.structure.crystal import crystal import pymatflow.third.aseio as aseio a = crystal() a.cell, a.atoms = aseio.read_lammps_data(filepath) else: pass return a
def main(): parser = argparse.ArgumentParser() subparsers = parser.add_subparsers( dest="driver", title="subcommands", description="choose one and only one subcommand") # -------------------------------------------------------------------------- # supercell builder # -------------------------------------------------------------------------- subparser = subparsers.add_parser("supercell", help="using supercell subcommand") subparser.add_argument("-i", "--input", type=str, required=True, help="input structure file") subparser.add_argument("-o", "--output", type=str, required=True, help="output structure file") subparser.add_argument("-n", "--supern", nargs="+", type=int, help="bulid supern:[int, int, int] supercell") # -------------------------------------------------------------------------- # fix atoms # -------------------------------------------------------------------------- subparser = subparsers.add_parser("fix", help="using fix subcommand") subparser.add_argument("-i", "--input", type=str, required=True, help="input structure file") subparser.add_argument("-o", "--output", type=str, required=True, help="output structure file") subparser.add_argument( "--fix", help= "list of fixed atoms, index start from 1, have privilege over --around-z", nargs='+', type=int, default=None) subparser.add_argument( "--around-z", type=float, nargs=3, default=None, help= "select atoms around specified z in Angstrom with tolerance, like this --around-z 10 -0.5 0.5" ) subparser.add_argument( "--color", type=str, default="white", choices=["red", "green", "blue", "white"], help= "select color to color the fix atoms in xsd file, can be: red green blue and white" ) # -------------------------------------------------------------------------- # convert file type # -------------------------------------------------------------------------- subparser = subparsers.add_parser("convert", help="using convert subcommand") subparser.add_argument("-i", "--input", type=str, required=True, help="input structure file") subparser.add_argument("-o", "--output", type=str, required=True, help="output structure file") # -------------------------------------------------------------------------- # kpath # -------------------------------------------------------------------------- subparser = subparsers.add_parser("kpath", help="using kpath subcommand") subparser.add_argument("-i", "--input", type=str, required=True, help="input structure file") subparser.add_argument("--engine", type=str, default="seekpath", choices=["seekpath"], help="choose tool to generate kpath") subparser.add_argument("--kpath-file", type=str, default="kpath-from-seekpath.txt", help="the output kpoints file") # --------------------------------------------------------------------------------- # move atoms along one direction # --------------------------------------------------------------------------------- subparser = subparsers.add_parser("move", help="move atoms along one direction") subparser.add_argument("-i", "--input", type=str, required=True, help="input structure file") subparser.add_argument("-o", "--output", type=str, required=True, help="output structure file") subparser.add_argument("--atoms", type=int, nargs="+", help="atoms to move, index start from 1") subparser.add_argument( "--direction", type=float, nargs=3, help= "direction to move the atoms, in format of crystal orientation index") subparser.add_argument( "--disp", type=float, help="displacement along the moving direction, in unit of Anstrom") # --------------------------------------------------------------------------------- # remove atoms # --------------------------------------------------------------------------------- subparser = subparsers.add_parser("remove", help="remove specified atoms") subparser.add_argument("-i", "--input", type=str, required=True, help="input structure file") subparser.add_argument("-o", "--output", type=str, required=True, help="output structure file") subparser.add_argument("--atoms", type=int, nargs="+", help="atoms to remove, index start from 1") subparser.add_argument("--elements", type=str, nargs="+", help="elements to remove") # --------------------------------------------------------------------------------- # vacuum layer # --------------------------------------------------------------------------------- subparser = subparsers.add_parser("vacuum", help="add vacuum layer") subparser.add_argument("-i", "--input", type=str, required=True, help="input structure file") subparser.add_argument("-o", "--output", type=str, required=True, help="output structure file") subparser.add_argument( "--plane", type=int, default=1, help="on which plane to add vacuum layer. 1: ab, 2: ac, 3: bc") subparser.add_argument( "--thick", type=float, default=10, help="thickness of the vacuum layer, in unit of Angstrom, default is 10" ) # --------------------------------------------------------------------------------- # inverse atoms against geometric center # --------------------------------------------------------------------------------- subparser = subparsers.add_parser("inverse", help="inverse against geo center") subparser.add_argument("-i", "--input", type=str, required=True, help="input structure file") subparser.add_argument("-o", "--output", type=str, required=True, help="output structure file") subparser.add_argument("-c", "--center", type=str, default="cell", choices=["geo", "cell"], help="inversion center, can geo or cell") # --------------------------------------------------------------------------------- # redefine lattice # --------------------------------------------------------------------------------- subparser = subparsers.add_parser("redefine", help="redefine lattice") subparser.add_argument("-i", "--input", type=str, required=True, help="input structure file") subparser.add_argument("-o", "--output", type=str, required=True, help="output structure file") subparser.add_argument("-a", type=int, nargs=3, default=[1, 0, 0], help="a from old a b c") subparser.add_argument("-b", type=int, nargs=3, default=[0, 1, 0], help="b from old a b c") subparser.add_argument("-c", type=int, nargs=3, default=[0, 0, 1], help="c from old a b c") subparser.add_argument( "--precision", type=float, default=1.0e-8, help= "a value that is less than 1 and infinitely close to 1 used to judge whether one atom is in another periodic of the redefined cell" ) # --------------------------------------------------------------------------------- # cleave surface # --------------------------------------------------------------------------------- subparser = subparsers.add_parser("cleave", help="cleave surface") subparser.add_argument("-i", "--input", type=str, required=True, help="input structure file") subparser.add_argument("-o", "--output", type=str, required=True, help="output structure file") subparser.add_argument("--direction", type=int, nargs=3, default=[0, 0, 1], help="direction of the surface plane to cleave") subparser.add_argument( "--thick", type=float, help="thickness of the vacuum layer, in unit of Angstrom, default is 10" ) subparser.add_argument( "--precision", type=float, default=1.0e-8, help= "a value that is large than 0 and infinitely close to 0 used to judge whether one atom is in another periodic of the redefined cell used in cleave surface" ) # --------------------------------------------------------------------------------- # merge layers | ab plane # --------------------------------------------------------------------------------- subparser = subparsers.add_parser("merge", help="merge layers | ab plane") subparser.add_argument("-i", "--input", type=str, nargs=2, required=True, help="input structure files") subparser.add_argument("-o", "--output", type=str, required=True, help="output structure file") #subparser.add_argument("--direction", type=int, nargs=3, default=[0, 0, 1], # help="direction of the surface plane to cleave") subparser.add_argument( "--usecell", type=str, default="average", choices=["1", "2", "average"], help="use cell of structure 1 or 2 , otherwise average by default") subparser.add_argument( "--thick", type=float, help="thickness of the vacuum layer, in unit of Angstrom, default is 10" ) subparser.add_argument( "--distance", type=float, help="distance between the layer, in unit of Angstrom, default is 3.4") # --------------------------------------------------------------------------------- # nanotube builder # --------------------------------------------------------------------------------- subparser = subparsers.add_parser( "tube", help= "nanotube along b direction(a must be perpendicular to b and ab is the surface plane)" ) subparser.add_argument("-i", "--input", type=str, required=True, help="input structure files") subparser.add_argument("-o", "--output", type=str, required=True, help="output structure file") subparser.add_argument( "--plane", type=int, default=1, help="on which plane to add vacuum layer. 1: ab, 2: ac, 3: bc") subparser.add_argument( "--axis", type=str, default="b", choices=["a", "b", "c"], help="build nanotube along an axis parallel to axis specified") # ----------------------------------------------------------------------------------- # set frac within zero and one # ------------------------------------------------------------------------------------ subparser = subparsers.add_parser( "std", help="set fractional coordinates within zero and one") subparser.add_argument("-i", "--input", type=str, required=True, help="input structure file") subparser.add_argument("-o", "--output", type=str, required=True, help="output structure file") # ------------------------------------------------------------------------------------ # generate series of cell volume changed structures # ------------------------------------------------------------------------------------ subparser = subparsers.add_parser( "cv", help="generate series of cell volume changed structures") subparser.add_argument("-i", "--input", type=str, required=True, help="input structure file") subparser.add_argument("-d", "--directory", type=str, default="./", help="directory to put the generated structures") subparser.add_argument( "--range", type=float, nargs=3, default=[0.95, 1.05, 0.01], help="cell volume change ratio, default is [0.95, 1.05, 0.01]") # ========================================================== # transfer parameters from the arg subparser to static_run setting # ========================================================== args = parser.parse_args() # if no argument passed to matflow if len(sys.argv) == 1: # display help message when no args provided parser.print_help() sys.exit(1) if args.driver == "supercell": from pymatflow.base.xyz import base_xyz from pymatflow.structure.crystal import crystal a = read_structure(filepath=args.input) supercell = a.build_supercell(args.supern) new_structure = crystal() new_structure.get_cell_atoms(cell=supercell["cell"], atoms=supercell["atoms"]) write_structure(structure=new_structure, filepath=args.output) print("=========================================================\n") print(" structflow supercell builder\n") print("---------------------------------------------------------\n") print("you are trying to bulid supercell from %s\n" % args.input) print("the output structure file is -> %s\n" % args.output) elif args.driver == "fix": # can only write xyz and poscar file a = read_structure(filepath=args.input) if args.fix != None: fix = args.fix elif args.around_z != None: atoms_index_from_1 = [] for i in range(len(a.atoms)): if a.atoms[i].z > (args.around_z[0] + args.around_z[1]) and a.atoms[i].z < ( args.around_z[0] + args.around_z[2]): atoms_index_from_1.append(i + 1) fix = atoms_index_from_1 else: fix = [] if args.output.split(".")[-1] == "xyz": fix_str = "" for i in fix: fix_str += "%d " % i os.system("xyz-fix-atoms.py -i %s -o %s --fix %s" % (args.input, args.output, fix_str)) elif os.path.basename(args.output) == "POSCAR": from pymatflow.vasp.base.poscar import vasp_poscar for i in fix: a.atoms[i - 1].fix = [True, True, True] poscar = vasp_poscar() poscar.xyz.cell = a.cell poscar.xyz.atoms = a.atoms poscar.xyz.natom = len(poscar.xyz.atoms) poscar.xyz.set_species_number() # needed for poscar output poscar.selective_dynamics = True with open(args.output, 'w') as fout: poscar.to_poscar(fout=fout, coordtype="Direct") else: print( "===============================================================\n" ) print(" WARNING !!!\n") print( "---------------------------------------------------------------\n" ) print("structflow fix now only supports write of xyz and POSCAR\n") sys.exit(1) # output an xsd file with fixed atoms colored specifically so that user can check the atoms fixed from xml.etree.ElementTree import parse os.system("mkdir -p /tmp/structflow/fix") write_structure(a, filepath="/tmp/structflow/fix/tmp.xsd") # read xsd file xsd = parse("/tmp/structflow/fix/tmp.xsd") # ID of Atom3D in xsd file start from 4 imap = xsd.getroot().find("AtomisticTreeRoot").find( "SymmetrySystem").find("MappingSet").find("MappingFamily").find( "IdentityMapping") atoms = imap.findall("Atom3d") if args.color == "white": RGB = [255, 255, 255] elif args.color == "red": RGB = [255, 0, 0] elif args.color == "green": RGB = [0, 255, 0] elif args.color == "blue": RGB = [0, 0, 255] else: RGB = [255, 255, 255] # default for i in fix: atoms[i - 1].set("Color", "%f, %f, %f, %f" % (RGB[0], RGB[1], RGB[2], 1)) # write xsd file xsd.write(args.input + ".coloring.atoms.fixed.xsd") elif args.driver == "convert": # will convert file type according to the suffix of the specified input and output file a = read_structure(filepath=args.input) write_structure(structure=a, filepath=args.output) print("=========================================================\n") print(" structflow convert\n") print("---------------------------------------------------------\n") print("with the help from ase.io\n") elif args.driver == "kpath": if args.engine == "seekpath": os.system("kpath-xyz-seekpath.py -i %s -o %s" % (args.input, args.output)) else: pass elif args.driver == "move": from pymatflow.structure.tools import move_along # input structure a = read_structure(filepath=args.input) # move atoms print("=========================================================\n") print(" structflow\n") print("----------------------------------------------------------\n") print("you are trying to move atoms:\n") print(args.atoms) for i in args.atoms: print("%d -> %s\n" % (i, a.atoms[i - 1].name)) print("\n") print("along direction:\n") print(args.direction) print("\n") print("by length of -> %f, in unit of Angstrom\n" % args.disp) move_along(a, atoms_to_move=[i - 1 for i in args.atoms], direc=args.direction, disp=args.disp) # output structure write_structure(structure=a, filepath=args.output) elif args.driver == "remove": from pymatflow.structure.tools import remove_atoms a = read_structure(filepath=args.input) # remove atoms print( "=======================================================================\n" ) print(" structflow\n") print( "-----------------------------------------------------------------------\n" ) print( "you are trying to remove from %s the following list of atoms:\n" % args.input) print(args.atoms) if args.atoms != None: for i in args.atoms: print("%d -> %s\n" % (i, a.atoms[i - 1].name)) else: pass print("\n") print("also the following elements will be removed:\n") print(args.elements) print("the output structure file is -> %s\n" % args.output) if args.atoms != None: remove_atoms(a, atoms_to_remove=[i - 1 for i in args.atoms]) # we should first remove atoms specified by args.atoms # and remove atoms specified by args.elements # as remove atom will change the index of atom if args.elements != None: element_atoms_to_remove = [] for i in range(len(a.atoms)): if a.atoms[i].name in args.elements: element_atoms_to_remove.append(i) remove_atoms(a, atoms_to_remove=element_atoms_to_remove) # output structure write_structure(structure=a, filepath=args.output) elif args.driver == "vacuum": from pymatflow.structure.tools import vacuum_layer a = read_structure(filepath=args.input) # add vacuum layer print( "=======================================================================\n" ) print(" structflow\n") print( "-----------------------------------------------------------------------\n" ) if args.plane == 1: plane = "ab" elif args.plane == 2: plane = "ac" elif args.plane == 3: plane = "bc" print( "you are trying to add vacuum layer of %f Angstrom on %s plane\n" % (args.thick, plane)) print("from %s\n" % args.input) print("\n") print("the output structure file is -> %s\n" % args.output) vacuum_layer(a, plane=args.plane, thickness=args.thick if args.thick != None else 10.0) # output structure write_structure(structure=a, filepath=args.output) elif args.driver == "inverse": from pymatflow.structure.tools import inverse_geo_center from pymatflow.structure.tools import inverse_cell_center a = read_structure(filepath=args.input) print( "=======================================================================\n" ) print(" structflow\n") print( "-----------------------------------------------------------------------\n" ) if args.center == "geo": print( "you are trying to inverse the system against the geometric center\n" ) elif args.center == "cell": print( "you are trying to inverse the system against the cell center\n" ) print("from %s\n" % args.input) print("\n") print("the output structure file is -> %s\n" % args.output) if args.center == "geo": inverse_geo_center(a) elif args.center == "cell": inverse_cell_center(a) # output structure write_structure(structure=a, filepath=args.output) elif args.driver == "redefine": from pymatflow.structure.tools import redefine_lattice a = read_structure(filepath=args.input) print( "=======================================================================\n" ) print(" structflow\n") print( "-----------------------------------------------------------------------\n" ) print("you are trying to redefine the lattice\n") print("from %s\n" % args.input) print("\n") print("the output structure file is -> %s\n" % args.output) redefined = redefine_lattice(structure=a, a=args.a, b=args.b, c=args.c, precision=args.precision) # output structure write_structure(structure=redefined, filepath=args.output) elif args.driver == "cleave": from pymatflow.structure.tools import cleave_surface a = read_structure(filepath=args.input) print( "=======================================================================\n" ) print(" structflow\n") print( "-----------------------------------------------------------------------\n" ) print("you are trying to cleave the surface of (%d, %d, %d)\n" % (args.direction[0], args.direction[1], args.direction[2])) print("from %s\n" % args.input) print("\n") print("the output structure file is -> %s\n" % args.output) cleaved = cleave_surface( structure=a, direction=args.direction, thickness=args.thick if args.thick != None else 10.0, precision=args.precision) # output structure write_structure(structure=cleaved, filepath=args.output) elif args.driver == "merge": from pymatflow.structure.tools import merge_layers a_list = [] for i in range(2): a_list.append(read_structure(filepath=args.input[i])) print( "=======================================================================\n" ) print(" structflow\n") print( "-----------------------------------------------------------------------\n" ) print("you are trying to merge layers on ab plane\n") print("from %s\n" % (args.input[0])) print("and %s\n" % (args.input[1])) print("\n") print("the output structure file is -> %s\n" % args.output) if args.usecell == "1": usecell = 1 elif args.usecell == "2": usecell = 2 else: usecell = "average" merged = merge_layers( structure1=a_list[0], structure2=a_list[1], use_cell=usecell, distance=args.distance if args.distance != None else 3.4, thickness=args.thick if args.thick != None else 10.0) # output structure write_structure(structure=merged, filepath=args.output) elif args.driver == "tube": a = read_structure(filepath=args.input) if args.plane == 1: plane = "ab" elif args.plane == 2: plane = "ac" elif args.plane == 3: plane = "bc" print( "=======================================================================\n" ) print(" structflow\n") print( "-----------------------------------------------------------------------\n" ) print( "you are trying to build nanotube of %s plane along %s vector\n" % (plane, args.axis)) print("from %s\n" % (args.input)) print("the output structure file is -> %s\n" % args.output) tube = None if plane == "ab": from pymatflow.structure.tools import build_nanotube_ab if args.axis not in "ab": print( "building nanotube of ab plane along axis parallel to c is unphysical!!!\n" ) sys.exit() else: tube = build_nanotube_ab(structure=a, axis=args.axis) if plane == "ac": from pymatflow.structure.tools import build_nanotube_ac if args.axis not in "ac": print( "building nanotube of ac plane along axis parallel to b is unphysical!!!\n" ) sys.exit() else: tube = build_nanotube_ac(structure=a, axis=args.axis) if plane == "bc": from pymatflow.structure.tools import build_nanotube_bc if args.axis not in "bc": print( "building nanotube of bc plane along axis parallel to a is unphysical!!!\n" ) sys.exit() else: tube = build_nanotube_bc(structure=a, axis=args.axis) # output structure if tube != None: write_structure(structure=tube, filepath=args.output) elif args.driver == "std": from pymatflow.structure.tools import set_frac_within_zero_and_one a = read_structure(filepath=args.input) print( "=======================================================================\n" ) print(" structflow\n") print( "-----------------------------------------------------------------------\n" ) print("you are trying to set fractional coords within 0 and 1\n") print("from %s\n" % (args.input)) print("\n") print("the output structure file is -> %s\n" % args.output) normalized = set_frac_within_zero_and_one(structure=a) # output structure write_structure(structure=normalized, filepath=args.output) elif args.driver == "cv": from pymatflow.structure.crystal import crystal from pymatflow.base.atom import Atom a = read_structure(filepath=args.input) print( "=======================================================================\n" ) print(" structflow\n") print( "-----------------------------------------------------------------------\n" ) print( "you are trying to get a series of structure with different volume\n" ) print("from %s\n" % (args.input)) print("\n") print("the output dir for structure file is -> %s\n" % args.directory) # now calc the fractional coordinates atoms_frac = [] latcell = np.array(a.cell) convmat = np.linalg.inv(latcell.T) for i in range(len(a.atoms)): atom = [] atom.append(a.atoms[i].name) atom = atom + list( convmat.dot( np.array([a.atoms[i].x, a.atoms[i].y, a.atoms[i].z]))) atoms_frac.append(atom) # out = crystal() os.system("mkdir -p %s" % args.directory) for i, ratio_v in enumerate( np.arange(args.range[0], args.range[1], args.range[2])): ratio = np.power(ratio_v, 1 / 3) # now convert coord of atom in atoms_frac_within_new_cell to cartesian out.atoms = [] out.cell = (np.array(a.cell) * ratio).tolist() latcell = np.array(out.cell) convmat_frac_to_cartesian = latcell.T for atom in atoms_frac: cartesian = list( convmat_frac_to_cartesian.dot( np.array([atom[1], atom[2], atom[3]]))) out.atoms.append( Atom(name=atom[0], x=cartesian[0], y=cartesian[1], z=cartesian[2])) output_name = ".".join( os.path.basename(args.input).split(".")[:-1] + ["%d" % i, "cif"]) write_structure(out, filepath=os.path.join(args.directory, output_name)) # with open(os.path.join(args.directory, "log.txt"), 'w') as fout: fout.write("# index\tratio_v\tvolume(Angstrom^3)\n") for i, ratio_v in enumerate( np.arange(args.range[0], args.range[1], args.range[2])): ratio = np.power(ratio_v, 1 / 3) cell_now = (np.array(a.cell) * ratio).tolist() fout.write("%d\t%f\t%f\n" % (i, ratio_v, np.linalg.det(cell_now)))
def main(): parser = argparse.ArgumentParser() parser.add_argument("-i", "--input", type=str, required=True, help="input cube file") parser.add_argument("--output-structure", type=str, default="cube.cif", help="output stucture contained in PARCHG") parser.add_argument("-o", "--output", type=str, default="cube", help="prefix of the output image file name") parser.add_argument("--levels", type=int, default=10, help="levels of the color map or color bar") parser.add_argument( "-z", "--z", type=float, default=1, help= "a value between 0 and 1, indicat height of in z direction to print the plot" ) parser.add_argument("--cmap", type=str, default="gray", choices=[ "gray", "hot", "afmhot", "Spectral", "plasma", "magma", "hsv", "rainbow", "brg" ]) # ========================================================== # transfer parameters from the arg subparser to static_run setting # ========================================================== args = parser.parse_args() cube_filepath = args.input with open(cube_filepath, "r") as fin: cube = fin.readlines() ngridx = int(cube[3].split()[0]) ngridy = int(cube[4].split()[0]) ngridz = int(cube[5].split()[0]) # read structure info natom = abs(int( cube[2].split() [0])) # it might be negative, if MO infor are included in cube file bohr_to_angstrom = 0.529177249 structure = crystal() structure.cell = [] for i in range(3): tmp = [] for j in range(3): tmp.append( int(cube[i + 3].split()[0]) * float(cube[i + 3].split()[j + 1]) * bohr_to_angstrom) structure.cell.append(tmp) atoms_list = [] for i in range(natom): atomic_number = int(cube[i + 6].split()[0]) for e in elem: if elem[e].number == atomic_number: label = e atoms_list.append([ label, float(cube[i + 6].split()[2]) * bohr_to_angstrom, float(cube[i + 6].split()[3]) * bohr_to_angstrom, float(cube[i + 6].split()[4]) * bohr_to_angstrom, ]) structure.get_atoms(atoms_list) # end read structure info write_structure(structure=structure, filepath=args.output_structure) # read grid value tmp_str = "".join(cube[natom + 6:]) data = np.fromstring(tmp_str, sep="\n") #data = data.reshape(ngridz, ngridy, ngridx) # grid data in cube is iterated in different compared to *CHG* of vasp data = data.reshape(ngridx, ngridy, ngridz) # charge data in cube file is in shape (ngridx, ngridy, ngridz) # while charge in *CHG* file is in shape (ngzf, ngyf, ngxf) # they are different! # ------------------------------------------------------- # matrix image only for z direction # may not work for triclinic and monoclinic crystal system # ------------------------------------------------------- zi = int((data.shape[2] - 1) * args.z) img = data[::, ::, zi].T #.reshape(ngridy, ngridx) should be transpose here but not reshape img = (img - img.min()) / (img.max() - img.min()) * 255 # need to do a transform when the cell is not Orthorhombic # skew the image a = np.array(structure.cell[0]) b = np.array(structure.cell[1]) cosangle = a.dot(b) / (np.linalg.norm(a) * np.linalg.norm(b)) angle = np.arccos(cosangle) * 180 / np.pi ax = plt.axes() #plt.figure() n1 = ngridx n2 = ngridy n1_right = n1 n1_left = -(n2 * np.tan((angle - 90) / 180 * np.pi)) #im = ax.imshow(img, cmap="gray", extent=[0, n1, 0, n2], interpolation="none", origin="lower", clip_on=True) im = ax.imshow(img, cmap=args.cmap, extent=[0, n1, 0, n2], interpolation="none", origin="lower", clip_on=True) #im = plt.imshow(data[i, :, :], cmap="gray") trans_data = mtransforms.Affine2D().skew_deg(90 - angle, 0) + ax.transData im.set_transform(trans_data) # display intended extent of the image x1, x2, y1, y2 = im.get_extent() # do not view the line, but it is needed to be plot so the intended image is dispalyed completely ax.plot([x1, x2, x2, x1, x1], [y1, y1, y2, y2, y1], "y--", transform=trans_data, visible=False) #ax.set_xlim(n1_left, n1_right) #ax.set_ylim(0, n2) plt.colorbar(im) ax.autoscale() plt.tight_layout() plt.savefig(args.output + "-z-%f.matrix-image.png" % args.z) plt.close() # ----------------------------------------------------------------------------- # 2D contour plot #------------------------------------------------------------------------------ nx = np.linspace(0, 1, ngridx) ny = np.linspace(0, 1, ngridy) X, Y = np.meshgrid( nx, ny ) # now this Mesh grid cannot be used directly, we have to calc the real x y for it for xi in range(len(nx)): for yi in range(len(ny)): X[yi, xi] = structure.cell[0][0] * nx[xi] + structure.cell[1][ 0] * ny[yi] Y[yi, xi] = structure.cell[0][1] * nx[xi] + structure.cell[1][ 1] * ny[yi] Z = data[::, ::, zi].T #.reshape(ngridy, ngridx) should be transpose here but not reshape Z = (Z - Z.min()) / (Z.max() - Z.min()) * 255 # fill color, three color are divided into three layer(6) # cmap = plt.cm.hot means using thermostat plot(graduated red yellow) #cset = plt.contourf(X, Y, Z, levels=args.levels, cmap=plt.cm.hot) #cset = plt.contourf(X, Y, Z, levels=args.levels, cmap=plt.cm.gray) cset = plt.contourf(X, Y, Z, levels=args.levels, cmap=args.cmap) contour = plt.contour(X, Y, Z, levels=[20, 40], colors='k') plt.colorbar(cset) plt.autoscale() plt.tight_layout() #plt.show() plt.axis("equal") # set axis equally spaced plt.xlabel('x') plt.ylabel('y') plt.savefig(args.output + ".2d-contour-z-%f.png" % args.z) plt.close()
def main(): parser = argparse.ArgumentParser() parser.add_argument("-i", "--input", type=str, required=True, help="input cube file, -i xxx.cube") parser.add_argument("--output-structure", type=str, default="chg", help="output stucture contained in cube file") parser.add_argument("-o", "--output", type=str, default="chg", help="prefix of the output image file name") parser.add_argument("--levels", type=int, default=10, help="levels of the color map or color bar") parser.add_argument( "-z", "--z", type=float, default=1, help= "a value between 0 and 1, indicat height of in z direction to print the plot" ) parser.add_argument("--cmap", type=str, default="gray", choices=[ "gray", "hot", "afmhot", "Spectral", "plasma", "magma", "hsv", "rainbow", "brg" ]) parser.add_argument( "--abscissa", type=str, nargs="+", default=["a", "b", "c"], choices=["a", "b", "c"], help="choose the direction to do the dimension reduction") # ========================================================== # transfer parameters from the arg subparser to static_run setting # ========================================================== args = parser.parse_args() cube_filepath = args.input with open(cube_filepath, "r") as fin: cube = fin.readlines() bohr_to_angstrom = 0.529177249 # read structure info natom = abs(int( cube[2].split() [0])) # it might be negative, if MO infor are included in cube file structure = crystal() structure.cell = [] for i in range(3): tmp = [] for j in range(3): tmp.append( int(cube[i + 3].split()[0]) * float(cube[i + 3].split()[j + 1]) * bohr_to_angstrom) structure.cell.append(tmp) atoms_list = [] for i in range(natom): atomic_number = int(cube[i + 6].split()[0]) for e in elem: if elem[e].number == atomic_number: label = e atoms_list.append([ label, float(cube[i + 6].split()[2]) * bohr_to_angstrom, float(cube[i + 6].split()[3]) * bohr_to_angstrom, float(cube[i + 6].split()[4]) * bohr_to_angstrom, ]) structure.get_atoms(atoms_list) # end read structure info write_structure(structure=structure, filepath=args.output_structure + ".cif") a = np.linalg.norm(structure.cell[0]) b = np.linalg.norm(structure.cell[1]) c = np.linalg.norm(structure.cell[2]) # assume three cube file have the same ngridx ngridy and ngridz ngridx = int(cube[3].split()[0]) ngridy = int(cube[4].split()[0]) ngridz = int(cube[5].split()[0]) # read grid value tmp_str = "".join(cube[natom + 6:]) data = np.fromstring(tmp_str, sep="\n") # grid data in cube is iterated in different compared to *CHG* of vasp data = data.reshape(ngridx, ngridy, ngridz) # charge data in cube file is in shape (ngridx, ngridy, ngridz) # while charge in *CHG* file is in shape (ngzf, ngyf, ngxf) # they are different! # data dimension reduction # the unit of value is actually not physical now! # # cell_volume are in unit of Angstrom^3 cell_volume = np.dot( np.cross(np.array(structure.cell[0]), np.array(structure.cell[1])), np.array(structure.cell[2])) cell_volume_per_unit = cell_volume / (ngridx * ngridy * ngridz) # value in cube file are \rho(r)_of_electrons in unit of e/Bohr^3 # namely number of electrons each Borh^3 # so we have to convert it to e/Angstrom^23, through divide it by borh_to_angstrom**3 total_electrons = np.sum(data) * cell_volume_per_unit / bohr_to_angstrom**3 # print("======================================================\n") print(" Information collected\n") print("------------------------------------------------------\n") print("cell volume: %f (A^3)\n" % cell_volume) print("total electrons: %f\n" % total_electrons) # data is in unit of e/Bohr^3 # we will build data_red_? to be in unit of e/Anstrom, namely number of electrons per Angstrom # to do this we have to time the volume density with bohr_to_angstrom^-3 data_red_a = [] data_red_b = [] data_red_c = [] if "c" in args.abscissa: len_ci = c / ngridz for ci in range(data.shape[2]): tmp = 0 for bi in range(data.shape[1]): tmp += np.sum(data[:, bi, ci]) nelect_ci = tmp * cell_volume_per_unit / bohr_to_angstrom**3 rho_line = nelect_ci / len_ci data_red_c.append(rho_line) if "b" in args.abscissa: len_bi = b / ngridy for bi in range(data.shape[1]): tmp = 0 for ai in range(data.shape[0]): tmp += np.sum(data[ai, bi, :]) nelect_bi = tmp * cell_volume_per_unit / bohr_to_angstrom**3 rho_line = nelect_bi / len_bi data_red_b.append(rho_line) if "a" in args.abscissa: len_ai = a / ngridx for ai in range(data.shape[0]): tmp = 0 for ci in range(data.shape[2]): tmp += np.sum(data[ai, :, ci]) nelect_ai = tmp * cell_volume_per_unit / bohr_to_angstrom**3 rho_line = nelect_ai / len_ai data_red_a.append(rho_line) # output the data and make the plot if "c" in args.abscissa: with open(args.output + ".1d.c.data", 'w') as fout: fout.write( "#c(angstrom) rho(e) (number of electron per Angstrom)\n") c_coord = np.linspace(0, c, len(data_red_c)) for i in range(len(data_red_c)): fout.write("%f %f\n" % (c_coord[i], data_red_c[i])) plt.plot(np.linspace(0, c, len(data_red_c)), data_red_c) plt.ylabel(r"$\rho (e/\AA)$") plt.tight_layout() plt.savefig(args.output + ".1d.c.png") plt.close() if "b" in args.abscissa: with open(args.output + ".1d.b.data", 'w') as fout: fout.write( "#b(angstrom) rho(e) (number of electron per Angstrom)\n") b_coord = np.linspace(0, b, len(data_red_b)) for i in range(len(data_red_b)): fout.write("%f %f\n" % (b_coord[i], data_red_b[i])) plt.plot(np.linspace(0, b, len(data_red_b)), data_red_b) plt.ylabel(r"$\rho (e/\AA)$") plt.tight_layout() plt.savefig(args.output + ".1d.b.png") plt.close() if "a" in args.abscissa: with open(args.output + ".1d.a.data", 'w') as fout: fout.write( "#a(angstrom) rho(e) (number of electron per Angstrom)\n") a_coord = np.linspace(0, a, len(data_red_a)) for i in range(len(data_red_a)): fout.write("%f %f\n" % (a_coord[i], data_red_a[i])) plt.plot(np.linspace(0, a, len(data_red_a)), data_red_a) plt.ylabel(r"$\rho (e/\AA)$") plt.tight_layout() plt.savefig(args.output + ".1d.a.png") plt.close()
element_n_list = [] for i in range(len(xdatcar[5].split())): element = {} element["label"] = xdatcar[5].split()[i] element["n"] = int(xdatcar[6].split()[i]) element_n_list.append(element) element_list = [] for i in range(len(element_n_list)): for j in range(element_n_list[i]["n"]): element_list.append(element_n_list[i]["label"]) images = [] for i in range(nimage): image = crystal() image.cell = [] if i == 0: for j in range(3): tmp = [ float(xdatcar[2 + j].split()[0]), float(xdatcar[2 + j].split()[1]), float(xdatcar[2 + j].split()[2]) ] image.cell.append(tmp) else: if vc == False: image.cell = images[-1].cell else: for j in range(3): tmp = [
def merge_layers(structure1, structure2, use_cell=None, distance=3.4, thickness=10): """ :param structure1: an instance of crystal() :param structure2: an instance of crystal() :param use_cell: use cell parameter of structure 1 or 2 or None(average) to set the new a b cell parameter attention: c vector is not handled this way :param distance: the distance between layers :param thickness: the vaccum layer thickness of the combined system :return an object of crystal() Note: only merge layers with ab plane as the surface plane """ from pymatflow.structure.crystal import crystal from pymatflow.base.atom import Atom structure1 = set_frac_within_zero_and_one(structure1) structure2 = set_frac_within_zero_and_one(structure2) old_cell_1 = copy.deepcopy(structure1.cell) old_cell_2 = copy.deepcopy(structure2.cell) # first transfer to fractional coordinate structure1.natom = len(structure1.atoms) frac_1 = structure1.get_fractional() structure2.natom = len(structure2.atoms) frac_2 = structure2.get_fractional() average_cell = [] for i in range(3): average_cell.append( list((np.array(old_cell_1[i]) + np.array(old_cell_2[i])) / 2)) out = crystal() if use_cell == 1: latcell_frac_to_cart_1 = old_cell_1 latcell_frac_to_cart_2 = old_cell_1[0:2] latcell_frac_to_cart_2.append(old_cell_2[2]) elif use_cell == 2: latcell_frac_to_cart_2 = old_cell_2 latcell_frac_to_cart_1 = old_cell_2[0:2] latcell_frac_to_cart_1.append(old_cell_1[2]) else: #average_ab = [] #for i in range(2): # vec = [] # for j in range(3): # vec.append((old_cell_1[i][j] + old_cell_2[i][j]) / 2 ) # average_ab.append(vec) latcell_frac_to_cart_1 = average_cell latcell_frac_to_cart_1[2] = old_cell_1[2] latcell_frac_to_cart_2 = average_cell latcell_frac_to_cart_2[2] = old_cell_2[2] # convert frac to cartesian again convmat_1 = np.array(latcell_frac_to_cart_1).T convmat_2 = np.array(latcell_frac_to_cart_2).T cart_1 = [] for atom in frac_1: cartesian = list(convmat_1.dot(np.array([atom[1], atom[2], atom[3]]))) cart_1.append([atom[0], cartesian[0], cartesian[1], cartesian[2]]) cart_2 = [] for atom in frac_2: cartesian = list(convmat_2.dot(np.array([atom[1], atom[2], atom[3]]))) cart_2.append([atom[0], cartesian[0], cartesian[1], cartesian[2]]) # make distance gap between cart_1 and cart_2 is the value of distance z_1 = [] for atom in cart_1: z_1.append(atom[3]) z_2 = [] for atom in cart_2: z_2.append(atom[3]) max_z_1 = max(z_1) min_z_2 = min(z_2) for i in range(len(cart_2)): cart_2[i][3] += distance - (min_z_2 - max_z_1) cart_all = cart_1 + cart_2 out.atoms = [] for atom in cart_all: out.atoms.append(Atom(name=atom[0], x=atom[1], y=atom[2], z=atom[3])) if use_cell == 1: out.cell = old_cell_1 factor = (np.linalg.norm(np.array(old_cell_1[2])) + np.linalg.norm( np.array(old_cell_2[2]))) / np.linalg.norm(np.array(old_cell_1[2])) out.cell[2] = list(np.array(old_cell_1[2]) * factor) elif use_cell == 2: out.cell = old_cell_2 factor = (np.linalg.norm(np.array(old_cell_1[2])) + np.linalg.norm( np.array(old_cell_2[2]))) / np.linalg.norm(np.array(old_cell_2[2])) out.cell[2] = list(np.array(old_cell_2[2]) * factor) else: out.cell = average_cell factor = (np.linalg.norm(np.array(old_cell_1[2])) + np.linalg.norm( np.array(old_cell_2[2]))) / np.linalg.norm(np.array(out.cell[2])) out.cell[2] = list(np.array(out.cell[2]) * factor) vacuum_layer(structure=out, plane=1, thickness=thickness) return out
def redefine_lattice(structure, a, b, c, precision=1.0e-8): """ :param a, b, c: new lattice vectors in terms of old. new_a = a[0] * old_a + a[1] * old_b + a[2] * old_c like a=[1, 0, 0], b=[0, 1, 0], c=[0, 0, 1] actually defines the same lattice as old. :param precision, a value that is less than 1 and infinitely close to 1 used to judge whether one atom is in another periodic of the redefined cell :return an object of crystal() Method: first make a large enough supercell, which guarantee that all the atoms in the new lattice are inside the supercell. then redfine the cell, and calc the fractional coord of all atoms with regarding the new cell finally remove those atoms who's fractional coord is not within range [0, 1), and we can convert fractional coords to cartesian. Note: relationship among convertion of coords. the most important point is that all coords actually have one common reference system, namely the General XYZ coordinate system. all the cell are defined with XYZ as reference, and the convmat build from the cell(with XYZ as reference) can be applied only to atoms also with XYZ as ference, finally we convert frac to cartesian using convmat also defined using cell with XYZ as reference, so we get the cartesian with general XYZ as reference. In the last all the coord of atoms and cell have the general XYZ system as reference. So it works! """ from pymatflow.structure.crystal import crystal from pymatflow.base.atom import Atom old_cell = copy.deepcopy(structure.cell) new_cell = copy.deepcopy(structure.cell) new_cell[0] = list(a[0] * np.array(old_cell[0]) + a[1] * np.array(old_cell[1]) + a[2] * np.array(old_cell[2])) new_cell[1] = list(b[0] * np.array(old_cell[0]) + b[1] * np.array(old_cell[1]) + b[2] * np.array(old_cell[2])) new_cell[2] = list(c[0] * np.array(old_cell[0]) + c[1] * np.array(old_cell[1]) + c[2] * np.array(old_cell[2])) # enlarge the system atoms_container = crystal() atoms_container.get_atoms( enlarge_atoms_new_cell(structure=structure, new_cell=new_cell)) print("atoms_container.size(): %d\n" % len(atoms_container.atoms)) # now calc the fractional coordinates of all atoms in atoms_container with new_cell as reference atoms_frac = [] latcell_new = np.array(new_cell) convmat_new = np.linalg.inv(latcell_new.T) for i in range(len(atoms_container.atoms)): atom = [] atom.append(atoms_container.atoms[i].name) atom = atom + list( convmat_new.dot( np.array([ atoms_container.atoms[i].x, atoms_container.atoms[i].y, atoms_container.atoms[i].z ]))) atoms_frac.append(atom) atoms_frac_within_new_cell = [] for atom in atoms_frac: if (0 <= atom[1] < (1 - precision)) and (0 <= atom[2] < (1 - precision)) and (0 <= atom[3] < (1 - precision)): atoms_frac_within_new_cell.append(atom) # now convert coord of atom in atoms_frac_within_new_cell to cartesian out = crystal() out.atoms = [] latcell_new = np.array(new_cell) convmat_frac_to_cartesian = latcell_new.T for atom in atoms_frac_within_new_cell: cartesian = list( convmat_frac_to_cartesian.dot(np.array([atom[1], atom[2], atom[3]]))) out.atoms.append( Atom(name=atom[0], x=cartesian[0], y=cartesian[1], z=cartesian[2])) # out.cell = new_cell return out
def main(): parser = argparse.ArgumentParser() subparsers = parser.add_subparsers( dest="driver", title="subcommands", description="choose one and only one calculator") # -------------------------------------------------------------------------- # LAMMPS # -------------------------------------------------------------------------- subparser = subparsers.add_parser("lmp", help="using lammps as calculator") subparser.add_argument( "-r", "--runtype", type=int, default=0, choices=[0, 1, 2, 3, 4, 5, 6, 7], help= "choices of runtype. 0->static_run; 1->optimization; 2->cubic-cell; 3->hexagonal-cell; 4->tetragonal-cell; 5->neb; 6->vasp-phonon; 7->phonopy" ) subparser.add_argument("-d", "--directory", type=str, default="matflow-running", help="Directory for the running.") # -------------------------------------------------------------------------- # LAMMPS data # -------------------------------------------------------------------------- subparser = subparsers.add_parser("data", help="lammps structure data operation") subparser.add_argument( "-i", "--input", type=str, help="input structure file, canbe xxx.cif, xxx.xyz, xxx.xsd, xxx.cube") subparser.add_argument( "-o", "--output", type=str, default="lammps.data", help="output lammps data file containing the structure information") # ========================================================== # transfer parameters from the arg subparser to static_run setting # ========================================================== args = parser.parse_args() # if no argument passed to matflow if len(sys.argv) == 1: # display help message when no args provided parser.print_help() sys.exit(1) if args.driver == "lmp": pass elif args.driver == "data": # will convert file type according to the suffix of the specified input # input structure if args.input.split(".")[-1] == "xyz": from pymatflow.structure.crystal import crystal a = crystal() a.from_xyz_file(args.input) elif args.input.split(".")[-1] == "cif": from pymatflow.structure.crystal import crystal import pymatflow.third.aseio as aseio a = crystal() a.cell, a.atoms = aseio.read_cif(args.input) elif args.input.split(".")[-1] == "xsd": from pymatflow.structure.crystal import crystal import pymatflow.third.aseio as aseio a = crystal() a.cell, a.atoms = aseio.read_xsd(args.input) elif args.input.split(".")[-1] == "xsf": from pymatflow.structure.crystal import crystal import pymatflow.third.aseio as aseio a = crystal() a.cell, a.atoms = aseio.read_xsf(args.input) elif os.path.basename(args.input) == "POSCAR" or os.path.basename( args.input) == "CONTCAR": from pymatflow.structure.crystal import crystal import pymatflow.third.aseio as aseio a = crystal() a.cell, a.atoms = aseio.read_poscar(args.input) # output structure import pymatflow.third.aseio aseio.write_lammps_data(cell=a.cell, atoms=a.atoms, filepath=args.output) print("=========================================================\n") print(" lmpflow data\n") print("---------------------------------------------------------\n") print("with the help from ase.io\n")
""" usage: xyz-build-supercell.py -i input.xyz -o output.xyz -n n1 n2 n3 n1, n2, n3 are the three repeated number in the three direct of three basis vectors """ if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument("-i", "--input", type=str, help="input xyz file") parser.add_argument("-o", "--output", type=str, help="output xyz file") parser.add_argument("-n", "--supern", nargs="+", type=int, help="bulid supern:[int, int, int] supercell") args = parser.parse_args() xyz = base_xyz() xyz.get_xyz(args.input) structure = crystal() new_structure = crystal() structure.from_base_xyz(xyz) supercell = structure.build_supercell(args.supern) new_structure.get_cell_atoms(cell=supercell["cell"], atoms=supercell["atoms"]) new_structure.to_base_xyz().to_xyz_file(args.output)