Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions autoadsorbate/Smile.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def conformers_from_smile(
conf = mol.GetConformer(conf_id)
positions = conf.GetPositions()
atoms = Atoms(symbols, positions=positions)
atoms.info["smiles"] = smiles
conformer_trj.append(atoms)

print(f'User requested {to_initialize = } conformers.')
Expand Down
47 changes: 29 additions & 18 deletions autoadsorbate/Surf.py
Original file line number Diff line number Diff line change
Expand Up @@ -1608,7 +1608,7 @@ def drop_fragment_to_z_zero(atoms: Atoms) -> None:
atoms.positions -= np.array([0, 0, min_z])


def conformer_to_site(atoms, site, conformer, mode="optimize", overlap_thr=0):
def conformer_to_site(atoms, site, conformer, mode="optimize", overlap_thr=0, use_swirl=True):
"""
Aligns and attaches a conformer to a specified site on a slab of atoms, optimizing the orientation to minimize overlap.

Expand All @@ -1618,6 +1618,9 @@ def conformer_to_site(atoms, site, conformer, mode="optimize", overlap_thr=0):
conformer (object): An object containing the conformer to be attached.
mode (str): The mode of operation. Currently, only 'optimize' is supported. Default is 'optimize'.
overlap_thr (float): The overlap threshold. Default is 0.0.
use_swirl (bool): Whether to optimize marked fragments with swirl_fragment
for Cl-marked monodentates and swing_fragment for S1S-marked
bidentates. Default is True.

Returns:
object: The combined atoms object with the conformer attached and optimized.
Expand Down Expand Up @@ -1660,25 +1663,33 @@ def conformer_to_site(atoms, site, conformer, mode="optimize", overlap_thr=0):
# out_atoms.info['site_info'] = site

if conformer.info["smiles"][:3] == "S1S":
out_atoms = swing_fragment(
atoms=out_atoms,
fragment_index=n_f,
site=site,
resolution=10,
mode=mode,
span_angle=50,
overlap_thr=overlap_thr,
)
if use_swirl:
out_atoms = swing_fragment(
atoms=out_atoms,
fragment_index=n_f,
site=site,
resolution=10,
mode=mode,
span_angle=50,
overlap_thr=overlap_thr,
)
else:
out_atoms.info["mdf"] = minimum_fragment_distance(out_atoms)
out_atoms = [out_atoms]

if conformer.info["smiles"][:2] == "Cl":
out_atoms = swirl_fragment(
atoms=out_atoms,
fragment_index=n_f,
site=site,
resolution=10,
mode="optimize",
overlap_thr=0.0,
)
if use_swirl:
out_atoms = swirl_fragment(
atoms=out_atoms,
fragment_index=n_f,
site=site,
resolution=10,
mode="optimize",
overlap_thr=0.0,
)
else:
out_atoms.info["mdf"] = minimum_fragment_distance(out_atoms)
out_atoms = [out_atoms]

return out_atoms

Expand Down
20 changes: 16 additions & 4 deletions autoadsorbate/autoadsorbate.py
Original file line number Diff line number Diff line change
Expand Up @@ -626,19 +626,23 @@ def get_populated_sites(
overlap_thr=1.5,
verbose=False,
parallel=None,
use_swirl=True,
):
"""
Populates the specified sites with the given fragment, optimizing the orientation to minimize overlap.

Parameters:
fragment (object): An object containing the fragment to be attached.
site_index (str or int): The index of the site to be populated. Default is 'all'.
site_index (str or int or list[int]): The index of the site to be populated. Default is 'all'.
sample_rotation (bool): Whether to sample different rotations of the fragment. Default is True.
mode (str): The mode of operation. Can be 'heuristic' or 'all'. Default is 'heuristic'.
conformers_per_site_cap (int or None): The maximum number of conformers per site. Default None mean the maximum number of conformers.
overlap_thr (float): The overlap threshold. Default is 1.5.
verbose (bool): Whether to print detailed information during execution. Default is False.
parallel (int): If value >0, parallelize the configuration on the number of CPU specified. Default None
use_swirl (bool): Whether to optimize marked fragments with swirl_fragment
for Cl-marked monodentates and swing_fragment for S1S-marked
bidentates. Default is True.

Returns:
list: A list containing the optimized atoms objects for each site.
Expand All @@ -649,6 +653,11 @@ def get_populated_sites(

all_sites = {}
site_df = self.site_df

if isinstance(site_index, int):
site_df = site_df.loc[[site_index]]
elif isinstance(site_index, list):
site_df = site_df.loc[site_index]

if mode.lower() == "all":
sites = [site_df.loc[i].to_dict() for i in site_df.index.values]
Expand Down Expand Up @@ -686,7 +695,10 @@ def get_populated_sites(
ca.rotate(a, "z")
conformers.append(ca)
else:
conformers = [c.copy() for c in fragment.conformers]
conformers = [
fragment.get_conformer(i)
for i, _ in enumerate(fragment.conformers)
]

out_trj = []

Expand All @@ -702,13 +714,13 @@ def get_populated_sites(

if parallel != None:

c_trj.extend(Parallel(n_jobs=parallel)(delayed(conformer_to_site)(self.atoms, site, conformer, mode="optimize", overlap_thr=0) for conformer in conformers))
c_trj.extend(Parallel(n_jobs=parallel)(delayed(conformer_to_site)(self.atoms, site, conformer, mode="optimize", overlap_thr=0, use_swirl=use_swirl) for conformer in conformers))
c_trj = [x[0] for x in c_trj]

else:
for conformer in conformers:
c_trj += conformer_to_site(
self.atoms, site, conformer, mode="optimize", overlap_thr=0
self.atoms, site, conformer, mode="optimize", overlap_thr=0, use_swirl=use_swirl
) # the zero is intentional

if conformers_per_site_cap == None:
Expand Down