Source code for mbuild.port

import itertools

import numpy as np

from mbuild.compound import Compound, Particle
from mbuild.coordinate_transform import unit_vector, angle
from mbuild import clone


[docs]class Port(Compound): """A set of four ghost Particles used to connect parts. Parameters ---------- anchor : mb.Particle, optional, default=None A Particle associated with the port. Used to form bonds. orientation : array-like, shape=(3,), optional, default=[0, 1, 0] Vector along which to orient the port separation : float, optional, default=0 Distance to shift port along the orientation vector from the anchor particle position. If no anchor is provided, the port will be shifted from the origin. Attributes ---------- anchor : mb.Particle, optional, default=None A Particle associated with the port. Used to form bonds. up : mb.Compound Collection of 4 ghost particles used to perform equivalence transforms. Faces the opposite direction as self['down']. down : mb.Compound Collection of 4 ghost particles used to perform equivalence transforms. Faces the opposite direction as self['up']. used : bool Status of whether a port has been occupied following an equivalence transform. """ def __init__(self, anchor=None, orientation=None, separation=0): super(Port, self).__init__(name='Port', port_particle=True) self.anchor = anchor default_direction = np.array([0, 1, 0]) if orientation is None: orientation = [0, 1, 0] orientation = np.asarray(orientation) up = Compound(name='subport', port_particle=True) up.add(Particle(name='G', pos=[0.005, 0.0025, -0.0025], port_particle=True), 'middle') up.add(Particle(name='G', pos=[0.005, 0.0225, -0.0025], port_particle=True), 'top') up.add(Particle(name='G', pos=[-0.015, -0.0075, -0.0025], port_particle=True), 'left') up.add(Particle(name='G', pos=[0.005, -0.0175, 0.0075], port_particle=True), 'right') down = clone(up) self.add(up, 'up') self.add(down, 'down') self.used = False if np.allclose( default_direction, unit_vector(-orientation)): down.rotate(np.pi, [0, 0, 1]) self.rotate(np.pi, [0, 0, 1]) elif np.allclose( default_direction, unit_vector(orientation)): down.rotate(np.pi, [0, 0, 1]) else: normal = np.cross(default_direction, orientation) self.rotate(angle(default_direction, orientation), normal) down.rotate(np.pi, normal) if anchor: self.translate_to(anchor.pos) self.translate(separation*unit_vector(orientation)) def _clone(self, clone_of=None, root_container=None): newone = super(Port, self)._clone(clone_of, root_container) newone.anchor = clone(self.anchor, clone_of, root_container) newone.used = self.used return newone @property def center(self): """The cartesian center of the Port""" return np.mean(self.xyz_with_ports, axis=0) @property def direction(self): """The unit vector pointing in the 'direction' of the Port """ return unit_vector(self.xyz_with_ports[1]-self.xyz_with_ports[0]) @property def access_labels(self): """List of labels used to access the Port Returns ------- list of str Strings that can be used to access this Port relative to self.root """ access_labels = [] for referrer in self.referrers: referrer_labels = [key for key, val in self.root.labels.items() if val == referrer] port_labels = [key for key, val in referrer.labels.items() if val == self] if referrer is self.root: for label in port_labels: access_labels.append("['{}']".format(label)) for label in itertools.product(referrer_labels, port_labels): access_labels.append("['{}']".format("']['".join(label))) return access_labels def __repr__(self): descr = list('<') descr.append(self.name + ', ') if self.anchor: descr.append("anchor: '{}', ".format(self.anchor.name)) else: descr.append('anchor: None, ') descr.append('labels: {}, '.format(', '.join(self.access_labels))) descr.append('id: {}>'.format(id(self))) return ''.join(descr)