Placement functions#
pasted._placement#
Atom-placement algorithms (gas / chain / shell) and post-placement repulsion relaxation. No file I/O; no metrics.
- pasted._placement.add_hydrogen(atoms: list[str], rng: Random) list[str][source]#
Append hydrogen atoms when H is in the pool but absent from atoms.
The number of H atoms added is:
n_H = 1 + round(uniform(0, 1) × n_current × 1.2)The original list is not modified; a new list is returned.
- pasted._placement.place_chain(atoms: list[str], bond_lo: float, bond_hi: float, branch_prob: float, persist: float, rng: Random, chain_bias: float = 0.0) tuple[list[str], list[tuple[float, float, float]]][source]#
Random-walk atom-chain growth with branching and directional persistence.
- Parameters:
atoms – Element symbols (order is preserved).
bond_lo – Bond-length range (Å).
bond_hi – Bond-length range (Å).
branch_prob – Probability that an atom becomes a new branch tip rather than replacing the existing tip (0 = linear, 1 = fully branched tree).
persist –
Directional persistence ∈ [0, 1]. A new step direction d is accepted only when
dot(d, prev_dir) ≥ persist − 1.0.0 → fully random (may self-tangle)
0.5 → rear 120° cone excluded (default)
1.0 → front hemisphere only, nearly straight chain
rng – Seeded random-number generator.
chain_bias –
Global-axis drift strength ∈ [0, 1] (default: 0.0).
After the first bond is placed its direction becomes the bias axis. Every subsequent step direction is blended toward that axis before normalisation:
d_biased = d + axis * chain_bias d_final = d_biased / ||d_biased||
0.0 → no bias; behaviour identical to previous versions
- 0.3 → moderate elongation; shape_aniso ≥ 0.5 rate rises from
~40% to ~70% for n = 20 atoms
1.0 → strong elongation; nearly rod-like for small n
chain_biasandpersistare complementary:persistcontrols local turn angles between consecutive bonds;chain_biasimposes a global preferred axis regardless of chain length.
- Returns:
Always
len(atoms)positions.- Return type:
(atoms, positions)
- pasted._placement.place_gas(atoms: list[str], region: str, rng: Random) tuple[list[str], list[tuple[float, float, float]]][source]#
Place all atoms uniformly at random inside region.
No clash checking is performed — call
relax_positions()afterwards.- Parameters:
atoms – Element symbols.
region –
"sphere:R"|"box:L"|"box:LX,LY,LZ"rng – Seeded random-number generator.
- Returns:
Always
len(atoms)positions.- Return type:
(atoms, positions)
- Raises:
ValueError – On unrecognised region spec.
- pasted._placement.place_maxent(atoms: list[str], region: str, cov_scale: float, rng: Random, maxent_steps: int = 300, maxent_lr: float = 0.05, maxent_cutoff_scale: float = 2.5, trust_radius: float = 0.5, convergence_tol: float = 0.001, seed: int | None = None) tuple[list[str], list[tuple[float, float, float]]][source]#
Place atoms to maximise angular entropy subject to distance constraints.
Implements constrained maximum-entropy placement: atoms are initialised inside region at random, then iteratively repositioned so that each atom’s neighbourhood directions become as uniformly distributed over the sphere as possible — the solution to
max S = −∫ p(Ω) ln p(Ω) dΩ s.t. d_ij ≥ cov_scale × (r_i + r_j) ∀ i,j
The angular repulsion potential
U = Σ_{i} Σ_{j,k ∈ N(i), j≠k} 1 / (1 − cos θ_{jk} + ε)
is minimised by L-BFGS (m=7, Armijo backtracking) when the C++ extension
_maxent_core.place_maxent_cppis available (HAS_MAXENT_LOOP), or by steepest descent otherwise. A per-atom trust radius caps the maximum displacement per step, replacing the fixedmaxent_lrunit-norm clip of the steepest-descent fallback.After every gradient step the mandatory distance-constraint relaxation is applied (L-BFGS penalty, identical to
_relax_core).Stability measures applied per step:
Per-atom trust-radius clamp: the step is uniformly rescaled so no atom moves more than trust_radius Å, preventing L-BFGS overshooting.
Soft restoring force: atoms that drift outside the initial region radius are gently pulled back toward the centre of mass.
Centre-of-mass pinning: the centre of mass is re-centred to the origin after each step so the whole structure does not drift.
- Parameters:
atoms – Element symbols.
region – Initial placement region:
"sphere:R"|"box:L"|"box:LX,LY,LZ".cov_scale – Pyykkö distance scale factor.
rng – Seeded random-number generator.
maxent_steps – Gradient-descent / L-BFGS outer iterations (default: 300).
maxent_lr – Learning rate used only by the Python steepest-descent fallback (default: 0.05). Ignored when the C++ loop is active.
maxent_cutoff_scale – Neighbour cutoff = this factor × median covalent sum (default: 2.5). Larger values include more neighbours in the angular calculation.
trust_radius – Per-atom maximum displacement per step (Å, default: 0.5). Used by the C++ L-BFGS loop; steepest-descent fallback uses unit-norm clip scaled by maxent_lr instead.
convergence_tol – Early-termination threshold: the loop stops when the RMS gradient per atom falls below this value (Å⁻¹·a.u., default: 1e-3). Set to
0to disable early termination and always run maxent_steps iterations. Ignored by the Python steepest-descent fallback.seed – Optional integer seed forwarded to the steric-clash relaxation for the coincident-atom edge case.
None→ non-deterministic (default).
- Returns:
Always
len(atoms)positions.- Return type:
(atoms, positions)
- pasted._placement.place_shell(atoms: list[str], center_sym: str, coord_lo: int, coord_hi: int, shell_lo: float, shell_hi: float, tail_lo: float, tail_hi: float, rng: Random) tuple[list[str], list[tuple[float, float, float]]][source]#
Center atom at origin + coordination shell + tail atoms.
No clash checking is performed — call
relax_positions()afterwards.- Parameters:
atoms – Element symbols; must contain at least one occurrence of center_sym.
center_sym – Symbol of the atom placed at the origin.
coord_lo – Coordination-number range (number of shell atoms).
coord_hi – Coordination-number range (number of shell atoms).
shell_lo – Shell radius range (Å).
shell_hi – Shell radius range (Å).
tail_lo – Tail bond-length range (Å).
tail_hi – Tail bond-length range (Å).
rng – Seeded random-number generator.
- Returns:
Center atom is first; always
len(atoms)positions.- Return type:
(ordered_atoms, positions)
- pasted._placement.relax_positions(atoms: list[str], positions: list[tuple[float, float, float]], cov_scale: float, max_cycles: int = 500, *, seed: int | None = None) tuple[list[tuple[float, float, float]], bool][source]#
Resolve interatomic distance violations by L-BFGS penalty minimization.
For every pair (i, j) whose distance falls below
cov_scale × (r_i + r_j)(Pyykkö single-bond covalent radii), a harmonic penalty energy is accumulated and its gradient used to drive atoms apart. The C++ path minimizesE = Σ_{i<j} ½ · max(0, threshold − d_ij)²via L-BFGS; convergence is declared when E < 1 × 10⁻⁶.When the compiled C++ extension (
pasted._ext._relax_core) is available the optimization runs in native code; otherwise the pure-Python/NumPy Gauss-Seidel fallback is used transparently.- Parameters:
atoms – Element symbols, one per atom.
positions – Initial Cartesian coordinates (Å).
cov_scale – Scale factor applied to the sum of covalent radii.
max_cycles – Maximum number of L-BFGS iterations (C++ path) or Gauss-Seidel sweeps (Python fallback). The C++ solver exits early when E < 1e-6, so the limit is rarely reached for typical structures.
seed – Optional integer seed for the one-time pre-perturbation jitter (C++ path) or the coincident-atom RNG (Python fallback).
None→ non-deterministic. Pass the generator’s master seed here for full reproducibility.
- Returns:
converged is
Falseonly when max_cycles was reached with violations still present; the structure is still returned and usable.- Return type:
(relaxed_positions, converged)