Ejemplo n.º 1
0
def get_normal(building_block):
    """
    Get a normal to a plane crossing the building block.

    The normal is defined by the plane of best fit to the placer atoms
    of the building block. It is defined such that the it always forms
    an acute angle with the vector running from the centroid of the
    placer atoms to the centroid of the building block.

    Parameters
    ----------
    building_block : :.BuildingBlock`
        The building block whose normal should be calculated.

    Returns
    -------
    :class:`numpy.ndarray`
        The normal of `building_block`.

    """

    placer_centroid = building_block.get_centroid(
        atom_ids=building_block.get_placer_ids(),
    )
    normal = stk.get_acute_vector(
        reference=building_block.get_centroid() - placer_centroid,
        vector=building_block.get_plane_normal(
            atom_ids=building_block.get_placer_ids(),
        ),
    )
    if np.allclose(normal, [0, 0, 1], atol=1e-13):
        return np.array([0, 0, 1])
    if np.allclose(normal, [0, 0, -1], atol=1e-13):
        return np.array([0, 0, -1])
    return normal
Ejemplo n.º 2
0
def functional_group_angle(building_block):
    fg0 = next(building_block.get_functional_groups(0))
    fg0_position = building_block.get_centroid(
        atom_ids=fg0.get_placer_ids(),
    )
    placer_centroid = building_block.get_centroid(
        atom_ids=building_block.get_placer_ids(),
    )
    fg0_direction = fg0_position - placer_centroid
    centroid = building_block.get_centroid(
        atom_ids=building_block.get_placer_ids(),
    )
    normal = stk.get_acute_vector(
        reference=building_block.get_centroid() - placer_centroid,
        vector=building_block.get_plane_normal(
            atom_ids=building_block.get_placer_ids(),
        ),
    )
    axis = -np.cross(normal, fg0_direction)

    def inner(functional_group):
        position = building_block.get_centroid(
            atom_ids=functional_group.get_placer_ids(),
        )
        fg_direction = position - centroid
        theta = stk.vector_angle(fg0_direction, fg_direction)

        projection = fg_direction @ axis
        if theta > 0 and projection < 0:
            return 2*np.pi - theta
        return theta

    return inner
Ejemplo n.º 3
0
def get_plane_normal(building_block):
    macrocycle = max(
        rdkit.GetSymmSSSR(building_block.to_rdkit_mol()),
        key=len,
    )
    centroid = building_block.get_centroid()
    atom1_position, = building_block.get_atomic_positions(0)
    normal = -stk.get_acute_vector(
        reference=atom1_position - centroid,
        vector=building_block.get_plane_normal(macrocycle),
    )
    if np.allclose(normal, [1, 0, 0], atol=1e-13):
        return np.array([1, 0, 0], dtype=np.float64)
    elif np.allclose(normal, [-1, 0, 0], atol=1e-13):
        return np.array([-1, 0, 0], dtype=np.float64)

    return normal