From 7c1509e8659b657c88d0f9139e2918b08be03c27 Mon Sep 17 00:00:00 2001 From: Stef Smeets Date: Wed, 15 Feb 2023 10:58:35 +0100 Subject: [PATCH] Tweak metadata and fix pip install --- CITATION.cff | 4 +- setup.cfg | 6 +- topas_tools/cif2patterson.py | 114 ++++++------ topas_tools/expandcell.py | 340 +++++++++++++++++------------------ 4 files changed, 229 insertions(+), 235 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 05a0c79..4f84a46 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -13,9 +13,9 @@ keywords: - "Topas" - "Structure refinement" - "Profile refinement" -license: "GPL-2.0" +license: "MIT" message: "If you use this software, please cite it using these metadata." repository-code: "https://github.com/stefsmeets/topas_tools" title: topas_tools -version: "1.0.0" +version: "1.0.1" ... diff --git a/setup.cfg b/setup.cfg index 03d3f10..af77168 100644 --- a/setup.cfg +++ b/setup.cfg @@ -25,7 +25,7 @@ project_urls = Bug Tracker = https://github.com/stefsmeets/topas_tools/issues Documentation = https://github.com/stefsmeets/topas_tools url = https://github.com/stefsmeets/topas_tools -version = 1.0.0 +version = 1.0.1 [options] @@ -52,9 +52,9 @@ console_scripts = topasrestraints = topas_tools.topas_restraints:main topas_ndxan = topas_tools.topas_ndxan:main restraints_statistics = topas_tools.restraints_statistics:main - cif2patterson = topas_tools.cif2patterson + cif2patterson = topas_tools.cif2patterson:main cif2topas = topas_tools.cif2topas:main - expandcell = topas_tools.expandcell + expandcell = topas_tools.expandcell:main stripcif = topas_tools.stripcif:main topasdiff = topas_tools.topasdiff:main make_superflip = topas_tools.make_superflip:main diff --git a/topas_tools/cif2patterson.py b/topas_tools/cif2patterson.py index d6116d9..f27fae2 100644 --- a/topas_tools/cif2patterson.py +++ b/topas_tools/cif2patterson.py @@ -24,90 +24,88 @@ def read_cif(f): val.show_summary().show_scatterers() return structures +def main(): + usage = """cif2patterson structure.cif""" -usage = """cif2patterson structure.cif""" + description = """Notes: Takes any cif file and generated patterson map + """ -description = """Notes: Takes any cif file and generated patterson map -""" + parser = argparse.ArgumentParser( # usage=usage, + description=description, + formatter_class=argparse.RawDescriptionHelpFormatter) -parser = argparse.ArgumentParser( # usage=usage, - description=description, - formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument("args", + type=str, metavar="FILE", + help="Path to input cif") -parser.add_argument("args", - type=str, metavar="FILE", - help="Path to input cif") + parser.set_defaults( + spgr="P1" + ) -parser.set_defaults( - spgr="P1" -) + options = parser.parse_args() -options = parser.parse_args() + cif = options.args + s = list(read_cif(cif).values())[0] + s = s.expand_to_p1() + print(f"Expanded to P1 => {s.scatterers().size()} atoms") + print() -cif = options.args -s = list(read_cif(cif).values())[0] -s = s.expand_to_p1() -print(f"Expanded to P1 => {s.scatterers().size()} atoms") -print() + root, ext = os.path.splitext(cif) -root, ext = os.path.splitext(cif) + uc = s.unit_cell() -uc = s.unit_cell() + scatterers = s.scatterers() -scatterers = s.scatterers() + fout1 = open("patterson_dists.txt", 'w') + fout2 = open("patterson_full.txt", 'w') -fout1 = open("patterson_dists.txt", 'w') -fout2 = open("patterson_full.txt", 'w') + distances_all = [] -distances_all = [] + verbose = False + for atom1 in scatterers: + x1, y1, z1 = atom1.site -verbose = False -for atom1 in scatterers: - x1, y1, z1 = atom1.site - - if verbose: - print() - atom1.show() - distances = [] - for atom2 in scatterers: if verbose: - atom2.show() - - x2, y2, z2 = atom2.site + print() + atom1.show() + distances = [] + for atom2 in scatterers: + if verbose: + atom2.show() - dx, dy, dz = x1-x2, y1-y2, z1-z2 + x2, y2, z2 = atom2.site - dx = dx % 1 - dy = dy % 1 - dz = dz % 1 + dx, dy, dz = x1-x2, y1-y2, z1-z2 - length = uc.length((dx, dy, dz)) + dx = dx % 1 + dy = dy % 1 + dz = dz % 1 - distances.append((atom2.label, dx, dy, dz, length)) + length = uc.length((dx, dy, dz)) - if verbose: - print(f' --> {atom2.label:>4s} {dx:9.5f} {dy:9.5f} {dz:9.5f} {length:9.5f}') + distances.append((atom2.label, dx, dy, dz, length)) - # print atom1.label, '-->', atom2.label, '=', uc.length((dx,dy,dz)) + if verbose: + print(f' --> {atom2.label:>4s} {dx:9.5f} {dy:9.5f} {dz:9.5f} {length:9.5f}') - distances_all.extend(distances) + # print atom1.label, '-->', atom2.label, '=', uc.length((dx,dy,dz)) - atom1.show(fout2) - for label, dx, dy, dz, distance in sorted(distances, key=lambda x: x[-1]): - print(' --> {:>4s} {:9.5f} {:9.5f} {:9.5f} {:9.5f}'.format( - label, dx, dy, dz, distance), file=fout2) - print(file=fout2) + distances_all.extend(distances) -print('Wrote file', fout2.name) + atom1.show(fout2) + for label, dx, dy, dz, distance in sorted(distances, key=lambda x: x[-1]): + print(' --> {:>4s} {:9.5f} {:9.5f} {:9.5f} {:9.5f}'.format( + label, dx, dy, dz, distance), file=fout2) + print(file=fout2) -for label, dx, dy, dz, distance in sorted(distances_all, key=lambda x: x[-1]): - print(f'{distance:9.5f}', file=fout1) + print('Wrote file', fout2.name) -print('Wrote file', fout1.name) + for label, dx, dy, dz, distance in sorted(distances_all, key=lambda x: x[-1]): + print(f'{distance:9.5f}', file=fout1) -fout1.close() -fout2.close() + print('Wrote file', fout1.name) -sys.exit() + fout1.close() + fout2.close() diff --git a/topas_tools/expandcell.py b/topas_tools/expandcell.py index d428794..fe63cd1 100644 --- a/topas_tools/expandcell.py +++ b/topas_tools/expandcell.py @@ -27,222 +27,218 @@ def read_cif(f): return structures -description = """Notes: -""" +def main(): + description = "expandcell is a tool to create supercells from a cif file." + parser = argparse.ArgumentParser( + description=description, + formatter_class=argparse.RawDescriptionHelpFormatter) -parser = argparse.ArgumentParser( - description=description, - formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument("args", + type=str, metavar="FILE", + help="Path to input cif") + parser.add_argument("-x", + type=int, metavar="N", dest="expand_x", + help="""Expand N times along x direction""") -parser.add_argument("args", - type=str, metavar="FILE", - help="Path to input cif") + parser.add_argument("-y", + type=int, metavar="N", dest="expand_y", + help="""Expand N times along y direction""") -parser.add_argument("-x", - type=int, metavar="N", dest="expand_x", - help="""Expand N times along x direction""") + parser.add_argument("-z", + type=int, metavar="N", dest="expand_z", + help="""Expand N times along z direction""") -parser.add_argument("-y", - type=int, metavar="N", dest="expand_y", - help="""Expand N times along y direction""") + parser.add_argument("-e", "--exclude", + type=str, metavar="X", nargs="+", dest="exclude", + help="""Exclude these elements from final output""") -parser.add_argument("-z", - type=int, metavar="N", dest="expand_z", - help="""Expand N times along z direction""") + parser.add_argument("-f", "--shift", + type=float, metavar="dx dy dz", nargs=3, dest="shift", + help="""Applies shift to coordinates, this number comes directly from PLATON (Origin shifted to ... )""") -parser.add_argument("-e", "--exclude", - type=str, metavar="X", nargs="+", dest="exclude", - help="""Exclude these elements from final output""") + parser.add_argument("-s", "--spgr", + type=str, metavar="P1", dest="spgr", + help="""Apply this symmetry to the new structure (default = P1)""") -parser.add_argument("-f", "--shift", - type=float, metavar="dx dy dz", nargs=3, dest="shift", - help="""Applies shift to coordinates, this number comes directly from PLATON (Origin shifted to ... )""") -parser.add_argument("-s", "--spgr", - type=str, metavar="P1", dest="spgr", - help="""Apply this symmetry to the new structure (default = P1)""") + parser.set_defaults( + expand_x=1, + expand_y=1, + expand_z=1, + exclude=(), + shift=[], + spgr="P1" + ) + options = parser.parse_args() -parser.set_defaults( - expand_x=1, - expand_y=1, - expand_z=1, - exclude=(), - shift=[], - spgr="P1" -) + cif = options.args + s = list(read_cif(cif).values())[0] -options = parser.parse_args() - -cif = options.args -s = list(read_cif(cif).values())[0] + excluded = [] + if options.exclude: + for atom in s.scatterers(): + if atom.element_symbol() in options.exclude: + excluded.append(atom) -excluded = [] -if options.exclude: - for atom in s.scatterers(): - if atom.element_symbol() in options.exclude: - excluded.append(atom) + s = s.expand_to_p1() + print(f"Expanded to P1 => {s.scatterers().size()} atoms") + print() -s = s.expand_to_p1() -print(f"Expanded to P1 => {s.scatterers().size()} atoms") -print() + root, ext = os.path.splitext(cif) -root, ext = os.path.splitext(cif) + expand_x = options.expand_x + expand_y = options.expand_y + expand_z = options.expand_z -expand_x = options.expand_x -expand_y = options.expand_y -expand_z = options.expand_z + spgr = options.spgr + shift = options.shift -spgr = options.spgr -shift = options.shift + assert expand_x > 0, "N must be bigger than 0" + assert expand_y > 0, "N must be bigger than 0" + assert expand_z > 0, "N must be bigger than 0" -assert expand_x > 0, "N must be bigger than 0" -assert expand_y > 0, "N must be bigger than 0" -assert expand_z > 0, "N must be bigger than 0" + out = root + for direction, number in enumerate((expand_x, expand_y, expand_z)): + if number == 1: + continue + out += "_{}{}".format(number, 'xyz'[direction]) + if expand_x * expand_y * expand_z == 1: + if spgr == "P1": + out += "_P1" + else: + out += "_new" + out += ext -out = root -for direction, number in enumerate((expand_x, expand_y, expand_z)): - if number == 1: - continue - out += "_{}{}".format(number, 'xyz'[direction]) -if expand_x * expand_y * expand_z == 1: - if spgr == "P1": - out += "_P1" - else: - out += "_new" -out += ext + cell = s.unit_cell().parameters() -cell = s.unit_cell().parameters() + new_cell = (cell[0] * expand_x, cell[1] * expand_y, + cell[2] * expand_z, cell[3], cell[4], cell[5]) -new_cell = (cell[0] * expand_x, cell[1] * expand_y, - cell[2] * expand_z, cell[3], cell[4], cell[5]) + print("old cell:") + print(cell) + print() + print("new cell:") + print(new_cell) + print() -print("old cell:") -print(cell) -print() -print("new cell:") -print(new_cell) -print() + def expand_cell(scatterers, direction, number): + for atom in scatterers: + print(atom.label, number) + site = list(atom.site) -def expand_cell(scatterers, direction, number): - for atom in scatterers: - print(atom.label, number) - site = list(atom.site) + coord = site[direction] - coord = site[direction] + for n in range(number): + n = float(n) + new = (coord / number) + (n / number) + site[direction] = new - for n in range(number): - n = float(n) - new = (coord / number) + (n / number) - site[direction] = new + label = atom.label+chr(97+int(n)) # 97 => a + yield xray.scatterer(label=label, site=site, u=atom.u_iso, occupancy=atom.occupancy) - label = atom.label+chr(97+int(n)) # 97 => a - yield xray.scatterer(label=label, site=site, u=atom.u_iso, occupancy=atom.occupancy) + if options.exclude: + scatterers = excluded + print(">> Excluding these atoms:", ", ".join(options.exclude)) + print() + for atom in s.scatterers(): + if atom.element_symbol() in options.exclude: + continue + else: + scatterers.append(atom) + else: + scatterers = s.scatterers() -if options.exclude: - scatterers = excluded - print(">> Excluding these atoms:", ", ".join(options.exclude)) + print(f"Starting with {len(scatterers)} scatterers") print() - for atom in s.scatterers(): - if atom.element_symbol() in options.exclude: + + for direction, number in enumerate((expand_x, expand_y, expand_z)): + if number == 1: continue - else: - scatterers.append(atom) -else: - scatterers = s.scatterers() - -print(f"Starting with {len(scatterers)} scatterers") -print() - -for direction, number in enumerate((expand_x, expand_y, expand_z)): - if number == 1: - continue - print(" >> Expanding cell along {} by {}".format('xyz'[direction], number)) - scatterers = [ - scatterer for scatterer in expand_cell(scatterers, direction, number)] - print('New number of scatterers:', len(scatterers)) - print() + print(" >> Expanding cell along {} by {}".format('xyz'[direction], number)) + scatterers = [ + scatterer for scatterer in expand_cell(scatterers, direction, number)] + print('New number of scatterers:', len(scatterers)) + print() -print(f" >> Applying spacegroup {spgr}") -print() + print(f" >> Applying spacegroup {spgr}") + print() -sps = crystal.special_position_settings( - crystal_symmetry=crystal.symmetry( - unit_cell=new_cell, - space_group_symbol=spgr), - min_distance_sym_equiv=0.00001) + sps = crystal.special_position_settings( + crystal_symmetry=crystal.symmetry( + unit_cell=new_cell, + space_group_symbol=spgr), + min_distance_sym_equiv=0.00001) -s = xray.structure( - special_position_settings=sps, - scatterers=flex.xray_scatterer(scatterers)) + s = xray.structure( + special_position_settings=sps, + scatterers=flex.xray_scatterer(scatterers)) -if shift: - # shift = [-1*number for number in shift] - print(f">> Applying shift {shift} to all atom sites") - print() - s = s.apply_shift(shift) + if shift: + # shift = [-1*number for number in shift] + print(f">> Applying shift {shift} to all atom sites") + print() + s = s.apply_shift(shift) -if spgr != "P1": - # shift all atoms to inside unit cell, so asu can be applied - s = s.sites_mod_positive() + if spgr != "P1": + # shift all atoms to inside unit cell, so asu can be applied + s = s.sites_mod_positive() - asu = s.space_group_info().brick().as_string() - print("Asymmetric unit:") - # print box_min, "=>", box_max - print(asu) - print() - asu_x, asu_y, asu_z = asu.split(';') - def fx(x): return eval(asu_x) - def fy(y): return eval(asu_y) - def fz(z): return eval(asu_z) - - if '-' in asu: - print("Did not account for negative values in asymmetric unit. Duplicate atoms cannot be removed (use Kriber)") - print("") - print("Remove a,b,c etc from atom labels in cif, then run:") - print(" > cif2strudat", out) - print(" > kriber") - print(" >> reacs global") - print(" >> wricif") + asu = s.space_group_info().brick().as_string() + print("Asymmetric unit:") + # print box_min, "=>", box_max + print(asu) print() - else: - scatterers = [] - for atom in s.scatterers(): - x, y, z = atom.site - - if fx(x) and fy(y) and fz(z): - scatterers.append(atom) + asu_x, asu_y, asu_z = asu.split(';') + def fx(x): return eval(asu_x) + def fy(y): return eval(asu_y) + def fz(z): return eval(asu_z) + + if '-' in asu: + print("Did not account for negative values in asymmetric unit. Duplicate atoms cannot be removed (use Kriber)") + print("") + print("Remove a,b,c etc from atom labels in cif, then run:") + print(" > cif2strudat", out) + print(" > kriber") + print(" >> reacs global") + print(" >> wricif") + print() + else: + scatterers = [] + for atom in s.scatterers(): + x, y, z = atom.site - sps = crystal.special_position_settings( - crystal_symmetry=crystal.symmetry( - unit_cell=new_cell, - space_group_symbol=spgr), - min_distance_sym_equiv=0.00001) + if fx(x) and fy(y) and fz(z): + scatterers.append(atom) - s = xray.structure( - special_position_settings=sps, - scatterers=flex.xray_scatterer(scatterers)) + sps = crystal.special_position_settings( + crystal_symmetry=crystal.symmetry( + unit_cell=new_cell, + space_group_symbol=spgr), + min_distance_sym_equiv=0.00001) - print(f" >> Removing duplicate atoms, reduced number to {s.scatterers().size()} atoms") - print() + s = xray.structure( + special_position_settings=sps, + scatterers=flex.xray_scatterer(scatterers)) -s.as_cif_simple(out=open(out, 'w')) -print(f" >> Wrote file {out}") -print() + print(f" >> Removing duplicate atoms, reduced number to {s.scatterers().size()} atoms") + print() -if (not shift) and (spgr == "P1"): - print("---") - print("To find the right symmetry of the expanded unit cell:") + s.as_cif_simple(out=open(out, 'w')) + print(f" >> Wrote file {out}") print() - print("Run Platon, and then the Addsym routine") - print("Select NoSubCell in sidebar, then run ADDSYMExact") - print("Note the space group, and Origin shift") - print() - print("Rerun expandcell with --shift X Y Z --spgr SPGR") -sys.exit() + if (not shift) and (spgr == "P1"): + print("---") + print("To find the right symmetry of the expanded unit cell:") + print() + print("Run Platon, and then the Addsym routine") + print("Select NoSubCell in sidebar, then run ADDSYMExact") + print("Note the space group, and Origin shift") + print() + print("Rerun expandcell with --shift X Y Z --spgr SPGR")