Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A new function to contract the coordinates after the random generation to ensure that the atoms are not to far apart. #53

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
2814737
Initial commit contract coordinates
jonathan-schoeps Sep 13, 2024
8f476a3
Merge branch 'main' into dev/contract_coordinates
jonathan-schoeps Sep 18, 2024
783a38f
new function to contract the coordinates before the xtb scf
jonathan-schoeps Sep 19, 2024
a369163
Merge branch 'main' into dev/contract_coordinates
jonathan-schoeps Sep 23, 2024
f35e604
The coordinates are now drawn towards the origin to improve convergence.
jonathan-schoeps Sep 23, 2024
47fa140
The coordinates are now drawn towards the origin to improve convergence.
jonathan-schoeps Sep 26, 2024
49c29fa
Merge branch 'main' into dev/contract_coordinates
jonathan-schoeps Sep 26, 2024
d38c896
suggest changes to dev/contract_coordinates to make code more consist…
marcelmbn Sep 27, 2024
4300fff
Merge pull request #1 from marcelmbn/dev/revised_contract_coordinates
jonathan-schoeps Sep 27, 2024
1eb5770
Merge branch 'main' into dev/contract_coordinates
jonathan-schoeps Sep 27, 2024
db3aa1b
Merge remote-tracking branch 'origin/dev/contract_coordinates' into d…
jonathan-schoeps Sep 27, 2024
9e48a3b
merged dev/dist_cov_radii and the changes to the function contract_co…
jonathan-schoeps Oct 4, 2024
4e950b2
bug fix were the boolean was not correctly passed on
jonathan-schoeps Oct 4, 2024
f373630
Merge branch 'main' into dev/contract_coordinates
jonathan-schoeps Oct 7, 2024
4e0937a
Changes which were done twice are removed
jonathan-schoeps Oct 7, 2024
e1476c6
Changed a thing left over from teh debugging
jonathan-schoeps Oct 7, 2024
08e9b76
Changed a Todo
jonathan-schoeps Oct 7, 2024
47fa366
suggested changes within the PR
jonathan-schoeps Oct 8, 2024
a5418a7
Update mindlessgen.toml
jonathan-schoeps Oct 8, 2024
e86e9c6
Update src/mindlessgen/prog/config.py
jonathan-schoeps Oct 8, 2024
5cfbee5
mindlessgen.toml now consistent with the default
jonathan-schoeps Oct 8, 2024
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added
- Support for the novel "g-xTB" method (working title: GP3-xTB)
- A function which contracts the coordinates after the initial generation.
- A function which is able to printout the xyz coordinates to the terminal similar to the `.xyz` layout.

### Breaking Changes
- Removal of the `dist_threshold` flag and in the `-toml` file.
Expand Down
6 changes: 4 additions & 2 deletions mindlessgen.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ init_scaling = 3.0
# > Increase in the coordinate scaling factor per trial after check_distance was not met. Options: <float>
increase_scaling_factor = 1.3
# > Scaling factor for the employed van der Waals radii. Options: <float>
scale_vdw_radii = 1.3333
scale_vdw_radii = 1.25
# > Scaling factor for the minimal bondlength based on the sum of the van der Waals radii. Options: <float>
scale_minimal_bondlength = 0.75
scale_minimal_bondlength = 0.8
# > Contract the coordinates after the initial generation. Leads to more cluster-like and less extended structures. Options: <bool>
contract_coords = false
# > Atom types and their minimum and maximum occurrences. Format: "<element>:<min_count>-<max_count>"
# > Elements that are not specified are only added by random selection.
# > A star sign (*) can be used as a wildcard for integer value.
Expand Down
19 changes: 13 additions & 6 deletions src/mindlessgen/cli/cli_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,12 @@ def cli_parser(argv: Sequence[str] | None = None) -> dict:
required=False,
help="List of forbidden elements.",
)
parser.add_argument(
"--contract_coords",
type=bool,
required=False,
help="Contract the coordinates of the molecule after the coordinats generation.",
)

### Refinement arguments ###
parser.add_argument(
Expand Down Expand Up @@ -195,19 +201,19 @@ def cli_parser(argv: Sequence[str] | None = None) -> dict:
required=False,
help="Path to the xTB binary.",
)
parser.add_argument(
jonathan-schoeps marked this conversation as resolved.
Show resolved Hide resolved
"--xtb-level",
type=int,
required=False,
help="Level of theory to use in xTB.",
)
parser.add_argument(
"--postprocess-debug",
action="store_true",
default=None,
required=False,
help="Print debug information during postprocessing.",
)
parser.add_argument(
"--xtb-level",
type=int,
required=False,
help="Level of theory to use in xTB.",
)

### ORCA specific arguments ###
parser.add_argument(
Expand Down Expand Up @@ -273,6 +279,7 @@ def cli_parser(argv: Sequence[str] | None = None) -> dict:
"forbidden_elements": args_dict["forbidden_elements"],
"scale_vdw_radii": args_dict["scale_vdw_radii"],
"scale_minimal_bondlength": args_dict["scale_minimal_bondlength"],
"contract_coords": args_dict["contract_coords"],
}
# XTB specific arguments
rev_args_dict["xtb"] = {"xtb_path": args_dict["xtb_path"]}
Expand Down
39 changes: 39 additions & 0 deletions src/mindlessgen/molecules/generate_molecule.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ def generate_random_molecule(
verbosity=verbosity,
scale_bondlength=config_generate.scale_minimal_bondlength,
)
if config_generate.contract_coords:
mol.xyz = contract_coordinates(
xyz=mol.xyz,
ati=mol.ati,
scale_minimal_distance=config_generate.scale_minimal_bondlength,
)
mol.charge, mol.uhf = set_random_charge(mol.ati, verbosity)
mol.set_name_from_formula()

Expand Down Expand Up @@ -371,6 +377,39 @@ def generate_random_coordinates(at: np.ndarray) -> tuple[np.ndarray, np.ndarray]
return xyz, ati


def contract_coordinates(
xyz: np.ndarray, ati: np.ndarray, scale_minimal_distance: float
) -> np.ndarray:
"""
Pull the atoms towards the origin.
"""
# Initialize the old coordinates as an array of zeros
xyz_old: np.ndarray = np.zeros_like(xyz)
cycle = 0
# Break if the coordinates do not change
while not np.array_equal(xyz_old, xyz):
cycle += 1
if cycle > 2500:
raise RuntimeError(
"Could not contract the coordinates in a reasonable amount of cycles."
)
xyz_old = xyz.copy()
# Go through the atoms dimension of the xyz array in a reversed order
# Justification: First atoms are most likely hydrogen atoms, which should be moved last
for i in range(len(xyz) - 1, -1, -1):
atom_xyz = xyz[i]
atom_xyz_norm = np.linalg.norm(atom_xyz)
normalized_atom_xyz = atom_xyz / atom_xyz_norm
# Shift the atom only if it is closer to the origin after the shift
if atom_xyz_norm > 0.1:
# Pull the atom towards the origin
xyz[i] -= normalized_atom_xyz * 0.2
# When the check_distances function returns False, reset the atom coordinates
if not check_distances(xyz, ati, scale_minimal_distance):
xyz[i] = xyz_old[i]
return xyz


def check_distances(xyz: np.ndarray, ati: np.ndarray, scale_bondlength: float) -> bool:
"""
Check if the distances between atoms are larger than a threshold.
Expand Down
44 changes: 22 additions & 22 deletions src/mindlessgen/molecules/molecule.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,12 +459,29 @@ def atlist(self, value: np.ndarray):

self._atlist = value

def print_xyz(self):
def get_xyz_str(self) -> str:
"""
Print the XYZ coordinates of the molecule.
Obtain a string with the full XYZ file information of the molecule.
"""
# TODO: Implement a better way to print the coordinates
print(self._xyz)
xyz_str = f"{self.num_atoms}\n"
try:
commentline = f"Total charge: {self.charge} ; "
except ValueError:
commentline = ""
try:
commentline = commentline + f"Unpaired electrons: {self.uhf} ; "
except ValueError:
pass
commentline = commentline + f"Generated by mindlessgen-v{__version__}\n"
xyz_str += commentline
for i in range(self.num_atoms):
xyz_str += (
f"{PSE[self.ati[i]+1]:<5} "
+ f"{self.xyz[i, 0]:>12.7f} "
+ f"{self.xyz[i, 1]:>12.7f} "
+ f"{self.xyz[i, 2]:>12.7f}\n"
)
return xyz_str

def write_xyz_to_file(self, filename: str | Path | None = None):
"""
Expand Down Expand Up @@ -496,24 +513,7 @@ def write_xyz_to_file(self, filename: str | Path | None = None):
filename = Path("mlm_" + self.name + ".xyz").resolve()

with open(filename, "w", encoding="utf8") as f:
f.write(f"{self.num_atoms}\n")
try:
commentline = f"Total charge: {self.charge} ; "
except ValueError:
commentline = ""
try:
commentline = commentline + f"Unpaired electrons: {self.uhf} ; "
except ValueError:
pass
commentline = commentline + f"Generated by mindlessgen-v{__version__}\n"
f.write(commentline)
for i in range(self.num_atoms):
f.write(
f"{PSE[self.ati[i]+1]:<5} "
+ f"{self.xyz[i, 0]:>12.7f} "
+ f"{self.xyz[i, 1]:>12.7f} "
+ f"{self.xyz[i, 2]:>12.7f}\n"
)
f.write(self.get_xyz_str())
# if the charge is set, write it to a '.CHRG' file
if self._charge is not None:
with open(filename.with_suffix(".CHRG"), "w", encoding="utf8") as f:
Expand Down
21 changes: 19 additions & 2 deletions src/mindlessgen/prog/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,9 @@ def __init__(self: GenerateConfig) -> None:
self._increase_scaling_factor: float = 1.3
self._element_composition: dict[int, tuple[int | None, int | None]] = {}
self._forbidden_elements: list[int] | None = None
self._scale_vdw_radii: float = 4.0 / 3.0
self._scale_minimal_bondlength: float = 0.75
self._scale_vdw_radii: float = 1.25
self._scale_minimal_bondlength: float = 0.8
jonathan-schoeps marked this conversation as resolved.
Show resolved Hide resolved
self._contract_coords: bool = False

def get_identifier(self) -> str:
return "generate"
Expand Down Expand Up @@ -383,6 +384,22 @@ def scale_minimal_bondlength(self, scale_minimal_bondlength: float):
raise ValueError("Scale minimal bond length should be greater than 0.")
self._scale_minimal_bondlength = scale_minimal_bondlength

@property
def contract_coords(self):
"""
Get the contract_coords flag.
"""
return self._contract_coords

@contract_coords.setter
def contract_coords(self, contract_coords: bool):
"""
Set the contract_coords flag.
"""
if not isinstance(contract_coords, bool):
raise TypeError("Contract coords should be a boolean.")
self._contract_coords = contract_coords


class RefineConfig(BaseConfig):
"""
Expand Down