Returns the Crick angle for each CA atom in the `Polymer`.

    Notes
    -----
    The final value is in the returned list is `None`, since the angle
    calculation requires pairs of points on both the primitive and
    reference_axis.

    Parameters
    ----------
    p : ampal.Polymer
        Reference `Polymer`.
    reference_axis : list(numpy.array or tuple or list)
        Length of reference_axis must equal length of the Polymer.
        Each element of reference_axis represents a point in R^3.
    tag : bool, optional
        If `True`, tags the `Polymer` with the reference axis coordinates
        and each Residue with its Crick angle. Crick angles are stored
        at the Residue level, but are calculated using the CA atom.
    reference_axis_name : str, optional
        Used to name the keys in tags at Chain and Residue level.

    Returns
    -------
    cr_angles : list(float)
        The crick angles in degrees for each CA atom of the Polymer.

    Raises
    ------
    ValueError
        If the Polymer and the reference_axis have unequal length.

def crick_angles(p, reference_axis, tag=True, reference_axis_name='ref_axis'):
    """Returns the Crick angle for each CA atom in the `Polymer`.

    Notes
    -----
    The final value is in the returned list is `None`, since the angle
    calculation requires pairs of points on both the primitive and
    reference_axis.

    Parameters
    ----------
    p : ampal.Polymer
        Reference `Polymer`.
    reference_axis : list(numpy.array or tuple or list)
        Length of reference_axis must equal length of the Polymer.
        Each element of reference_axis represents a point in R^3.
    tag : bool, optional
        If `True`, tags the `Polymer` with the reference axis coordinates
        and each Residue with its Crick angle. Crick angles are stored
        at the Residue level, but are calculated using the CA atom.
    reference_axis_name : str, optional
        Used to name the keys in tags at Chain and Residue level.

    Returns
    -------
    cr_angles : list(float)
        The crick angles in degrees for each CA atom of the Polymer.

    Raises
    ------
    ValueError
        If the Polymer and the reference_axis have unequal length.
    """
    if not len(p) == len(reference_axis):
        raise ValueError(
            "The reference axis must contain the same number of points"
            " as the Polymer primitive.")
    prim_cas = p.primitive.coordinates
    p_cas = p.get_reference_coords()
    ref_points = reference_axis.coordinates
    cr_angles = [
        dihedral(ref_points[i], prim_cas[i], prim_cas[i + 1], p_cas[i])
        for i in range(len(prim_cas) - 1)]
    cr_angles.append(None)

    if tag:
        p.tags[reference_axis_name] = reference_axis
        monomer_tag_name = 'crick_angle_{0}'.format(reference_axis_name)
        for m, c in zip(p._monomers, cr_angles):
            m.tags[monomer_tag_name] = c
    return cr_angles