xnn.common.models.les.LatentEwald#
- class xnn.common.models.les.LatentEwald(model, n_channels=4, hidden=None, q_bias=False, q_add_linear=True, dl=2.0, sigma=1.0, exponent=1, remove_self_interaction=False, constrain_charge=False, charge_channel=0, charge_weights='uniform', charge_solve=False, hardness='element', hardness_init=10.0, fragments=False, bond_factor=1.2, ion_charges=None, method='kspace', pme_order=8, pme_oversample=2.0, dipole_origin='com', dielectric=1.0, learn_dielectric=False)[source]#
Bases:
InteratomicPotentialWrap any xnn model with a Latent-Ewald long-range energy (CACE-LR).
The wrapped model must expose invariant per-atom features through the
"node_features"key of its output dict and anode_feature_dimattribute – every built-in xnn model does. A bias-free MLP plus a parallel bias-free linear layer (the head used by the referencecace-lr-fitscripts) maps the features to the hidden variableq(paper eq 2), andEwaldSummationturnsqinto the long-range energy added to the model’s short-range prediction.Enable from a config with
model.extra["long_range"], e.g.:extra: {..., long_range: {n_channels: 4, sigma: 1.0, dl: 2.0}}
- Parameters:
model (InteratomicPotential) – The short-range model to wrap.
n_channels (int, optional) – Dimension of the hidden variable
q, by default 4 (the paper’s bulk-water/NaCl setting; the reference charged-dimer script uses 1).hidden (list of int, optional) – Hidden widths of the
qMLP, by default[24, 12](upstream).q_bias (bool, optional) – Use a bias in the
qMLP, by defaultFalse(the water script’s head). The reference charged-dimer script usesTrue– the bias lets the latent charge carry a per-structure offset, which matters for net-charged systems like ionic dimers.q_add_linear (bool, optional) – Add a parallel bias-free linear layer to the
qhead, by defaultTrue(the water script). The charged-dimer script usesFalse(MLP only).constrain_charge (bool, optional) – Pin each structure’s latent charges to its net charge after the q head: the channel
charge_channelsums tototal_charge * LATENT_CHARGE_PER_E(the batch’stotal_charge, neutral when absent) and every other channel to zero, by a per-structure shiftq_i <- q_i - w_i (sum q - Q') / sum w(the correction of PhysNet). The sum is then exact for any system size, where a bias in the q head (q_bias) only learns an offset per atom, and in the molecular path the monopole energy of charged structures follows. Off by default (the reference behavior). Charged training structures must carry theirtotal_chargelabel, or they are forced neutral.charge_channel (int, optional) – The channel that carries the physical net charge, by default 0.
charge_weights (str, optional) –
"uniform"(default): the same shift for every atom;"learned":w_i = softplus(linear(features_i)), a learned per-atom capacity for the residual.charge_solve (bool, optional) – Global charge solve for channel
charge_channel(charge_solve): the head’s output of that channel is an electronegativitychi_iand the charges minimisechi.q + 1/2 sum J q^2 + E_lr(q)withsum q = total_charge(in latent units), so every charge responds to every other one through the Ewald kernel. Addschi.q + 1/2 J q^2to the energy (E_lris the usual one). Off by default. With the coupling it contains,constrain_chargeis its coupling-free limit.hardness (str, optional) – Where the hardness
J_i > 0of the charge solve comes from:"element"(default), one learned value per element, or"features",softplus(linear(features_i)).hardness_init (float, optional) – Initial hardness in eV per e^2 (converted to latent units), by default 10.0, about the atomic values of charge equilibration.
fragments (bool, optional) – One constraint row per fragment instead of one per structure, so no charge flows between separate molecules (plain charge equilibration is metallic at long range). Fragments are the covalently connected components (
bonded_fragments()), with the ions ofion_chargesalways on their own; each fragment’s charge comes from the structure’sfragment_chargeslabel (the charge of the fragment each atom belongs to) when present, else fromion_charges(neutral otherwise), and must add up tototal_charge. Off by default.bond_factor (float, optional) – Bond criterion: distance below
bond_factortimes the sum of the covalent radii, by default 1.2.ion_charges (dict, optional) – Formal charges by element symbol or atomic number, by default
ION_CHARGES(the alkali, alkaline-earth and halide ions).dipole_origin (str, optional) – Origin of the
"les_dipole"output:"com"(default) the center of mass,"centroid"the mean position,"origin"the coordinate origin. The choice only matters for charged structures.dielectric (float, optional) – Screening of the charge channel’s long-range energy: its Ewald energy (and, with the charge solve, its Coulomb coupling) is divided by
dielectric, by default 1 (vacuum). Set it to the solvent’s constant (78.4 for water) when the labels come from a continuum solvent model, so charges fitted to physical ones carry the screened interaction those labels contain. The other channels are unscreened.learn_dielectric (bool, optional) – Make the dielectric a trainable parameter (its logarithm, so it stays positive), starting from
dielectric. Off by default.dl (float) – Passed to
EwaldSummation(method: pmeruns the periodic sum on a particle mesh). Note thatdlacts on periodic structures only andexponent = 6is periodic-only as well (the real-space branch that molecular structures take implements the1/rkernel), so a dataset without cells trains neither.sigma (float) – Passed to
EwaldSummation(method: pmeruns the periodic sum on a particle mesh). Note thatdlacts on periodic structures only andexponent = 6is periodic-only as well (the real-space branch that molecular structures take implements the1/rkernel), so a dataset without cells trains neither.exponent (int) – Passed to
EwaldSummation(method: pmeruns the periodic sum on a particle mesh). Note thatdlacts on periodic structures only andexponent = 6is periodic-only as well (the real-space branch that molecular structures take implements the1/rkernel), so a dataset without cells trains neither.remove_self_interaction (bool) – Passed to
EwaldSummation(method: pmeruns the periodic sum on a particle mesh). Note thatdlacts on periodic structures only andexponent = 6is periodic-only as well (the real-space branch that molecular structures take implements the1/rkernel), so a dataset without cells trains neither.method (str) – Passed to
EwaldSummation(method: pmeruns the periodic sum on a particle mesh). Note thatdlacts on periodic structures only andexponent = 6is periodic-only as well (the real-space branch that molecular structures take implements the1/rkernel), so a dataset without cells trains neither.pme_order (int) – Passed to
EwaldSummation(method: pmeruns the periodic sum on a particle mesh). Note thatdlacts on periodic structures only andexponent = 6is periodic-only as well (the real-space branch that molecular structures take implements the1/rkernel), so a dataset without cells trains neither.pme_oversample (float) – Passed to
EwaldSummation(method: pmeruns the periodic sum on a particle mesh). Note thatdlacts on periodic structures only andexponent = 6is periodic-only as well (the real-space branch that molecular structures take implements the1/rkernel), so a dataset without cells trains neither.
- Variables:
model (InteratomicPotential) – The wrapped short-range model.
q_net (torch.nn.Module) – The latent-charge MLP.
q_linear (torch.nn.Module or None) – The optional parallel linear layer;
q = q_net(B) [+ q_linear(B)].ewald (EwaldSummation) – The long-range energy module.
cutoff (float) – The wrapped model’s neighbor-list cutoff (proxied).
Notes
forwardreturns the combined"energy"; the long-range energy is spread uniformly over the atoms of each structure in"node_energy"so it still sums to the total. The additional keys"energy_sr","energy_lr", and"latent_charges"expose the decomposition."les_charges"(N,)is the channelcharge_channelin e (after the constraint or the charge solve) and"les_dipole"(B, 3)its dipole momentsum_i Q_i (r_i - o)in e Angstrom about thedipole_origin, for the molecular structures (zero for periodic ones, whose dipole is undefined). The loss termsles_charge_weightandles_dipole_weightfit them tochargesanddipolelabels; the keys are distinct from the"charges"/"dipole"outputs of models with charges of their own. With several channels only that channel is exported. Both report the charges before the dielectric screening, which acts on the energy only.- property dielectric: Tensor#
The current dielectric constant of the charge channel (a scalar tensor).
- screened(q)[source]#
qwith the charge channel divided bysqrt(dielectric), so the Ewald energy of that channel is divided by the dielectric.
- set_use_fast(use_fast)[source]#
Choose the implementation of the reciprocal sum.
- Parameters:
use_fast (bool or str) –
"auto"(default): the factorized reciprocal sum (EwaldSummation.reciprocal_fast()) on a CUDA device for the periodic structures of at leastAUTO_POLICYatoms (3000);True: wherever it runs;False: always the reference. The wrapped model’s own fast paths are set byset_use_fast(), which reaches both.- Returns:
self.- Return type:
- forward(data)[source]#
Short-range prediction plus the latent-Ewald long-range energy.
- Parameters:
data (AtomicGraph) – The batched atomic graph.
- Returns:
The wrapped model’s outputs with
"energy"and"node_energy"including the long-range term, plus"energy_sr"(B,),"energy_lr"(B,),"latent_charges"(N, n_channels),"les_charges"(N,)and"les_dipole"(B, 3).- Return type:
dict of str to torch.Tensor
- dipole(charges, pos, data, cell)[source]#
Dipole moment
sum_i Q_i (r_i - o)of every structure,(B, 3).- Parameters:
charges (Tensor) – Per-atom charges
(N,)in e.pos (Tensor) – Positions
(N, 3)in the charges’ dtype.data (AtomicGraph) – The batch (structure index, atomic numbers, periodic flags).
cell (Tensor or None) – The cells
(B, 3, 3), orNonefor a molecular batch.
- Returns:
The dipole moments in e Angstrom about the
dipole_origin, zero for periodic structures.- Return type:
Tensor
- hardness_of(features, atomic_numbers)[source]#
The hardness
J_i > 0of every atom,(N,), in latent units.
- solve_charges(chi, q, features, data, pos, cell)[source]#
Replace channel
charge_channelofqby the solved charges.One augmented solve per structure (
solve_charges()with the Coulomb matrix of its own kernel: the direct sum for a cluster, the reciprocal sum for a cell), with one constraint row per structure or, withfragments, per fragment.- Returns:
The charges
(N, n_channels), the per-atom energychi_i q_i + 1/2 J_i q_i^2(N,), the chemical potentials (one per constraint row), the hardness(N,)and the fragment index of every atom(N,)(Nonewithout fragments).- Return type:
(Tensor, Tensor, Tensor, Tensor, Tensor or None)
- Parameters:
- constrain(q, features, batch, num_graphs, total_charge)[source]#
Shift the latent charges so each structure sums to its target.
- Parameters:
q (Tensor) – Latent charges,
(N, n_channels).features (Tensor) – Per-atom features,
(N, F)(the learned weights read them).batch (Tensor) – Structure index of every atom,
(N,).num_graphs (int) – Number of structures.
total_charge (Tensor or None) – Net charge of every structure in e,
(B,);Noneis neutral.
- Returns:
qwith channelcharge_channelsumming tototal_charge * LATENT_CHARGE_PER_Eand the others to zero.- Return type:
Tensor