Source code for pytc.jastrow.rexp

from pytc import jastrow
import jax
import jax.numpy as jnp
from flax import struct

[docs] def _safe_norm_np(x, epsilon): # Match NumPy behavior: r + eps (not sqrt(r^2 + eps^2)) # This ensures JAX and NumPy implementations give identical results return jnp.sqrt(jnp.sum(x*x, axis=-1)) + epsilon
@struct.dataclass class REXP(jastrow.Jastrow): """Exponential Jastrow factor: u(r) = 0.5 * r * exp(-alpha * r).""" epsilon: float = struct.field(pytree_node=False, default=1e-8) name: str = struct.field(pytree_node=False, default=None) def _compute(self, r1, r2, params): r12 = r1-r2 # Use custom norm to match NumPy behavior r12_norm = _safe_norm_np(r12, jnp.array(self.epsilon)) return 0.5*jnp.exp(-params['alpha'] * r12_norm) * r12_norm def __call__(self, r1, r2, params): return super().__call__(r1, r2, params) def init_params(self, **kwargs): alpha = kwargs.get('alpha', 0.5) return {'alpha': jnp.array([alpha])} def grad_r_batch(self, r1_batch, r2_batch, params): """Compute gradients for a batch of r1 and r2 points analytically. Args: r1_batch: (batch_size_out, 3) r2_batch: (batch_size_in, 3) params: Jastrow parameters Returns: Gradients of shape (batch_size_out, batch_size_in, 3) """ # r1_batch: (N_out, 3) # r2_batch: (N_in, 3) # diff: (N_out, N_in, 3) diff = r1_batch[:, None, :] - r2_batch[None, :, :] # dist: (N_out, N_in) dist = _safe_norm_np(diff, jnp.array(self.epsilon)) alpha = params['alpha'][0] # u = 0.5 * r * exp(-alpha * r) # grad = 0.5 * exp(-alpha * r) * (1 - alpha * r) * (diff / r) prefactor = 0.5 * jnp.exp(-alpha * dist) * (1 - alpha * dist) # Avoid division by zero (handled by safe norm, but explicit safety for direction) # safe_dist = dist + epsilon (already done in _safe_norm_np if we used it directly, # but _safe_norm_np returns r+eps) # diff / dist: (N_out, N_in, 3) direction = diff / dist[..., None] return prefactor[..., None] * direction