def place_building_block(self, building_block, edges): assert ( building_block.get_num_functional_groups() > 2 ), ( f'{building_block} needs to have more than 2 functional ' 'groups but has ' f'{building_block.get_num_functional_groups()}.' ) building_block = building_block.with_centroid( position=self._position, atom_ids=building_block.get_placer_ids(), ) edge_centroid = ( sum(edge.get_position() for edge in edges) / len(edges) ) edge_normal = get_acute_vector( reference=edge_centroid, vector=get_plane_normal( points=np.array([ edge.get_position() for edge in edges ]), ), ) core_centroid = building_block.get_centroid( atom_ids=building_block.get_core_atom_ids(), ) placer_centroid = building_block.get_centroid( atom_ids=building_block.get_placer_ids(), ) building_block = building_block.with_rotation_between_vectors( start=get_acute_vector( reference=core_centroid - placer_centroid, vector=building_block.get_plane_normal( atom_ids=building_block.get_placer_ids(), ), ), target=edge_normal, origin=self._position, ) fg_bonder_centroid = building_block.get_centroid( atom_ids=next( building_block.get_functional_groups() ).get_placer_ids(), ) edge_position = edges[self._aligner_edge].get_position() return building_block.with_rotation_to_minimize_angle( start=fg_bonder_centroid - self._position, target=edge_position - edge_centroid, axis=edge_normal, origin=self._position, ).get_position_matrix()
def place_building_block(self, building_block, edges): building_block = building_block.with_centroid( position=self._position, atom_ids=building_block.get_placer_ids(), ) edge_centroid = (sum(edge.get_position() for edge in edges) / len(edges)) core_centroid = building_block.get_centroid( atom_ids=building_block.get_core_atom_ids(), ) placer_centroid = building_block.get_centroid( atom_ids=building_block.get_placer_ids(), ) building_block = building_block.with_rotation_between_vectors( start=get_acute_vector( reference=core_centroid - placer_centroid, vector=building_block.get_plane_normal( atom_ids=building_block.get_placer_ids(), ), ), target=self._edge_normal, origin=self._position, ) fg_bonder_centroid = building_block.get_centroid(atom_ids=next( building_block.get_functional_groups()).get_placer_ids(), ) start = fg_bonder_centroid - self._position edge_coord = edges[self._aligner_edge].get_position() building_block = (building_block.with_rotation_to_minimize_angle( start=start, target=edge_coord - edge_centroid, axis=self._edge_normal, origin=self._position, )) return building_block.get_position_matrix()
def __init__(self, building_block): """ Initialize a :class:`._FunctionalGroupSorter` instance. Parameters ---------- building_block : :class:`.BuildingBlock` The building block, whose functional groups are to be sorted. """ self._building_block = building_block fg0_position = building_block.get_centroid(atom_ids=next( building_block.get_functional_groups()).get_placer_ids(), ) self._placer_centroid = placer_centroid = (building_block.get_centroid( atom_ids=building_block.get_placer_ids(), )) fg0_direction = fg0_position - placer_centroid core_centroid = building_block.get_centroid( atom_ids=building_block.get_core_atom_ids(), ) axis = np.cross( fg0_direction, get_acute_vector( reference=core_centroid - placer_centroid, vector=building_block.get_plane_normal(), ), ) axis.setflags(write=False) super().__init__( items=range(building_block.get_num_functional_groups()), reference=fg0_direction, axis=axis, )
def place_building_block(self, building_block, edges): assert ( building_block.get_num_functional_groups() > 2 ), ( f'{building_block} needs to have more than 2 functional ' 'groups but has ' f'{building_block.get_num_functional_groups()}.' ) # Sort to ensure that for two vertices, which are periodically # equivalent, "edges" has identical ordering. This means that # the aligner_edge is chosen consistently in both cases. edges = sorted(edges, key=lambda edge: edge.get_parent_id()) building_block = building_block.with_centroid( position=self._position, atom_ids=building_block.get_placer_ids(), ) core_centroid = building_block.get_centroid( atom_ids=building_block.get_core_atom_ids(), ) normal = building_block.get_plane_normal( atom_ids=building_block.get_placer_ids(), ) normal = get_acute_vector( reference=core_centroid - self._position, vector=normal, ) building_block = building_block.with_rotation_between_vectors( start=normal, target=[0, 0, 1], origin=self._position, ) fg, = building_block.get_functional_groups(0) fg_centroid = building_block.get_centroid(fg.get_placer_ids()) edge_position = edges[self._aligner_edge].get_position() return building_block.with_rotation_to_minimize_angle( start=fg_centroid - self._position, target=edge_position - self._position, axis=np.array([0, 0, 1], dtype=np.float64), origin=self._position, ).get_position_matrix()
def place_building_block(self, building_block, edges): assert ( building_block.get_num_functional_groups() == 2 ), ( f'{building_block} needs to have exactly 2 functional ' 'groups but has ' f'{building_block.get_num_functional_groups()}.' ) building_block = building_block.with_centroid( position=self._position, atom_ids=building_block.get_placer_ids(), ) # Align the normal of the plane of best fit, defined by # all atoms in the building block, with the z axis. core_centroid = building_block.get_centroid( atom_ids=building_block.get_core_atom_ids(), ) normal = building_block.get_plane_normal() normal = get_acute_vector( reference=core_centroid - self._position, vector=normal, ) building_block = building_block.with_rotation_between_vectors( start=normal, target=[0, 0, 1], origin=self._position, ) # Rotate to place fg-fg vector along edge-edge vector. fg, = building_block.get_functional_groups(0) fg_centroid = building_block.get_centroid(fg.get_placer_ids()) target = edges[0].get_position() - edges[1].get_position() target *= 1 if self._aligner_edge == 0 else -1 building_block = building_block.with_rotation_between_vectors( start=fg_centroid - self._position, target=target, origin=self._position, ) return building_block.get_position_matrix()