def initialize(self): """Initializes the analysis (e.g. parses and checks input parameters, set some variables ...). """ # The input parameters are parsed. self.interpreteInputParameters() self.bondNames = {} for aIndexes in self.group: for at in self.universe.atomList(): if at.index == aIndexes[0]: if isinstance(at.topLevelChemicalObject(), (Protein, PeptideChain, NucleotideChain)): self.bondNames[tuple( aIndexes)] = at.parent.parent.sequence_number else: self.bondNames[tuple(aIndexes)] = at.index break self.referenceDirection = Vector(0.0, 0.0, 1.0) # The results are stored in dictionnary because the order in which the bonds are treated does not # always follow the structure. self.P2 = {} self.S2 = {}
def centerAndMomentOfInertia(self, conf=None): """ :param conf: a configuration object, or None for the current configuration :type conf: :class:`~MMTK.ParticleProperties.Configuration` or NoneType :returns: the center of mass and the moment of inertia tensor in the given configuration """ from Scientific.Geometry import delta offset = None universe = self.universe() if universe is not None: offset = universe.contiguousObjectOffset([self], conf) m = 0. mr = Vector(0., 0., 0.) t = Tensor(3 * [3 * [0.]]) for a in self.atomIterator(): ma = a._mass if offset is None: r = a.position(conf) else: r = a.position(conf) + offset[a] m += ma mr += ma * r t += ma * r.dyadicProduct(r) cm = mr / m t -= m * cm.dyadicProduct(cm) t = t.trace() * delta - t return cm, t
def __init__(self, elementary_cell, lattice_vectors, cells, function=None, base=None): """ :param elementary_cell: a list of points in the elementary cell :param lattice_vectors: a list of lattice vectors. Each lattice vector defines a lattice dimension (only values from one to three make sense) and indicates the displacement along this dimension from one cell to the next. :param cells: a list of integers, whose length must equal the number of dimensions. Each entry specifies how often a cell is repeated along this dimension. :param function: a function that is called for every lattice point with the vector describing the point as argument. The return value of this function is stored in the lattice object. If the function is 'None', the vector is directly stored in the lattice object. """ if len(lattice_vectors) != len(cells): raise TypeError('Inconsistent dimension specification') if base is None: base = Vector(0, 0, 0) self.dimension = len(lattice_vectors) self.elements = [] self.makeLattice(elementary_cell, lattice_vectors, cells, base) Lattice.__init__(self, function)
def randomPointInSphere(r): """Returns a vector drawn from a uniform distribution within a sphere of radius |r|.""" rsq = r * r while 1: x = N.array([uniform(-r, r), uniform(-r, r), uniform(-r, r)]) if N.dot(x, x) < rsq: break return Vector(x)
def __init__(self, universe, cutoff): """ :param universe: the universe for which the basis will be used :type universe: :class:~MMTK.Universe.Universe :param cutoff: the wavelength cutoff. A smaller value yields a larger basis. :type cutoff: float """ p1, p2 = universe.boundingBox() p2 = p2 + Vector(cutoff, cutoff, cutoff) l = (p2 - p1).array n_max = (0.5 * l / cutoff + 0.5).astype(N.Int) wave_numbers = [(nx, ny, nz) for nx in range(-n_max[0], n_max[0]+1) for ny in range(-n_max[1], n_max[1]+1) for nz in range(-n_max[2], n_max[2]+1) if (nx/l[0])**2 + (ny/l[1])**2 + (nz/l[2])**2 \ < 0.25/cutoff**2] atoms = universe.atomList() natoms = len(atoms) basis = N.zeros((3 * len(wave_numbers) + 3, natoms, 3), N.Float) cm = universe.centerOfMass() i = 0 for rotation in [ Vector(1., 0., 0.), Vector(0., 1., 0.), Vector(0., 0., 1.) ]: v = ParticleProperties.ParticleVector(universe, basis[i]) for a in atoms: v[a] = rotation.cross(a.position() - cm) i += i conf = universe.configuration().array - p1.array for n in wave_numbers: k = 2. * N.pi * N.array(n) / l w = self._w(conf[:, 0], k[0]) * self._w(conf[:, 1], k[1]) * \ self._w(conf[:, 2], k[2]) basis[i, :, 0] = w basis[i + 1, :, 1] = w basis[i + 2, :, 2] = w i += 3 self.array = basis self.universe = universe
def momentum(self, velocities=None): "Returns the momentum." if velocities is None: velocities = self.atomList()[0].universe().velocities() p = Vector(0., 0., 0.) for a in self.atomList(): p = p + a._mass * velocities[a] return p
def __init__(self, points, **attr): """ @param points: a sequence of points to be connected by lines @type points: sequence of L{Scientific.Geometry.Vector} @param attr: graphics attributes as keyword parameters """ self.points = points ShapeObject.__init__(self, attr, None, None, Vector(0., 0., 0.))
def retrieveUnitCell(self, compact=True): """ Constructs a universe (OrthrhombicPeriodicUniverse or ParallelepipedicPeriodicUniverse) representing the unit cell of the crystal and adds all the molecules it contains, i.e. the molecules of the asymmetric unit and its images obtained by applying the crystallographic symmetry operations. :param compact: if True, the images are shifted such that their centers of mass lie inside the unit cell. :type compact: bool :returns: a universe :rtype: :class:~MMTK.Universe.Universe """ if not self.pdb_conf.cs_transformations: return self.retrieveAsymmetricUnit() universe = self.retrieveUniverse() asu_count = 0 for symop in self.pdb_conf.cs_transformations: transformation = symop.asLinearTransformation() rotation = transformation.tensor translation = transformation.vector is_asu = translation.length() < 1.e-8 and \ N.maximum.reduce(N.ravel(N.fabs((rotation -delta).array))) < 1.e-8 if is_asu: asu_count += 1 asu = MMTK.Collection(self.retrieveMolecules()) for atom in asu.atomList(): atom.setPosition(symop(atom.position())) if hasattr(atom, 'u'): atom.u = rotation.dot(atom.u.dot(rotation.transpose())) atom.u = atom.u.symmetricalPart() atom.in_asu = is_asu if compact: cm = asu.centerOfMass() cm_fr = self.pdb_conf.to_fractional(cm) cm_fr = Vector(cm_fr[0] % 1., cm_fr[1] % 1., cm_fr[2] % 1.) \ - Vector(0.5, 0.5, 0.5) cm = self.pdb_conf.from_fractional(cm_fr) asu.translateTo(cm) universe.addObject(asu) assert asu_count == 1 return universe
def _planar_qvectors(self): hkl_dir = self._generate_hkls() self.hkl_dir = [] factor = pgcd(hkl_dir[0]) self.hkl_dir.append(Vector(hkl_dir[0]) / factor) factor = pgcd(hkl_dir[1]) self.hkl_dir.append(Vector(hkl_dir[1]) / factor) self.qDirections = [] self.qDirections.append(self.transRecBasis * self.hkl_dir[0]) self.qDirections.append(self.transRecBasis * self.hkl_dir[1]) if self.qDirections[0].cross(self.qDirections[1]).length() <= 0: raise Error( "The q plan must be defined by two non-colinear q-directions.") for q in self.qShells: qMin = max(q - 0.5 * self.qShellWidth, 0.0) qMax = q + 0.5 * self.qShellWidth indMax = [int(qMax / v.length()) + 2 for v in self.qDirections] grid = N.transpose(numpy.mgrid[-indMax[0]:indMax[0], -indMax[1]:indMax[1]]) indRange = (-grid).reshape(grid.size / 2, 2).tolist() + grid.reshape( grid.size / 2, 2).tolist() shuffle(indRange) qVects, hkls = self._explicit_qvectors(qMin, qMax, indRange) if qVects: self.qRadii.append(q) self.qVectors.append(qVects) self.hkls.append(hkls)
def boundingBox(self, conf=None): """ :param conf: a configuration object, or None for the current configuration :type conf: :class:~MMTK.ParticleProperties.Configuration or NoneType :returns: two opposite corners of a bounding box around the object. The bounding box is the smallest rectangular bounding box with edges parallel to the coordinate axes. :rtype: tuple of two Scientific.Geometry.Vector """ atoms = self.atomList() min = atoms[0].position(conf).array max = min for a in atoms[1:]: r = a.position(conf).array min = N.minimum(min, r) max = N.maximum(max, r) return Vector(min), Vector(max)
def angularVelocity(self, velocities=None, conf=None): "Returns the angular velocity." if velocities is None: velocities = self.atomList()[0].universe().velocities() cm, inertia = self.centerAndMomentOfInertia(conf) l = Vector(0., 0., 0.) for a in self.atomList(): l = l + a._mass * a.position(conf).cross(velocities[a]) return inertia.inverse() * l
def angularMomentum(self, velocities=None, conf=None): "Returns the angular momentum." if velocities is None: velocities = self.atomList()[0].universe().velocities() cm = self.centerOfMass(conf) l = Vector(0., 0., 0.) for a in self.atomList(): l = l + a._mass * a.position(conf).cross(velocities[a]) return l
def applyTo(self, object): """ Define the positions of the atoms in a chemical object by the stored coordinates. :param object: the object to which the coordinates are applied """ for a, r in self.dict.items(): object.setPosition(a, Vector(r[0], r[1], r[2]))
def dipole(self, atoms, reference=None): if reference is None: reference = atoms.centerOfMass() total = Vector(0., 0., 0.) for a in atoms.atomList(): charge = a.topLevelChemicalObject() \ .getAtomProperty(a, self.dataset.charge_property) total = total + charge * (a.position() - reference) return total
def randomPointInBox(a, b=None, c=None): """Returns a vector drawn from a uniform distribution within a rectangular box with edge lengths |a|, |b|, |c|. If |b| and/or |c| are omitted, they are taken to be equal to |a|.""" if b is None: b = a if c is None: c = a x = uniform(-0.5 * a, 0.5 * a) y = uniform(-0.5 * b, 0.5 * b) z = uniform(-0.5 * c, 0.5 * c) return Vector(x, y, z)
def EnergyGradientsForceConstants(e, n): energy = e[0] deriv = e[1] deriv = deriv + (3 * n - len(deriv)) * [0] gradients = [] i = 0 for j in range(n): gradients.append(Vector(deriv[i], deriv[i + 1], deriv[i + 2])) i = i + 3 return (energy, gradients, Numeric.array(e[2]))
def __init__(self, cellsize, cells, function=None, base=None): """ :param cellsize: the edge length of the elementary cell :type cellsize: float :param cells: a list of integers, whose length must equal the number of dimensions. Each entry specifies how often a cell is repeated along this dimension. :param function: a function that is called for every lattice point with the vector describing the point as argument. The return value of this function is stored in the lattice object. If the function is 'None', the vector is directly stored in the lattice object. """ lattice_vectors = (cellsize * Vector(1., 0., 0.), cellsize * Vector(0., 1., 0.), cellsize * Vector(0., 0., 1.)) if type(cells) != type(()): cells = 3 * (cells, ) BravaisLattice.__init__(self, lattice_vectors, cells, function, base)
def cornerPoints(self): (c1x, c1y, c1z), (c2x, c2y, c2z) = self.corners return [ Vector(c1x, c1y, c1z), Vector(c1x, c1y, c2z), Vector(c1x, c2y, c1z), Vector(c2x, c1y, c1z), Vector(c2x, c2y, c1z), Vector(c2x, c1y, c2z), Vector(c1x, c2y, c2z), Vector(c2x, c2y, c2z) ]
def atomicParameters(self): """ :returns: an iterator over the atoms in the model yielding a tuple (atom_id, position, ADP_tensor, occupancy) :rtype: iterator """ for atom_id in self.ids: yield (atom_id, Vector(self.positions[self.id_dict[atom_id]]), SymmetricTensor(self.adps[self.id_dict[atom_id]]), self.occupancies[self.id_dict[atom_id]])
def __init__(self, elementary_cell, lattice_vectors, cells, function=None, base=None): if len(lattice_vectors) != len(cells): raise TypeError, 'Inconsistent dimension specification' if base is None: base = Vector(0, 0, 0) self.dimension = len(lattice_vectors) self.elements = [] self.makeLattice(elementary_cell, lattice_vectors, cells, base) Lattice.__init__(self, function)
def releasehandler1(self, event): self.configure(cursor='top_left_arrow') self.update_idletasks() try: dx = event.x - self.click1x dy = event.y - self.click1y except AttributeError: return if dx != 0 or dy != 0: normal = Vector(self.axis) move = Vector(-dx*self.plane[:,0]+dy*self.plane[:,1]) axis = normal.cross(move) / \ Numeric.minimum.reduce(Numeric.fabs(self.plotbox_size)) rot = Rotation(axis.normal(), axis.length()) self.axis = rot(normal).array self.plane[:,0] = rot(Vector(self.plane[:,0])).array self.plane[:,1] = rot(Vector(self.plane[:,1])).array self.clear(1) self.redraw()
def __call__(self, *points): if len(points) == 1: points = tuple(points[0]) value = apply(Interpolation.InterpolatingFunction.__call__, (self, ) + points) if self.rank == 0: return value elif self.rank == 1: return Vector(value) else: return Tensor(value)
def _test_position_derivatives(self, precision): llk, pd = self.re.targetFunctionAndPositionDerivatives() dp = 0.0001 max_error = 0. for atom_id in self.atom_ids: p = self.re.getPosition(atom_id) gradient = Vector(0., 0., 0.) for v in [ Vector(1., 0., 0.), Vector(0., 1., 0.), Vector(0., 0., 1.) ]: self.re.setPosition(atom_id, p + dp * v) llk_p, dummy = self.re.targetFunctionAndPositionDerivatives() self.re.setPosition(atom_id, p - dp * v) llk_m, dummy = self.re.targetFunctionAndPositionDerivatives() gradient += (llk_p - llk_m) / (2. * dp) * v self.re.setPosition(atom_id, p) error = (gradient - pd[atom_id]).length() / pd[atom_id].length() max_error = max(max_error, error) self.assert_(max_error < precision)
def randomVelocity(temperature, mass): """ :param temperature: the temperature defining a Maxwell distribution :type temperature: float :param mass: the mass of a particle :type mass: float :returns: a random velocity vector for a particle of a given mass at a given temperature :rtype: Scientific.Geometry.Vector """ sigma = N.sqrt((temperature * Units.k_B) / (mass * Units.amu)) return Vector(gaussian(0., sigma, (3, )))
def momentum(self, velocities = None): """ :param velocities: a set of velocities for all atoms, or None for the current velocities :type velocities: :class:`~MMTK.ParticleProperties.ParticleVector` :returns: the momentum :rtype: Scientific.Geometry.Vector """ if velocities is None: velocities = self.atomList()[0].universe().velocities() return sum((a._mass*velocities[a] for a in self.atomIterator()), Vector(0., 0., 0.))
def __init__(self, attr, rotation, translation, reference_point): VRMLObject.__init__(self, attr) if rotation is None: rotation = Transformation.Rotation(ez, 0.) else: rotation = apply(Transformation.Rotation, rotation) if translation is None: translation = Transformation.Translation(Vector(0., 0., 0.)) else: translation = Transformation.Translation(translation) self.transformation = translation * rotation self.reference_point = reference_point
def randomPointInSphere(r): """ :param r: the radius of a sphere :type r: float :returns: a vector drawn from a uniform distribution within a sphere of radius r. :rtype: Scientific.Geometry.Vector """ rsq = r * r while 1: x = N.array([uniform(-r, r), uniform(-r, r), uniform(-r, r)]) if N.dot(x, x) < rsq: break return Vector(x)
def boundingSphere(self, conf=None): """Returns a sphere that contains all atoms in the object. This is *not* the minimal bounding sphere, just *some* bounding sphere.""" atoms = self.atomList() r = Vector(0., 0., 0.) for a in atoms: r = r + a.position(conf) center = r / len(atoms) r = 0. for a in self.atomList(): r = max(r, (a.position(conf) - center).length()) return Objects3D.Sphere(center, r)
def __init__(self, points, index_lists, **attr): """ @param points: a sequence of points @type points: sequence of L{Scientific.Geometry.Vector} @param index_lists: a sequence of index lists, one for each polygon. The index list for a polygon defines which points are vertices of the polygon. @type index_lists: sequence of C{list} @param attr: graphics attributes as keyword parameters """ self.points = points self.index_lists = index_lists ShapeObject.__init__(self, attr, None, None, Vector(0., 0., 0.))
def __init__(self, universe, cutoff): p1, p2 = universe.boundingBox() p2 = p2 + Vector(cutoff, cutoff, cutoff) l = (p2-p1).array n_max = (0.5*l/cutoff+0.5).astype(Numeric.Int) wave_numbers = [] for nx in range(-n_max[0], n_max[0]+1): for ny in range(-n_max[1], n_max[1]+1): for nz in range(-n_max[2], n_max[2]+1): if (nx/l[0])**2 + (ny/l[1])**2 + (nz/l[2])**2 \ < 0.25/cutoff**2: wave_numbers.append((nx, ny, nz)) atoms = universe.atomList() natoms = len(atoms) basis = Numeric.zeros((3*len(wave_numbers)+3, natoms, 3), Numeric.Float) cm = universe.centerOfMass() i = 0 for rotation in [Vector(1.,0.,0.), Vector(0.,1.,0.), Vector(0.,0.,1.)]: v = ParticleProperties.ParticleVector(universe, basis[i]) for a in atoms: v[a] = rotation.cross(a.position()-cm) i = i + 1 conf = universe.configuration().array-p1.array for n in wave_numbers: k = 2.*Numeric.pi*Numeric.array(n)/l w = self._w(conf[:, 0], k[0]) * self._w(conf[:, 1], k[1]) * \ self._w(conf[:, 2], k[2]) basis[i, :, 0] = w basis[i+1, :, 1] = w basis[i+2, :, 2] = w i = i + 3 self.array = basis self.universe = universe