def get_coefficients_alg3(rh, a0, a1, a2, a3, idealize, sites_cart):
  r0 = matrix.col(sites_cart[a0.iseq])
  r1 = matrix.col(sites_cart[a1.iseq])
  r2 = matrix.col(sites_cart[a2.iseq])
  r3 = matrix.col(sites_cart[a3.iseq])
  uh0 = (rh - r0).normalize()
  u10 = (r1 - r0).normalize()
  u20 = (r2 - r0).normalize()
  u30 = (r3 - r0).normalize()
  if idealize:
    alpha0 = math.radians(a1.angle_ideal)
    alpha1 = math.radians(a2.angle_ideal)
    alpha2 = math.radians(a3.angle_ideal)
    c1, c2, c3 = math.cos(alpha0), math.cos(alpha1), math.cos(alpha2)
    omega0 = math.radians(a0.angle_ideal[0])
    omega1 = math.radians(a0.angle_ideal[1])
    omega2 = math.radians(a0.angle_ideal[2])
    w12, w23, w13 = math.cos(omega0), math.cos(omega1), math.cos(omega2)
  else:
    c1 = (uh0).dot(u10)
    c2 = (uh0).dot(u20)
    c3 = (uh0).dot(u30)
    w12 = (u10).dot(u20)
    w23 = (u20).dot(u30)
    w13 = (u10).dot(u30)
  matrix_d = matrix.sqr([
    1,   w12, w13,
    w12, 1,   w23,
    w13, w23, 1   ])
  #
  matrix_x = matrix.sqr([
    c1, w12, w13,
    c2, 1,   w23,
    c3, w23, 1   ])
  #
  matrix_y = matrix.sqr([
    1,   c1,  w13,
    w12, c2,  w23,
    w13, c3,  1   ])
  #
  matrix_z = matrix.sqr([
    1,   w12,  c1,
    w12, 1,    c2,
    w13, w23,  c3 ])
  if(matrix_d.determinant()==0):
    raise RuntimeError(
      "Denominator zero: matrix_d in get_h_parameterization.")
  a = matrix_x.determinant()/matrix_d.determinant()
  b = matrix_y.determinant()/matrix_d.determinant()
  c = matrix_z.determinant()/matrix_d.determinant()
  return a, b, c
 def get_coefficients_alg3(self, ih):
     neighbors = self.h_connectivity[ih]
     i_a0 = neighbors.a0['iseq']
     i_a1 = neighbors.a1['iseq']
     i_a2 = neighbors.a2['iseq']
     i_a3 = neighbors.a3['iseq']
     rh = matrix.col(self.sites_cart[ih])
     r0 = matrix.col(self.sites_cart[i_a0])
     r1 = matrix.col(self.sites_cart[i_a1])
     r2 = matrix.col(self.sites_cart[i_a2])
     r3 = matrix.col(self.sites_cart[i_a3])
     uh0 = (rh - r0).normalize()
     u10 = (r1 - r0).normalize()
     u20 = (r2 - r0).normalize()
     u30 = (r3 - r0).normalize()
     if self.use_ideal_bonds_angles:
         alpha0 = math.radians(neighbors.a1['angle_ideal'])
         alpha1 = math.radians(neighbors.a2['angle_ideal'])
         alpha2 = math.radians(neighbors.a3['angle_ideal'])
         c1, c2, c3 = math.cos(alpha0), math.cos(alpha1), math.cos(alpha2)
         omega0 = math.radians(neighbors.a0['angle_a1a0a2'])
         omega1 = math.radians(neighbors.a0['angle_a2a0a3'])
         omega2 = math.radians(neighbors.a0['angle_a3a0a1'])
         w12, w23, w13 = math.cos(omega0), math.cos(omega1), math.cos(
             omega2)
     else:
         c1 = (uh0).dot(u10)
         c2 = (uh0).dot(u20)
         c3 = (uh0).dot(u30)
         w12 = (u10).dot(u20)
         w23 = (u20).dot(u30)
         w13 = (u10).dot(u30)
     matrix_d = matrix.sqr([1, w12, w13, w12, 1, w23, w13, w23, 1])
     #
     matrix_x = matrix.sqr([c1, w12, w13, c2, 1, w23, c3, w23, 1])
     #
     matrix_y = matrix.sqr([1, c1, w13, w12, c2, w23, w13, c3, 1])
     #
     matrix_z = matrix.sqr([1, w12, c1, w12, 1, c2, w13, w23, c3])
     if (matrix_d.determinant() == 0):
         raise RuntimeError(
             "Denominator zero: matrix_d in get_h_parameterization.")
     a = matrix_x.determinant() / matrix_d.determinant()
     b = matrix_y.determinant() / matrix_d.determinant()
     c = matrix_z.determinant() / matrix_d.determinant()
     return a, b, c
def get_coefficients_alg3(rh, a0, a1, a2, a3, use_ideal_bonds_angles,
                          sites_cart):
    r0 = matrix.col(sites_cart[a0.iseq])
    r1 = matrix.col(sites_cart[a1.iseq])
    r2 = matrix.col(sites_cart[a2.iseq])
    r3 = matrix.col(sites_cart[a3.iseq])
    uh0 = (rh - r0).normalize()
    u10 = (r1 - r0).normalize()
    u20 = (r2 - r0).normalize()
    u30 = (r3 - r0).normalize()
    if use_ideal_bonds_angles:
        alpha0 = math.radians(a1.angle_ideal)
        alpha1 = math.radians(a2.angle_ideal)
        alpha2 = math.radians(a3.angle_ideal)
        c1, c2, c3 = math.cos(alpha0), math.cos(alpha1), math.cos(alpha2)
        omega0 = math.radians(a0.angle_ideal[0])
        omega1 = math.radians(a0.angle_ideal[1])
        omega2 = math.radians(a0.angle_ideal[2])
        w12, w23, w13 = math.cos(omega0), math.cos(omega1), math.cos(omega2)
    else:
        c1 = (uh0).dot(u10)
        c2 = (uh0).dot(u20)
        c3 = (uh0).dot(u30)
        w12 = (u10).dot(u20)
        w23 = (u20).dot(u30)
        w13 = (u10).dot(u30)
    matrix_d = matrix.sqr([1, w12, w13, w12, 1, w23, w13, w23, 1])
    #
    matrix_x = matrix.sqr([c1, w12, w13, c2, 1, w23, c3, w23, 1])
    #
    matrix_y = matrix.sqr([1, c1, w13, w12, c2, w23, w13, c3, 1])
    #
    matrix_z = matrix.sqr([1, w12, c1, w12, 1, c2, w13, w23, c3])
    if (matrix_d.determinant() == 0):
        raise RuntimeError(
            "Denominator zero: matrix_d in get_h_parameterization.")
    a = matrix_x.determinant() / matrix_d.determinant()
    b = matrix_y.determinant() / matrix_d.determinant()
    c = matrix_z.determinant() / matrix_d.determinant()
    return a, b, c
 def process_1_neighbor(self, neighbors):
     ih = neighbors.ih
     i_a0 = neighbors.a0['iseq']
     rh = matrix.col(self.sites_cart[ih])
     r0 = matrix.col(self.sites_cart[i_a0])
     if self.use_ideal_bonds_angles:
         disth = neighbors.a0['dist_ideal']
     else:
         disth = (r0 - rh).length()
     i_a1 = neighbors.a1['iseq']
     i_b1 = neighbors.b1['iseq']
     r1 = matrix.col(self.sites_cart[i_a1])
     rb1 = matrix.col(self.sites_cart[i_b1])
     uh0 = (rh - r0).normalize()
     u10 = (r1 - r0).normalize()
     dihedral = dihedral_angle(sites=[
         self.sites_cart[ih], self.sites_cart[i_a0], self.sites_cart[i_a1],
         self.sites_cart[i_b1]
     ])
     if self.use_ideal_bonds_angles:
         alpha = math.radians(neighbors.a1['angle_ideal'])
         #allow for rotation even for idealize = True
         #phi = math.radians(b1.dihedral_ideal)
         phi = dihedral
     else:
         alpha = (u10).angle(uh0)
         phi = dihedral
     u1 = (r0 - r1).normalize()
     rb10 = rb1 - r1
     u2 = (rb10 - ((rb10).dot(u1)) * u1).normalize()
     u3 = u1.cross(u2)
     if (neighbors.number_h_neighbors == 0):
         self.h_parameterization[ih] = riding_coefficients(htype='alg1b',
                                                           ih=ih,
                                                           a0=i_a0,
                                                           a1=i_a1,
                                                           a2=i_b1,
                                                           a3=0,
                                                           a=alpha,
                                                           b=phi,
                                                           h=0,
                                                           n=0,
                                                           disth=disth)
     if (neighbors.number_h_neighbors == 2):
         i_h1, i_h2 = neighbors.h1['iseq'], neighbors.h2['iseq']
         i_h1, i_h2 = self.check_propeller_order(i_a0=i_a0,
                                                 i_a1=i_a1,
                                                 ih=ih,
                                                 i_h1=i_h1,
                                                 i_h2=i_h2)
         for nprop, hprop in zip([0, 1, 2], [ih, i_h1, i_h2]):
             self.h_parameterization[hprop] = riding_coefficients(
                 htype='prop',
                 ih=hprop,
                 a0=i_a0,
                 a1=i_a1,
                 a2=i_b1,
                 a3=0,
                 a=alpha,
                 n=nprop,
                 b=phi,
                 h=0,
                 disth=disth)
 def get_coefficients(self, ih):
     neighbors = self.h_connectivity[ih]
     if (neighbors.number_h_neighbors == 1):
         i_h1 = neighbors.h1['iseq']
     else:
         i_h1 = None
     i_a0 = neighbors.a0['iseq']
     i_a1 = neighbors.a1['iseq']
     i_a2 = neighbors.a2['iseq']
     rh = matrix.col(self.sites_cart[ih])
     r0 = matrix.col(self.sites_cart[i_a0])
     r1 = matrix.col(self.sites_cart[i_a1])
     r2 = matrix.col(self.sites_cart[i_a2])
     uh0 = (rh - r0).normalize()
     u10 = (r1 - r0).normalize()
     u20 = (r2 - r0).normalize()
     if self.use_ideal_bonds_angles:
         alpha0 = math.radians(neighbors.a0['angle_a1a0a2'])
         alpha1 = math.radians(neighbors.a1['angle_ideal'])
         alpha2 = math.radians(neighbors.a2['angle_ideal'])
         c0, c1, c2 = math.cos(alpha0), math.cos(alpha1), math.cos(alpha2)
     else:
         alpha0 = (u10).angle(u20)
         alpha0 = math.acos(u10.dot(u20))
         alpha1 = (u10).angle(uh0)
         alpha2 = (uh0).angle(u20)
         c0 = (u10).dot(u20)
         c1 = (u10).dot(uh0)
         c2 = (uh0).dot(u20)
     sumang = alpha0 + alpha1 + alpha2
     denom = (1.0 - c0**2)
     if (denom == 0):
         raise RuntimeError(
             "Denominator zero: (1-c0*c0) in get_h_parameterization.")
     a = (c1 - c0 * c2) / (1 - c0 * c0)
     b = (c2 - c0 * c1) / (1 - c0 * c0)
     root = None
     #  # check if H, A0, A1, A2 are in a plane
     if (sumang < (2 * math.pi + 0.05) and (sumang > 2 * math.pi - 0.05)):
         h = None
     elif (sumang > (2 * math.pi + 0.05)
           and 1 - c1 * c1 - c2 * c2 - c0 * c0 + 2 * c0 * c1 * c2 < 0):
         root = 1 - c1 * c1 - c2 * c2 - c0 * c0 + 2 * c0 * c1 * c2
         h = None
         return sumang, a, b, h, root
     else:
         # two tetragonal geometry: e.g. CH2 group
         if (i_h1 is not None):
             rh2 = matrix.col(self.sites_cart[neighbors.h1['iseq']])
             uh02 = (rh2 - r0).normalize()
             if self.use_ideal_bonds_angles:
                 h = math.radians(neighbors.h1['angle_ideal']) * 0.5
             else:
                 h = (uh0).angle(uh02) * 0.5
             #test if vector v points to same 'side' as uh0
             if ((u10.cross(u20)).dot(uh0) < 0):
                 h = -h
         else:
             # if H is out of plane, but not in tetrahedral geometry
             root = 1 - c1 * c1 - c2 * c2 - c0 * c0 + 2 * c0 * c1 * c2
             if (root < 0):
                 raise RuntimeError(
                     "Expression in square root < 0 in get_h_parameterization."
                 )
             denom = math.sin(alpha0)
             if (denom == 0):
                 raise RuntimeError(
                     "Denominator zero: sin(alpha0)in get_h_parameterization."
                 )
             cz = (math.sqrt(1 - c1 * c1 - c2 * c2 - c0 * c0 +
                             2 * c0 * c1 * c2)) / math.sin(alpha0)
             h = cz
             #test if vector v points to same 'side' as uh0
             if ((u10.cross(u20)).dot(uh0) < 0):
                 h = -h
     return sumang, a, b, h, root
 def process_1_neighbor_type_arg(self, neighbors):
     ih = neighbors.ih
     i_h1 = neighbors.h1['iseq']
     i_a0 = neighbors.a0['iseq']
     rh = matrix.col(self.sites_cart[ih])
     r0 = matrix.col(self.sites_cart[i_a0])
     if self.use_ideal_bonds_angles:
         disth = neighbors.a0['dist_ideal']
     else:
         disth = (r0 - rh).length()
     i_a1 = neighbors.a1['iseq']
     r1 = matrix.col(self.sites_cart[i_a1])
     if ('dihedral_ideal' in neighbors.b1):
         ih_dihedral = ih
         ih_no_dihedral = i_h1
     else:
         if ('dihedral_ideal' in self.h_connectivity[i_h1].b1):
             ih_dihedral = i_h1
             ih_no_dihedral = ih
         else:
             self.unk_list.append(ih)
             return
     i_b1 = self.h_connectivity[ih_dihedral].b1['iseq']
     rb1 = matrix.col(self.sites_cart[i_b1])
     # check if angle is typical for propeller
     # catches case of missing propeller atom
     if (neighbors.h1['angle_ideal'] > 107
             and neighbors.h1['angle_ideal'] < 111):
         self.unk_list.append(ih)
     else:
         dihedral = dihedral_angle(sites=[
             self.sites_cart[i_b1], self.sites_cart[i_a1],
             self.sites_cart[i_a0], self.sites_cart[ih_dihedral]
         ])
         uh0 = (rh - r0).normalize()
         u10 = (r1 - r0).normalize()
         if self.use_ideal_bonds_angles:
             alpha = math.radians(neighbors.a1['angle_ideal'])
             phi = math.radians(
                 self.h_connectivity[ih_dihedral].b1['dihedral_ideal'])
         else:
             alpha = (u10).angle(uh0)
             phi = dihedral
         u1 = (r0 - r1).normalize()
         rb10 = rb1 - r1
         u2 = (rb10 - ((rb10).dot(u10)) * u10).normalize()
         u3 = u1.cross(u2)
         for ih_alg1a, phi_alg1a in zip([ih_dihedral, ih_no_dihedral],
                                        [phi, phi + math.pi]):
             if self.h_parameterization[ih_alg1a] is None:
                 self.h_parameterization[ih_alg1a] = riding_coefficients(
                     htype='alg1a',
                     ih=ih_alg1a,
                     a0=i_a0,
                     a1=i_a1,
                     a2=i_b1,
                     a3=0,
                     a=alpha,
                     b=phi_alg1a,
                     n=0,
                     h=0,
                     disth=disth)
def get_h_parameterization(
  connectivity, sites_cart, idealize):
  #connectivity, xray_structure, names, atoms_list, idealize):
  #sites_cart = xray_structure.sites_cart()
  h_parameterization = {}
  for ih in connectivity.keys():
    a0 = connectivity[ih][0]
    count_H, reduced_neighbs = a0.count_H, a0.reduced_neighbs
    n_red_neigbs = len(reduced_neighbs)
    rh = matrix.col(sites_cart[ih])
    r0 = matrix.col(sites_cart[a0.iseq])
    if idealize:
      dist_h = a0.dist_ideal
    else:
      dist_h = (r0 - rh).length()
  # case 2a and 2b, case 3
    if(n_red_neigbs == 2 or
      (n_red_neigbs == 3 and count_H == 0)):
      a1, a2  = reduced_neighbs[0], reduced_neighbs[1]
      r1 = matrix.col(sites_cart[a1.iseq])
      r2 = matrix.col(sites_cart[a2.iseq])
      uh0 = (rh - r0).normalize()
      u10 = (r1 - r0).normalize()
      u20 = (r2 - r0).normalize()
      if idealize:
        alpha0 = math.radians(a0.angle_ideal)
        alpha1 = math.radians(a1.angle_ideal)
        alpha2 = math.radians(a2.angle_ideal)
        c0, c1, c2 = math.cos(alpha0), math.cos(alpha1), math.cos(alpha2)
      else:
        alpha0 = (u10).angle(u20)
        alpha1 = (u10).angle(uh0)
        alpha2 = (uh0).angle(u20)
        c0 = (u10).dot(u20)
        c1 = (u10).dot(uh0)
        c2 = (uh0).dot(u20)
      #sumang = math.degrees(alpha0) + math.degrees(alpha1) + math.degrees(alpha2)
      #c0, c1, c2 = math.cos(alpha0), math.cos(alpha1), math.cos(alpha2)
      sumang = alpha0 + alpha1 + alpha2
      denom = (1.0-c0**2)
      if(denom==0):
        raise RuntimeError(
          "Denominator zero: (1-c0*c0) in get_h_parameterization.")
      a, b = (c1-c0*c2)/(1-c0*c0), (c2-c0*c1)/(1-c0*c0)
      h_parameterization[ih] = parameterization_info(
        a0     = a0.iseq,
        a1     = a1.iseq,
        a2     = a2.iseq,
        a      = a,
        b      = b,
        dist_h = dist_h)
      #if ((sumang < 361 and sumang > 359) and idealize == True ):
      #if (0):
      #if (sumang < 361 and sumang > 359):
      if (sumang < (2*math.pi + 0.01) and (sumang > 2*math.pi - 0.01)):
        h_parameterization[ih].htype = 'flat_2neigbs'
      else:
        root = 1-c1*c1-c2*c2-c0*c0+2*c0*c1*c2
        if(root < 0):
          raise RuntimeError(
            "Expression in square root < 0 in get_h_parameterization.")
        denom = math.sin(alpha0)
        if(denom==0):
          raise RuntimeError(
            "Denominator zero: sin(alpha0)in get_h_parameterization.")
        cz = (math.sqrt(1-c1*c1-c2*c2-c0*c0+2*c0*c1*c2))/math.sin(alpha0)
        h = cz/math.sin(alpha0)
        #test if vector v points to same 'side' as uh0
        if((u10.cross(u20)).dot(uh0) < 0):
          h = -h
        h_parameterization[ih].h = h
        if (n_red_neigbs == 2): # case 2b
          h_parameterization[ih].htype = '2neigbs'
        elif (n_red_neigbs == 3): # case 3
          h_parameterization[ih].htype = '3neigbs'
    # case 1a
    elif(n_red_neigbs == 1 and count_H == 1):
      neigbs_14 = connectivity[ih][2]
      a1 = reduced_neighbs[0]
      b1, b2 = neigbs_14[0], neigbs_14[1]
      r1 = matrix.col(sites_cart[a1.iseq])
      rb1 = matrix.col(sites_cart[b1.iseq])
      rb2 = matrix.col(sites_cart[b2.iseq])
      # chose 1-4 neighbor which is closer - important!
      if((rh-rb2).length() < (rh-rb1).length()):
        neigbs_14[0], neigbs_14[1] = neigbs_14[1], neigbs_14[0]
      rb1 = matrix.col(sites_cart[neigbs_14[0].iseq])
      r2 = r0 + (r1 - rb1).normalize()
      uh0 = (rh - r0).normalize()
      u10 = (r1 - r0).normalize()
      u20 = (r2 - r0).normalize()
      alpha0 = (u10).angle(u20)
      alpha1 = (u10).angle(uh0)
      alpha2 = (uh0).angle(u20)
      c0, c1, c2 = math.cos(alpha0), math.cos(alpha1), math.cos(alpha2)
      denom = (1-c0*c0)
      if(denom==0):
        raise RuntimeError(
          "Denominator zero: (1-c0*c0) in get_h_parameterization.")
      a, b = (c1-c0*c2)/(1-c0*c0), (c2-c0*c1)/(1-c0*c0)
      root = 1-c1*c1-c2*c2-c0*c0+2*c0*c1*c2
      if(root < 0):
        raise RuntimeError(
          "Expression in square root < 0 in get_h_parameterization.")
      denom = math.sin(alpha0)
      if(denom==0):
        raise RuntimeError(
          "Denominator zero: sin(alpha0)in get_h_parameterization.")
      cz = (math.sqrt(1-c1*c1-c2*c2-c0*c0+2*c0*c1*c2))/math.sin(alpha0)
      h = cz/math.sin(alpha0)
      # test if vector v points to same 'side' as uh0
      if((u10.cross(u20)).dot(uh0) < 0):
        h = -h
      h_parameterization[ih] = parameterization_info(
        htype  = 'alg1a',
        a0     = a0.iseq,
        a1     = a1.iseq,
        a2     = neigbs_14[0].iseq,
        a      = a,
        b      = b,
        h      = h,
        dist_h = dist_h)
    # case 1b
    elif(n_red_neigbs == 1 and (count_H == 0 or count_H ==2)):
      a1 = reduced_neighbs[0]
      a, b = 1, 1
      sec_neigbs = connectivity[ih][2]
      b1 = sec_neigbs[0]
      r1 = matrix.col(sites_cart[a1.iseq])
      rb1 = matrix.col(sites_cart[b1.iseq])
      #dh = a0.dist_ideal
      uh0 = (rh - r0).normalize()
      u10 = (r1 - r0).normalize()
      if idealize:
        alpha = math.radians(a1.angle_ideal)
      else:
        alpha = (u10).angle(uh0)
      rb10 = rb1 - r1
      v10 = (rb10 - ((rb10).dot(u10)) * u10).normalize()
      if(v10.dot(uh0) < 0):
        v10 = -v10
        a = -1
      #if(abs((u10.cross(v10)).dot(uh0)) < 0.001):
      #  h_parameterization[ih] = parameterization_info(
      #    htype  = 'alg1b_flat',
      #    a0     = a0.iseq,
      #    a1     = a1.iseq,
      #    a2     = b1.iseq,
      #    a      = a,
      #    alpha  = alpha,
      #    dist_h = dist_h)
      #else:
      #  w10 = (u10.cross(v10)).normalize()
      #  if(w10.dot(uh0) < 0):
      #    w10 = -w10
      #    b   = -1
      #  chi = math.asin((uh0).dot(w10))
      #  c_chi, s_chi = math.cos(abs(chi)), math.sin(abs(chi))
      #  rp = rh - dh * s_chi * w10
      #  rp0 = rp - r0
      #  eps = (rp0).angle(u10)
      #  h_parameterization[ih] = parameterization_info(
      #    htype  = 'alg1b',
      #    a0     = a0.iseq,
      #    a1     = a1.iseq,
      #    a2     = b1.iseq,
      #    a      = a,
      #    b      = b,
      #    chi    = chi,
      #    eps    = eps,
      #    alpha  = alpha,
      #    dist_h = dist_h)
      w10 = (u10.cross(v10)).normalize()
      if(w10.dot(uh0) < 0):
        w10 = -w10
        b   = -1
      chi = math.asin((uh0).dot(w10))
      c_chi, s_chi = math.cos(abs(chi)), math.sin(abs(chi))
      rp = rh - dist_h * s_chi * w10
      rp0 = rp - r0
      eps = (rp0).angle(u10)
      h_parameterization[ih] = parameterization_info(
        htype  = 'alg1b',
        a0     = a0.iseq,
        a1     = a1.iseq,
        a2     = b1.iseq,
        a      = a,
        b      = b,
        chi    = chi,
        eps    = eps,
        alpha  = alpha,
        dist_h = dist_h)
    else:
      h_parameterization[ih] = parameterization_info(
        htype  = 'unk',
        a0     = a0.iseq,
        a1     = a1.iseq)
  return h_parameterization
def get_coefficients(ih, a0, a1, a2, ih2, idealize, sites_cart, typeh):
  rh = matrix.col(sites_cart[ih])
  r0 = matrix.col(sites_cart[a0.iseq])
  r1 = matrix.col(sites_cart[a1.iseq])
  r2 = matrix.col(sites_cart[a2.iseq])
  uh0 = (rh - r0).normalize()
  u10 = (r1 - r0).normalize()
  u20 = (r2 - r0).normalize()
  if idealize:
    alpha0 = math.radians(a0.angle_ideal)
    alpha1 = math.radians(a1.angle_ideal)
    alpha2 = math.radians(a2.angle_ideal)
    c0, c1, c2 = math.cos(alpha0), math.cos(alpha1), math.cos(alpha2)
  else:
    alpha0 = (u10).angle(u20)
    alpha1 = (u10).angle(uh0)
    alpha2 = (uh0).angle(u20)
    c0 = (u10).dot(u20)
    c1 = (u10).dot(uh0)
    c2 = (uh0).dot(u20)
  sumang = alpha0 + alpha1 + alpha2
  denom = (1.0-c0**2)
  if(denom==0):
    raise RuntimeError(
      "Denominator zero: (1-c0*c0) in get_h_parameterization.")
  a = (c1-c0*c2)/(1-c0*c0)
  b = (c2-c0*c1)/(1-c0*c0)
  root = None
  # check if H, A0, A1, A2 are in a plane
  if (sumang < (2*math.pi + 0.05) and (sumang > 2*math.pi - 0.05)):
    h = None
  elif (sumang > (2*math.pi + 0.05) and 1-c1*c1-c2*c2-c0*c0+2*c0*c1*c2 < 0):
    root = 1-c1*c1-c2*c2-c0*c0+2*c0*c1*c2
    h = None
    return sumang, a, b, h, root
  else:
    # two tetragonal geometry: e.g. CH2 group
    if (ih2 is not None):
      rh2 = matrix.col(sites_cart[ih2.iseq])
      uh02 = (rh2 - r0).normalize()
      if idealize:
        h = math.radians(ih2.angle_ideal) * 0.5
      else:
        h = (uh0).angle(uh02) * 0.5
      #test if vector v points to same 'side' as uh0
      if((u10.cross(u20)).dot(uh0) < 0):
        h =  -h
    else:
    # if H is out of plane, but not in tetrahedral geometry
      root = 1-c1*c1-c2*c2-c0*c0+2*c0*c1*c2
      if(root < 0):
        raise RuntimeError(
          "Expression in square root < 0 in get_h_parameterization.")
      denom = math.sin(alpha0)
      if(denom==0):
        raise RuntimeError(
          "Denominator zero: sin(alpha0)in get_h_parameterization.")
      cz = (math.sqrt(1-c1*c1-c2*c2-c0*c0+2*c0*c1*c2))/math.sin(alpha0)
      h = cz
      #test if vector v points to same 'side' as uh0
      if((u10.cross(u20)).dot(uh0) < 0):
        h = -h
  return sumang, a, b, h, root
def get_h_parameterization(connectivity, sites_cart, idealize):
  h_parameterization = {}
  for ih in connectivity.keys():
   #for debugging
    #print 'atom:', names[ih]+' ('+str(ih)+ ') residue:', \
    #  atoms_list[ih].resseq, 'chain', atoms_list[ih].chain_id
    # if entry exists already, skip it
    if ih in h_parameterization:
      continue
    a0 = connectivity[ih][0]
    count_H  = a0.count_H
    reduced_neighbs = connectivity[ih][1]
    n_red_neigbs = len(reduced_neighbs)
    rh = matrix.col(sites_cart[ih])
    r0 = matrix.col(sites_cart[a0.iseq])
    if idealize:
      dist_h = a0.dist_ideal
    else:
      dist_h = (r0 - rh).length()
  # alg2a, 2tetra, 2neigbs
    if(n_red_neigbs == 2):
      a1, a2  = reduced_neighbs[0], reduced_neighbs[1]
      # if H is second neighbor, gets its index
      if (count_H == 1):
        hlist = connectivity[ih][2]
        if hlist:
          ih2 = (hlist[0])
          i_h2 = (hlist[0]).iseq
      else:
        ih2 = None
      sumang, a, b, h, root = get_coefficients(
        ih         = ih,
        a0         = a0,
        a1         = a1,
        a2         = a2,
        ih2        = ih2,
        idealize   = idealize,
        sites_cart = sites_cart,
        typeh      = 'alg2')
      h_parameterization[ih] = parameterization_info(
        a0     = a0.iseq,
        a1     = a1.iseq,
        a2     = a2.iseq,
        a      = a,
        b      = b,
        dist_h = dist_h)
      # alg2a
      if (sumang > (2*math.pi + 0.05) and root < 0):
        h_parameterization[ih].htype = 'unk_ideal'
      elif (sumang < (2*math.pi + 0.05) and (sumang > 2*math.pi - 0.05)):
        h_parameterization[ih].htype = 'flat_2neigbs'
      else:
        if (count_H == 1):
        # 2 tetragonal geometry
          h_parameterization[ih].htype = '2tetra'
          h_parameterization[ih].alpha = h
          h_parameterization[i_h2] = parameterization_info(
            a0     = a0.iseq,
            a1     = a1.iseq,
            a2     = a2.iseq,
            a      = a,
            b      = b,
            alpha  = -h,
            dist_h = dist_h,
            htype  = '2tetra')
        else:
          # 2neigbs
          h_parameterization[ih].h = h
          h_parameterization[ih].htype = '2neigbs'
    # tetragonal geometry: 3neigbs
    elif (n_red_neigbs == 3 and count_H == 0):
      a1, a2, a3  = reduced_neighbs[0], reduced_neighbs[1], reduced_neighbs[2]
      a, b, h = get_coefficients_alg3(
        rh         = rh,
        a0         = a0,
        a1         = a1,
        a2         = a2,
        a3         = a3,
        idealize   = idealize,
        sites_cart = sites_cart)
      h_parameterization[ih] = parameterization_info(
        a0     = a0.iseq,
        a1     = a1.iseq,
        a2     = a2.iseq,
        a3     = a3.iseq,
        a      = a,
        b      = b,
        h      = h,
        dist_h = dist_h,
        htype  = '3neigbs')
    # alg1a: X-H2 planar groups, such as in ARG, ASN, GLN
    # requires that dihedral angle restraint exists
    elif(n_red_neigbs == 1 and count_H == 1 and len(connectivity[ih])==4):
      a1 = reduced_neighbs[0]
      r1 = matrix.col(sites_cart[a1.iseq])
      hlist = connectivity[ih][2]
      ih_2 = hlist[0].iseq
      #if(len(connectivity[ih])!=4):
      #  continue
      b1 = (connectivity[ih][3])[0]
      if (b1.dihedral_ideal == None):
        continue
      #iseq_b1 = b1.iseq
      dihedral = dihedral_angle(
        sites=[sites_cart[b1.iseq], sites_cart[a1.iseq],
        sites_cart[a0.iseq],sites_cart[ih]])
      #print 'dihedrals', a0.dihedral, dihedral, a0.dihedral_ideal
      rb1 = matrix.col(sites_cart[b1.iseq])
      uh0 = (rh - r0).normalize()
      u10 = (r1 - r0).normalize()
      if idealize:
        alpha = math.radians(a1.angle_ideal)
        phi = math.radians(b1.dihedral_ideal)
        #phi = dihedral
      else:
        alpha = (u10).angle(uh0)
        #phi = a0.dihedral
        phi = dihedral
      u1 = (r0 - r1).normalize()
      rb10 = rb1 - r1
      u2 = (rb10 - ((rb10).dot(u10)) * u10).normalize()
      u3 = u1.cross(u2)
      h_parameterization[ih] = parameterization_info(
        htype  = 'alg1a',
        a0     = a0.iseq,
        a1     = a1.iseq,
        a2     = b1.iseq,
        phi    = phi,
        n      = 0,
        alpha  = alpha,
        dist_h = dist_h)
      h_parameterization[ih_2] = parameterization_info(
        htype  = 'alg1a',
        a0     = a0.iseq,
        a1     = a1.iseq,
        a2     = b1.iseq,
        phi    = phi+math.pi,
        n      = 0,
        alpha  = alpha,
        dist_h = dist_h)
    # case 1b
# a0.dihedral = dihedral angle between angle ideal and actual position
    elif(n_red_neigbs == 1 and (count_H == 0 or count_H ==2)):
      #if(count_H == 0 and len(connectivity[ih])!=4):
      #  print 'the culprit is ', ih, names[ih], atoms_list[ih].resseq
      if (len(connectivity[ih])!=4):
        continue
      a1 = reduced_neighbs[0]
      b1 = (connectivity[ih][3])[0]
      r1 = matrix.col(sites_cart[a1.iseq])
      rb1 = matrix.col(sites_cart[b1.iseq])
      uh0 = (rh - r0).normalize()
      u10 = (r1 - r0).normalize()
      dihedral = dihedral_angle(
        sites=[sites_cart[ih], sites_cart[a0.iseq],
        sites_cart[a1.iseq],sites_cart[b1.iseq]])
      if idealize:
        alpha = math.radians(a1.angle_ideal)
        #phi = math.radians(b1.dihedral_ideal)
        #allow for rotation even for idealize = True
        phi = dihedral
      else:
        alpha = (u10).angle(uh0)
        phi = dihedral
      u1 = (r0 - r1).normalize()
      rb10 = rb1 - r1
      u2 = (rb10 - ((rb10).dot(u1)) * u1).normalize()
      u3 = u1.cross(u2)
      h_parameterization[ih] = parameterization_info(
        htype  = 'alg1b',
        a0     = a0.iseq,
        a1     = a1.iseq,
        a2     = b1.iseq,
        phi    = phi,
        n      = 0,
        alpha  = alpha,
        dist_h = dist_h)
      if (count_H == 2):
        h_parameterization[ih].htype = 'prop'
        hlist = connectivity[ih][2]
        # TO DO: Can the order be reversed? To be kept in mind!!
        ih_2, ih_3 = hlist[0].iseq, hlist[1].iseq
        h_parameterization[ih_2] = parameterization_info(
          htype  = 'prop',
          a0     = a0.iseq,
          a1     = a1.iseq,
          a2     = b1.iseq,
          phi    = phi,
          n      = 1,
          alpha  = alpha,
          dist_h = dist_h)
        ih_2_coord = generate_H_positions(
          sites_cart        = sites_cart,
          ih                = ih_2,
          para_info         = h_parameterization[ih_2]).rH_gen
        h_parameterization[ih_3] = parameterization_info(
          htype  = 'prop',
          a0     = a0.iseq,
          a1     = a1.iseq,
          a2     = b1.iseq,
          phi    = phi,
          n      = 2,
          alpha  = alpha,
          dist_h = dist_h)
        if ((ih_2_coord - matrix.col(sites_cart[ih_3])).length() <
          (ih_2_coord - matrix.col(sites_cart[ih_2])).length() ):
          h_parameterization[ih_2].n = 2
          h_parameterization[ih_3].n = 1
    else:
      a1 = reduced_neighbs[0]
      h_parameterization[ih] = parameterization_info(
        htype  = 'unk',
        a0     = a0.iseq,
        a1     = a1.iseq)
  return h_parameterization
def get_coefficients(ih, a0, a1, a2, ih2, use_ideal_bonds_angles, sites_cart,
                     typeh):
    rh = matrix.col(sites_cart[ih])
    r0 = matrix.col(sites_cart[a0.iseq])
    r1 = matrix.col(sites_cart[a1.iseq])
    r2 = matrix.col(sites_cart[a2.iseq])
    uh0 = (rh - r0).normalize()
    u10 = (r1 - r0).normalize()
    u20 = (r2 - r0).normalize()
    if use_ideal_bonds_angles:
        alpha0 = math.radians(a0.angle_ideal[0])
        alpha1 = math.radians(a1.angle_ideal)
        alpha2 = math.radians(a2.angle_ideal)
        c0, c1, c2 = math.cos(alpha0), math.cos(alpha1), math.cos(alpha2)
    else:
        alpha0 = (u10).angle(u20)
        alpha0 = math.acos(u10.dot(u20))
        alpha1 = (u10).angle(uh0)
        alpha2 = (uh0).angle(u20)
        c0 = (u10).dot(u20)
        c1 = (u10).dot(uh0)
        c2 = (uh0).dot(u20)
    sumang = alpha0 + alpha1 + alpha2
    denom = (1.0 - c0**2)
    if (denom == 0):
        raise RuntimeError(
            "Denominator zero: (1-c0*c0) in get_h_parameterization.")
    a = (c1 - c0 * c2) / (1 - c0 * c0)
    b = (c2 - c0 * c1) / (1 - c0 * c0)
    root = None
    # check if H, A0, A1, A2 are in a plane
    if (sumang < (2 * math.pi + 0.05) and (sumang > 2 * math.pi - 0.05)):
        h = None
    elif (sumang > (2 * math.pi + 0.05)
          and 1 - c1 * c1 - c2 * c2 - c0 * c0 + 2 * c0 * c1 * c2 < 0):
        root = 1 - c1 * c1 - c2 * c2 - c0 * c0 + 2 * c0 * c1 * c2
        h = None
        return sumang, a, b, h, root
    else:
        # two tetragonal geometry: e.g. CH2 group
        if (ih2 is not None):
            rh2 = matrix.col(sites_cart[ih2.iseq])
            uh02 = (rh2 - r0).normalize()
            if use_ideal_bonds_angles:
                h = math.radians(ih2.angle_ideal) * 0.5
            else:
                h = (uh0).angle(uh02) * 0.5
            #test if vector v points to same 'side' as uh0
            if ((u10.cross(u20)).dot(uh0) < 0):
                h = -h
        else:
            # if H is out of plane, but not in tetrahedral geometry
            root = 1 - c1 * c1 - c2 * c2 - c0 * c0 + 2 * c0 * c1 * c2
            if (root < 0):
                raise RuntimeError(
                    "Expression in square root < 0 in get_h_parameterization.")
            denom = math.sin(alpha0)
            if (denom == 0):
                raise RuntimeError(
                    "Denominator zero: sin(alpha0)in get_h_parameterization.")
            cz = (math.sqrt(1 - c1 * c1 - c2 * c2 - c0 * c0 +
                            2 * c0 * c1 * c2)) / math.sin(alpha0)
            h = cz
            #test if vector v points to same 'side' as uh0
            if ((u10.cross(u20)).dot(uh0) < 0):
                h = -h
    return sumang, a, b, h, root
def get_h_parameterization(h_connectivity, sites_cart, use_ideal_bonds_angles):
    h_parameterization = {}
    n_atoms = len(sites_cart)
    for ih in h_connectivity.keys():
        #if (ih != 22):
        #  continue
        #for debugging
        #print 'atom:', names[ih]+' ('+str(ih)+ ') residue:', \
        #  atoms_list[ih].resseq, 'chain', atoms_list[ih].chain_id
        # if entry exists already, skip it
        if ih in h_parameterization.keys():
            continue
        a0 = h_connectivity[ih][0]
        count_H = a0.count_H
        reduced_neighbs = h_connectivity[ih][1]
        n_red_neigbs = len(reduced_neighbs)
        rh = matrix.col(sites_cart[ih])
        r0 = matrix.col(sites_cart[a0.iseq])
        if use_ideal_bonds_angles:
            dist_h = a0.dist_ideal
        else:
            dist_h = (r0 - rh).length()
    # alg2a, 2tetra, 2neigbs
        if (n_red_neigbs == 2):
            a1, a2 = reduced_neighbs[0], reduced_neighbs[1]
            # if H is second neighbor, gets its index
            if (count_H == 1):
                hlist = h_connectivity[ih][2]
                if hlist:
                    ih2 = (hlist[0])
                    i_h2 = (hlist[0]).iseq
            else:
                ih2 = None
            sumang, a, b, h, root = get_coefficients(
                ih=ih,
                a0=a0,
                a1=a1,
                a2=a2,
                ih2=ih2,
                use_ideal_bonds_angles=use_ideal_bonds_angles,
                sites_cart=sites_cart,
                typeh='alg2')
            h_parameterization[ih] = parameterization_info(a0=a0.iseq,
                                                           a1=a1.iseq,
                                                           a2=a2.iseq,
                                                           a=a,
                                                           b=b,
                                                           dist_h=dist_h)
            # alg2a
            if (sumang > (2 * math.pi + 0.05) and root < 0):
                h_parameterization[ih].htype = 'unk_ideal'
            elif (sumang < (2 * math.pi + 0.05)
                  and (sumang > 2 * math.pi - 0.05)):
                h_parameterization[ih].htype = 'flat_2neigbs'
            else:
                if (count_H == 1):
                    # 2 tetragonal geometry
                    h_parameterization[ih].htype = '2tetra'
                    h_parameterization[ih].alpha = h
                    h_parameterization[i_h2] = parameterization_info(
                        a0=a0.iseq,
                        a1=a1.iseq,
                        a2=a2.iseq,
                        a=a,
                        b=b,
                        alpha=-h,
                        dist_h=dist_h,
                        htype='2tetra')
                else:
                    # 2neigbs
                    h_parameterization[ih].h = h
                    h_parameterization[ih].htype = '2neigbs'
        # tetragonal geometry: 3neigbs
        elif (n_red_neigbs == 3 and count_H == 0):
            a1, a2, a3 = reduced_neighbs[0], reduced_neighbs[
                1], reduced_neighbs[2]
            a, b, h = get_coefficients_alg3(
                rh=rh,
                a0=a0,
                a1=a1,
                a2=a2,
                a3=a3,
                use_ideal_bonds_angles=use_ideal_bonds_angles,
                sites_cart=sites_cart)
            h_parameterization[ih] = parameterization_info(a0=a0.iseq,
                                                           a1=a1.iseq,
                                                           a2=a2.iseq,
                                                           a3=a3.iseq,
                                                           a=a,
                                                           b=b,
                                                           h=h,
                                                           dist_h=dist_h,
                                                           htype='3neigbs')
        # alg1a: X-H2 planar groups, such as in ARG, ASN, GLN
        # requires that dihedral angle restraint exists for at least one H atom
        elif (n_red_neigbs == 1 and count_H == 1
              and len(h_connectivity[ih]) == 4):
            b1 = None
            a1 = reduced_neighbs[0]
            r1 = matrix.col(sites_cart[a1.iseq])
            hlist = h_connectivity[ih][2]
            ih_2 = hlist[0].iseq
            for b1_test in h_connectivity[ih][3]:
                if (b1_test.dihedral_ideal is None):
                    continue
                else:
                    b1 = b1_test
            if (b1 == None):
                for b1_test in h_connectivity[ih_2][3]:
                    if (b1_test.dihedral_ideal is None):
                        continue
                    else:
                        b1 = b1_test
                        ih, ih_2 = ih_2, ih
            if (b1 == None):
                h_parameterization[ih] = parameterization_info(htype='unk',
                                                               a0=a0.iseq)
                continue
            # check if angle is typical for propeller
            # catches case of missing propeller atom
            if (hlist[0].angle_ideal > 107 and hlist[0].angle_ideal < 111):
                h_parameterization[ih] = parameterization_info(htype='unk',
                                                               a0=a0.iseq)
                h_parameterization[ih_2] = parameterization_info(htype='unk',
                                                                 a0=a0.iseq)
                continue
            dihedral = dihedral_angle(sites=[
                sites_cart[b1.iseq], sites_cart[a1.iseq], sites_cart[a0.iseq],
                sites_cart[ih]
            ])
            #print 'dihedrals', a0.dihedral, dihedral, a0.dihedral_ideal
            rb1 = matrix.col(sites_cart[b1.iseq])
            uh0 = (rh - r0).normalize()
            u10 = (r1 - r0).normalize()
            if use_ideal_bonds_angles:
                alpha = math.radians(a1.angle_ideal)
                phi = math.radians(b1.dihedral_ideal)
                #phi = dihedral
            else:
                alpha = (u10).angle(uh0)
                #phi = a0.dihedral
                phi = dihedral
            u1 = (r0 - r1).normalize()
            rb10 = rb1 - r1
            u2 = (rb10 - ((rb10).dot(u10)) * u10).normalize()
            u3 = u1.cross(u2)
            #print names[ih], names[b1.iseq], names[a1.iseq]
            if ih not in h_parameterization:
                h_parameterization[ih] = parameterization_info(htype='alg1a',
                                                               a0=a0.iseq,
                                                               a1=a1.iseq,
                                                               a2=b1.iseq,
                                                               phi=phi,
                                                               n=0,
                                                               alpha=alpha,
                                                               dist_h=dist_h)
            if ih_2 not in h_parameterization:
                h_parameterization[ih_2] = parameterization_info(htype='alg1a',
                                                                 a0=a0.iseq,
                                                                 a1=a1.iseq,
                                                                 a2=b1.iseq,
                                                                 phi=phi +
                                                                 math.pi,
                                                                 n=0,
                                                                 alpha=alpha,
                                                                 dist_h=dist_h)
        # case 1b


# a0.dihedral = dihedral angle between angle ideal and actual position
        elif (n_red_neigbs == 1 and (count_H == 0 or count_H == 2)):
            if (len(h_connectivity[ih]) != 4):
                continue
            a1 = reduced_neighbs[0]
            b1 = (h_connectivity[ih][3])[0]
            r1 = matrix.col(sites_cart[a1.iseq])
            rb1 = matrix.col(sites_cart[b1.iseq])
            uh0 = (rh - r0).normalize()
            u10 = (r1 - r0).normalize()
            dihedral = dihedral_angle(sites=[
                sites_cart[ih], sites_cart[a0.iseq], sites_cart[a1.iseq],
                sites_cart[b1.iseq]
            ])
            if use_ideal_bonds_angles:
                alpha = math.radians(a1.angle_ideal)
                #phi = math.radians(b1.dihedral_ideal)
                #allow for rotation even for idealize = True
                phi = dihedral
            else:
                alpha = (u10).angle(uh0)
                phi = dihedral
            u1 = (r0 - r1).normalize()
            rb10 = rb1 - r1
            u2 = (rb10 - ((rb10).dot(u1)) * u1).normalize()
            u3 = u1.cross(u2)
            h_parameterization[ih] = parameterization_info(htype='alg1b',
                                                           a0=a0.iseq,
                                                           a1=a1.iseq,
                                                           a2=b1.iseq,
                                                           phi=phi,
                                                           n=0,
                                                           alpha=alpha,
                                                           dist_h=dist_h)
            if (count_H == 2):
                h_parameterization[ih].htype = 'prop'
                hlist = h_connectivity[ih][2]
                ih_2, ih_3 = hlist[0].iseq, hlist[1].iseq
                h_parameterization[ih_2] = parameterization_info(htype='prop',
                                                                 a0=a0.iseq,
                                                                 a1=a1.iseq,
                                                                 a2=b1.iseq,
                                                                 phi=phi,
                                                                 n=1,
                                                                 alpha=alpha,
                                                                 dist_h=dist_h)
                # check if order is reversed
                ih_2_coord = compute_H_position(sites_cart=sites_cart,
                                                ih=ih_2,
                                                hp=h_parameterization[ih_2])
                h_parameterization[ih_3] = parameterization_info(htype='prop',
                                                                 a0=a0.iseq,
                                                                 a1=a1.iseq,
                                                                 a2=b1.iseq,
                                                                 phi=phi,
                                                                 n=2,
                                                                 alpha=alpha,
                                                                 dist_h=dist_h)
                if ((ih_2_coord - matrix.col(sites_cart[ih_3])).length() <
                    (ih_2_coord - matrix.col(sites_cart[ih_2])).length()):
                    h_parameterization[ih_2].n = 2
                    h_parameterization[ih_3].n = 1
        else:
            h_parameterization[ih] = parameterization_info(htype='unk',
                                                           a0=a0.iseq)
    return h_parameterization