def apply(self, compound, orientation='', compound_port=''): """Arrange copies of a Compound as specified by the Pattern. Parameters ---------- compound orientation Returns ------- """ compounds = list() if self.orientations.get(orientation): for port in self.orientations[orientation]: new_compound = clone(compound) new_port = new_compound.labels[compound_port] equivalence_transform(new_compound, new_port['up'], port['up']) compounds.append(new_compound) else: for point in self.points: new_compound = clone(compound) translate(new_compound, point) compounds.append(new_compound) return compounds
def __init__(self, proto, port_labels=("up", "down"), n=2): if n < 1: raise Exception('n must be 1 or more') super(Polymer, self).__init__() for label in port_labels: assert_port_exists(label, proto) last_part = None for _ in range(n): this_part = clone(proto) self.add(this_part, 'monomer[$]') if last_part is None: first_part = this_part else: # Transform this part, such that it's bottom port is rotated # and translated to the last part's top port. equivalence_transform(this_part, this_part.labels[port_labels[1]], last_part.labels[port_labels[0]]) last_part = this_part # Hoist the last part's top port to be the top port of the polymer. self.add(last_part.labels[port_labels[0]], port_labels[0], containment=False) # Hoist the first part's bottom port to be the bottom port of the polymer. self.add(first_part.labels[port_labels[1]], port_labels[1], containment=False)
def apply_to_compound(self, guest, guest_port_name='down', host=None, backfill=None, backfill_port_name='up'): """Attach copies of a guest Compound to Ports on a host Compound. Parameters ---------- guest guest_port_name host backfill backfill_port_name Returns ------- """ n_ports = len(host.available_ports()) assert n_ports >= self.points.shape[0], "Not enough ports for pattern." assert_port_exists(guest_port_name, guest) box = host.boundingbox pattern = self.points * box.lengths + box.mins port_positions = np.empty(shape=(n_ports, 3)) port_list = list() for port_idx, port in enumerate(host.available_ports()): port_positions[port_idx, :] = port['up']['middle'].pos port_list.append(port) used_ports = set() # Keep track of used ports for backfilling. guests = [] for point in pattern: closest_point_idx = np.argmin(host.min_periodic_distance(point, port_positions)) closest_port = port_list[closest_point_idx] used_ports.add(closest_port) # Attach the guest to the closest port. new_guest = clone(guest) equivalence_transform(new_guest, new_guest.labels[guest_port_name], closest_port) guests.append(new_guest) # Move the port as far away as possible (simpler than removing it). # There may well be a more elegant/efficient way of doing this. port_positions[closest_point_idx, :] = np.array([np.inf, np.inf, np.inf]) backfills = [] if backfill: assert_port_exists(backfill_port_name, backfill) # Attach the backfilling Compound to unused ports. for port in port_list: if port not in used_ports: new_backfill = clone(backfill) # Might make sense to have a backfill_port_name option... equivalence_transform( new_backfill, new_backfill.labels[backfill_port_name], port) backfills.append(new_backfill) return guests, backfills
def test_equivalence_transform(self, ch2, ch3, methane): ch2_atoms = list(ch2.particles()) methane_atoms = list(methane.particles()) equivalence_transform(ch2, ch2_atoms[0], methane_atoms[0], add_bond=False) assert (ch2_atoms[0].pos == methane_atoms[0].pos).all() equivalence_transform(ch2, ch2['up'], ch3['up']) assert ch2.n_bonds == 2 assert nx.number_of_edges(ch2.root.bond_graph) == 3 assert nx.number_of_edges(ch3.root.bond_graph) == 4 ethyl = mb.Compound([ch2, ch3]) assert ethyl.n_bonds == 6
def __init__(self, monomers, sequence="A", n=2, port_labels=("up", "down")): if n < 1: raise ValueError("n must be 1 or more") super(Polymer, self).__init__() if isinstance(monomers, Compound): monomers = (monomers,) for monomer in monomers: for label in port_labels: assert_port_exists(label, monomer) unique_seq_ids = sorted(set(sequence)) if len(monomers) != len(unique_seq_ids): raise ValueError( "Number of monomers passed to `Polymer` class must" " match number of unique entries in the specified" " sequence." ) # 'A': monomer_1, 'B': monomer_2.... seq_map = dict(zip(unique_seq_ids, monomers)) last_part = None for n_added, seq_item in enumerate(it.cycle(sequence)): this_part = clone(seq_map[seq_item]) self.add(this_part, "monomer[$]") if last_part is None: first_part = this_part else: # Transform this part, such that it's bottom port is rotated # and translated to the last part's top port. equivalence_transform(this_part, this_part.labels[port_labels[1]], last_part.labels[port_labels[0]]) last_part = this_part if n_added == n * len(sequence) - 1: break # Hoist the last part's top port to be the top port of the polymer. self.add(last_part.labels[port_labels[0]], port_labels[0], containment=False) # Hoist the first part's bottom port to be the bottom port of the polymer. self.add(first_part.labels[port_labels[1]], port_labels[1], containment=False)