def generate_fixed_fragment_coords(a, b, c, *others): """ TODO Document this """ ret_val = [BondLength(a, b), BondLength(a, c), BondAngle(b, a, c)] for d in others: ret_val.append(InternalCartesianX(a, b, c, d)) ret_val.append(InternalCartesianY(a, b, c, d)) ret_val.append(InternalCartesianZ(a, b, c, d)) return ret_val
def value_for_xyz(cls, xyz): def e(j, k): ev = LightVector.l_sub(xyz[k-1], xyz[j-1]); ev.normalize() return ev eab, eac, ead = e(1,2), e(1,3), e(1,4) tmp = eab.l_cross(eac).normalized() return BondLength.value_for_positions(xyz[0], xyz[3]) * tmp.dot(ead)
def value_for_xyz(cls, xyz): def e(j, k): ev = LightVector.l_sub(xyz[k - 1], xyz[j - 1]) ev.normalize() return ev return BondLength.value_for_positions(xyz[0], xyz[3]) * (e(1, 2).dot( e(1, 4)))
def value_for_xyz(cls, xyz): def e(j, k): ev = LightVector.l_sub(xyz[k - 1], xyz[j - 1]) ev.normalize() return ev eab, eac, ead = e(1, 2), e(1, 3), e(1, 4) tmp = eab.l_cross(eac).normalized() return BondLength.value_for_positions(xyz[0], xyz[3]) * tmp.dot(ead)
def __init__(self, molecule, coords_string, one_based=True, units=None): off = 1 if one_based else 0 self.molecule = molecule atoms = self.molecule.atoms coords = [] for line in coords_string.splitlines(): # ignore blank lines if len(line.strip()) == 0: continue vals = line.split() name = vals[0] nums = vals[1:] #TODO More coordinate types if name.lower() in self.STRE_NAMES: if len(nums) != 2: raise StandardError( "Invalid coordinate specification string: " + line) coord = BondLength( [atoms[int(nums[0]) - off], atoms[int(nums[1]) - off]], parent=self, index=len(coords)) coords.append(coord) elif name.lower() in self.BEND_NAMES: if len(nums) != 3: raise StandardError( "Invalid coordinate specification string: " + line) coord = BondAngle([ atoms[int(nums[0]) - off], atoms[int(nums[1]) - off], atoms[int(nums[2]) - off] ], parent=self, index=len(coords)) coords.append(coord) elif name.lower() in self.TORS_NAMES: if len(nums) != 4: raise StandardError( "Invalid coordinate specification string: " + line) coord = Torsion([ atoms[int(nums[0]) - off], atoms[int(nums[1]) - off], atoms[int(nums[2]) - off], atoms[int(nums[3]) - off] ], parent=self, index=len(coords)) coords.append(coord) else: raise StandardError( "Unknown or unimplemented internal coordinate string: " + line) self.__init__(molecule=molecule, coords=coords, units=units)
def R(i, j): # This is ugly... # TODO figure out a better way to do this mol = Molecule([Atom('H', args[i - 1]), Atom('H', args[j - 1])]) return BondLength(mol[0], mol[1])
def analytic_b_tensor_for_order(self, order): #--------------------------------------------------------------------------------# # Now check the cache cache_key = (self.__class__, order) + tuple(a.pos for a in self.atoms) cache_resp = SimpleInternalCoordinate._check_b_tensor_cache(*cache_key) if cache_resp is not None: return cache_resp #--------------------------------------------------------------------------------# B = partial(SimpleInternalCoordinate.b_tensor_element_reindexed, self) #--------------------------------------------------------------------------------# # First order is already done elsewhere... if order == 1: # We can't use the `b_vector` attribute since that vector is indexed in the parent # molecule's indexing scheme my_b = Vector( self.__class__.b_vector_for_positions( *[a.pos for a in self.atoms])) # Return now, to avoid double-caching return my_b #--------------------------------------------------------------------------------# # Second order terms if order == 2: # BondAngles are composed of 3 atoms (3 CartesianCoordinates each), and the # order is 2, so the output Tensor will be a 9x9 Tensor my_b = np.ndarray(shape=(9, ) * 2) # some precomputed values phi = self.value * self.units.to(Radians) cotphi = 1.0 / tan(phi) cscphi = 1.0 / sin(phi) #========================================# # see comments in BondLength version # First, handle the terminal atom entries for (a_idx, a), (c_idx, c) in product(zip([0, 2], self.terminal_atoms), repeat=2): # Generate the temporary coordinates if a_idx == 0: Rab = BondLength(self.atoms[0], self.atoms[1]) Rbc = BondLength(self.atoms[1], self.atoms[2]) else: # a_idx == 2 Rab = BondLength(self.atoms[2], self.atoms[1]) Rbc = BondLength(self.atoms[1], self.atoms[0]) #----------------------------------------# # Now iterate over the possible sets of cartesian coordinates for alpha, beta in product([X, Y, Z], repeat=2): a_alpha, c_beta = a_idx * 3 + alpha, c_idx * 3 + beta if a_idx == c_idx: # From equation 19 in Allen, et al. Mol. Phys. 89 (1996), 1213-1221 a_beta = c_beta other_terminal_index = 2 if a_idx == 0 else 0 my_b[a_alpha, a_beta] = ( -cotphi * B(self, a_alpha) * B(self, a_beta) - cscphi * sum( B(Rab, a_idx * 3 + sigma, a_alpha, a_beta) * B(Rbc, other_terminal_index * 3 + sigma) for sigma in [X, Y, Z])) else: # From equation 20 in Allen, et al. Mol. Phys. 89 (1996), 1213-1221 my_b[a_alpha, c_beta] = ( -cotphi * B(self, a_alpha) * B(self, c_beta) - cscphi * sum( B(Rab, a_idx * 3 + sigma, a_alpha) * B(Rbc, c_idx * 3 + sigma, c_beta) for sigma in [X, Y, Z])) # Now fill in the middle atom entries utilizing translational invariance # From equation 32 in Allen, et al. Mol. Phys. 89 (1996), 1213-1221 for alpha, beta in product([X, Y, Z], repeat=2): b_beta = 3 + beta for a_idx, a in zip([0, 2], self.terminal_atoms): a_alpha = 3 * a_idx + alpha my_b[b_beta, a_alpha] = my_b[a_alpha, b_beta] = \ -sum(my_b[a_alpha, t + beta] for t in [0, 6] # 0 and 6 are the offsets for the terminal atoms ) # Now the b_alpha, b_beta entry: my_b[3 + alpha, 3 + beta] = sum( my_b[atom1 * 3 + alpha, atom2 * 3 + beta] for atom1, atom2 in product([0, 2], repeat=2)) #--------------------------------------------------------------------------------# else: # behold, the general formula! # BondAngles are composed of 3 atoms (3 CartesianCoordinates each), # so the output will be a 9x9x...x9 (`order`-dimensional) tensor my_b = Tensor(indices=','.join('v' * order), index_range_set=self.__class__._btens_idx_range_set) #Bphi = self._btensor Rab = self.get_coord(BondLength, self.atoms[0], self.atoms[1]) Rbc = self.get_coord(BondLength, self.atoms[1], self.atoms[2]) #Brab = Rab._btensor #Brbc = Rbc._btensor #for o in xrange(1, order): # t = Bphi.for_order(o) # rab = Brab.for_order(o) # rbc = Rbc._btensor.for_order(o) # if isinstance(t, ComputableTensor): t.fill() # if isinstance(rab, ComputableTensor): rab.fill() # if isinstance(rbc, ComputableTensor): rab.fill() #Brab.for_order(order).fill() #Brbc.for_order(order).fill() #remap_set = IndexRangeSet() #DeclareIndexRange('v', 6, index_range_set=remap_set).with_subranges( # IndexRange('b', 3, 6, index_range_set=remap_set), # IndexRange('c', 0, 3, index_range_set=remap_set) #) ##Brbc = DerivativeCollection(coordinate=Rbc, einsum_index='v', index_range_set=remap_set) #ba = Vector([Brab[(0,) + (Ellipsis,)*order]]) #for o in xrange(1, order+1): # Brbc.for_order(o).index_range_set = remap_set ## some precomputed values phi = self.value * self.units.to(Radians) cotphi = 1.0 / tan(phi) cscphi = 1.0 / sin(phi) #========================================# # First take care of the terminal atoms... def f_K(k): if k % 2 == 1: if (k + 1) / 2 % 2 == 0: return 1 else: # (k+1)/2 % 2 == 1 return -1 elif k / 2 % 2 == 0: return cotphi else: # k/2 % 2 == 1 return -cotphi #----------------------------------------# a_idx, c_idx = 0, 2 for num_a_coords in xrange(0, order + 1): # outer loop over possible alphas for alphas in product([X, Y, Z], repeat=order): a_alphas = tuple(3 * a_idx + alpha for alpha in alphas[:num_a_coords]) c_alphas = tuple(3 * c_idx + alpha for alpha in alphas[num_a_coords:]) # Now we have all of the specifics for the left-hand side, so compute the # right-hand side to go with it... cum_sum = 0.0 for sigma in [X, Y, Z]: cum_sum += B(Rab, 3 * a_idx + sigma, *a_alphas) * B( Rbc, 3 * c_idx + sigma, *c_alphas) cum_sum *= -cscphi for k in range(2, order + 1): inner_sum = 0.0 for s in I_lubar(order, k, a_alphas + c_alphas): prod = 1.0 for i in range(k): prod *= B(self, *s[i]) inner_sum += prod cum_sum += f_K(k) * inner_sum # Spread over permutations for idxs in permutations(a_alphas + c_alphas): my_b[idxs] = cum_sum #========================================# # now compute the terms involving the middle atom a1_idx, a2_idx, a3_idx = 0, 1, 2 for num_a2s in xrange(1, order + 1): # Now fill in the middle atom entries utilizing translational invariance # From equation 32 in Allen, et al. Mol. Phys. 89 (1996), 1213-1221 for first_a2_position in xrange(0, order - num_a2s + 1): for alphas in product([X, Y, Z], repeat=order): a1_alphas = tuple( 3 * a1_idx + alpha for alpha in alphas[:first_a2_position]) middle_alphas = alphas[ first_a2_position:first_a2_position + num_a2s] a2_alphas = tuple(3 * a2_idx + alpha for alpha in middle_alphas) a3_alphas = tuple( 3 * a3_idx + alpha for alpha in alphas[first_a2_position + num_a2s:]) val_to_spread = 0.0 for midatoms in product([a1_idx, a3_idx], repeat=num_a2s): idxs = a1_alphas idxs += tuple(ai * 3 + middle_alphas[i] for i, ai in enumerate(midatoms)) idxs += a3_alphas val_to_spread += my_b[idxs] if num_a2s % 2 == 1: val_to_spread *= -1.0 for perm in permutations(a1_alphas + a2_alphas + a3_alphas): my_b[perm] = val_to_spread #--------------------------------------------------------------------------------# # Cache the value we got SimpleInternalCoordinate._set_b_tensor_cache_entry(my_b, *cache_key) #--------------------------------------------------------------------------------# return my_b
def value_for_xyz(cls, xyz): def e(j, k): ev = LightVector.l_sub(xyz[k-1], xyz[j-1]); ev.normalize() return ev return BondLength.value_for_positions(xyz[0], xyz[3]) * (e(1,2).dot(e(1,4)))