def mouseReleaseEvent(self, event): button = event.button() self.setCursor(Qt.arrowCursor) if button == Qt.LeftButton: 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) / \ N.minimum.reduce(N.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 elif button == Qt.MidButton: try: dx = event.x() - self.click2x dy = event.y() - self.click2y except AttributeError: return if dx != 0 or dy != 0: self.translate = self.translate + N.array([dx, dy]) else: try: dy = event.y() - self.click3y except AttributeError: return if dy != 0: ratio = -dy/self.plotbox_size[1] self.scale = self.scale * (1.+ratio) self.update()
def evaluationPoints(object, n, smallest=0.3, largest=0.5): """Returns a list of |n| points suitable for the evaluation of the electrostatic potential around |object|. The points are chosen at random and uniformly in a shell around the object such that no point has a distance larger than |largest| from any atom or smaller than |smallest| from any non-hydrogen atom. """ atoms = object.atomList() p1, p2 = object.boundingBox() margin = Vector(largest, largest, largest) p1 = p1 - margin p2 = p2 + margin a, b, c = tuple(p2 - p1) offset = 0.5 * Vector(a, b, c) points = [] while len(points) < n: p = p1 + Random.randomPointInBox(a, b, c) + offset m = 2 * largest ok = 1 for atom in atoms: d = (p - atom.position()).length() m = min(m, d) if d < smallest and atom.symbol != 'H': ok = 0 if not ok: break if ok and m <= largest: points.append(p) return points
def _userdefined_qvectors(self): hkls = self._generate_hkls() if self.universe.reciprocalBasisVectors() is None: qVects = [Vector(v) for v in hkls] else: qVects = [self.transRecBasis * Vector(hkl) for hkl in hkls] qVectsDict = {} for i in range(len(qVects)): qVect = qVects[i] hkl = Vector(hkls[i]) qLength = round(qVect.length(), 3) if qVectsDict.has_key(qLength): qVectsDict[qLength]["qvect"].append(qVect) qVectsDict[qLength]["hkl"].append(hkl) else: qVectsDict[qLength] = {"qvect": [qVect], "hkl": [hkl]} for q in sorted(qVectsDict.keys()): self.qRadii.append(q) self.qVectors.append(qVectsDict[q]["qvect"]) self.hkls.append(qVectsDict[q]["hkl"])
def _explicit_qvectors(self, qMin, qMax, indRange): qVects = [] hkls = [] dimen = len(self.qDirections) for ind in indRange: qVect = Vector() for i in range(dimen): qVect += ind[i] * self.qDirections[i] if qMin < qVect.length() <= qMax: if not qVect in qVects: qVects.append(qVect) hkl = Vector([0, 0, 0]) for i in range(dimen): hkl += ind[i] * self.hkl_dir[i] hkls.append(hkl) if len(qVects) >= self.qVectorsPerShell: break LogMessage( 'info', '%d explicit Q vectors generated for shell [%s,%s].' % (len(qVects), qMin, qMax), ['file', 'console']) return qVects, hkls
def __init__(self, cellsize, cells, function=None, base=None): """ @param cellsize: the edge length of the cubic elementary cell @type cellsize: C{float} @param cells: a tuple of three integers, indicating how often the elementary cell should be replicated along each lattice vector @param cells: C{tuple} of C{int} @param function: the function to be applied to each point in the lattice in order to obtain the value stored in the lattice. If no function is specified, the point itself becomes the value stored in the lattice. @type function: callable @param base: an offset added to all lattice points @type base: L{Scientific.Geometry.Vector} """ 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 __init__(self, cellsize, cells, function=None, base=None): 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 basisVectors(parameters): """Returns the basis vectors for the simulation cell from the six crystallographic parameters. @param parameters: the a, b, c, alpha, bete and gamma of the simulation cell. @type: parameters: list of 6 floats @return: a list of three Scientific.Geometry.Vector objects representing respectively a, b and c basis vectors. @rtype: list """ # The simulation cell parameters. a, b, c, alpha, beta, gamma = parameters # By construction the a vector is aligned with the x axis. e1 = Vector(a, 0.0, 0.0) # By construction the b vector is in the xy plane. e2 = b * Vector(N.cos(gamma), N.sin(gamma), 0.0) e3_x = N.cos(beta) e3_y = (N.cos(alpha) - N.cos(beta) * N.cos(gamma)) / N.sin(gamma) e3_z = N.sqrt(1.0 - e3_x**2 - e3_y**2) e3 = c * Vector(e3_x, e3_y, e3_z) return (e1, e2, e3)
def asuToUnitCell(self, asu_contents, compact=True): """ :param asu_contents: the molecules in the asymmetric unit, usually obtained from :func:~MMTK.PDB.PDBConfiguration.createAll(). :param compact: if True, all molecules images are shifted such that their centers of mass lie inside the unit cell. :type compact: bool :returns: a collection containing all molecules in the unit cell, obtained by copying and moving the molecules from the asymmetric unit according to the crystallographic symmetry operations. :rtype: :class:~MMTK.Collections.Collection """ unit_cell_contents = Collections.Collection() for symop in self.cs_transformations: transformation = symop.asLinearTransformation() rotation = transformation.tensor translation = transformation.vector image = copy.deepcopy(asu_contents) for atom in image.atomList(): atom.setPosition(symop(atom.position())) if compact: cm = image.centerOfMass() cm_fr = self.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.from_fractional(cm_fr) image.translateTo(cm) unit_cell_contents.addObject(image) return unit_cell_contents
def anchor(universe): """Anchor a universe""" if(universe.numberOfAtoms() >=3): #set anchor atoms indexes a1i = 0 for i in range(len(universe.atomList()[a1i].bondedTo())): for j in range(len(universe.atomList()[a1i].bondedTo()[i].bondedTo())): if universe.atomList()[a1i] is not \ universe.atomList()[a1i].bondedTo()[i].bondedTo()[j] : a2i = i; a3i = j; break print 'anchor using: ', a1i, a2i, a3i v1 = universe.atomList()[a1i].position(); v2 = universe.atomList()[a1i].bondedTo()[a2i].position(); v3 = universe.atomList()[a1i].bondedTo()[a2i].bondedTo()[a3i].position(); vT01 = -v1; tra01 = Translation(vT01); universe.applyTransformation(tra01); x = universe.atomList()[a1i].bondedTo()[a2i].position().x(); y = 0; z = universe.atomList()[a1i].bondedTo()[a2i].position().z(); vR01 = Vector(x,y,z); vR02 = Vector(1,0,0); sign = 1.0 if ((z > 0) and (x > 0)) or ((z < 0) and (x < 0)): sign = -1.0 rot01 = Rotation(Vector(0,1,0), sign*vR01.angle(vR02)); universe.applyTransformation(rot01); v4 = universe.atomList()[a1i].bondedTo()[a2i].position(); sign = -1.0 if ((x > 0) and (y > 0)) or ((x < 0) and (y < 0)): sign = 1.0 rot02 = Rotation(Vector(0,0,1), sign*v4.angle(Vector(1,0,0))); universe.applyTransformation(rot02); x = 0; y = universe.atomList()[a1i].bondedTo()[a2i].bondedTo()[a3i].position().y(); z = universe.atomList()[a1i].bondedTo()[a2i].bondedTo()[a3i].position().z(); sign = 1.0 if ((z > 0) and (y > 0)) or ((z < 0) and (y < 0)): sign = -1.0 vR03 = Vector(x,y,z); vR04 = Vector(0,1,0); rot03 = Rotation(Vector(1,0,0), sign*vR03.angle(vR04)); universe.applyTransformation(rot03); else: print "Molecule too little to be anchored";
def superpositionFit(confs): """ :param confs: the weight, reference position, and alternate position for each atom :type confs: sequence of (float, Vector, Vector) :returns: the quaternion representing the rotation, the center of mass in the reference configuration, the center of mass in the alternate configuraton, and the RMS distance after the optimal superposition """ w_sum = 0. wr_sum = N.zeros((3, ), N.Float) for w, r_ref, r in confs: w_sum += w wr_sum += w * r_ref.array ref_cms = wr_sum / w_sum pos = N.zeros((3, ), N.Float) possq = 0. cross = N.zeros((3, 3), N.Float) for w, r_ref, r in confs: w = w / w_sum r_ref = r_ref.array - ref_cms r = r.array pos = pos + w * r possq = possq + w*N.add.reduce(r*r) \ + w*N.add.reduce(r_ref*r_ref) cross = cross + w * r[:, N.NewAxis] * r_ref[N.NewAxis, :] k = N.zeros((4, 4), N.Float) k[0, 0] = -cross[0, 0] - cross[1, 1] - cross[2, 2] k[0, 1] = cross[1, 2] - cross[2, 1] k[0, 2] = cross[2, 0] - cross[0, 2] k[0, 3] = cross[0, 1] - cross[1, 0] k[1, 1] = -cross[0, 0] + cross[1, 1] + cross[2, 2] k[1, 2] = -cross[0, 1] - cross[1, 0] k[1, 3] = -cross[0, 2] - cross[2, 0] k[2, 2] = cross[0, 0] - cross[1, 1] + cross[2, 2] k[2, 3] = -cross[1, 2] - cross[2, 1] k[3, 3] = cross[0, 0] + cross[1, 1] - cross[2, 2] for i in range(1, 4): for j in range(i): k[i, j] = k[j, i] k = 2. * k for i in range(4): k[i, i] = k[i, i] + possq - N.add.reduce(pos * pos) from Scientific import LA e, v = LA.eigenvectors(k) i = N.argmin(e) v = v[i] if v[0] < 0: v = -v if e[i] <= 0.: rms = 0. else: rms = N.sqrt(e[i]) from Scientific.Geometry import Quaternion return Quaternion.Quaternion(v), Vector(ref_cms), \ Vector(pos), rms
def partitions(self): """Returns a list of cubic partitions. Each partition is specified by a tuple containing two vectors (describing the diagonally opposite corners) and the list of objects in the partition.""" list = [] for index, objects in self.partition.items(): min = Vector(index) * self.partition_size max = min + Vector(3 * [self.partition_size]) list.append((min, max, objects)) return list
def findTransformationAsQuaternion(self, conf1, conf2=None): universe = self.universe() if conf1.universe != universe: raise ValueError("conformation is for a different universe") if conf2 is None: conf1, conf2 = conf2, conf1 else: if conf2.universe != universe: raise ValueError("conformation is for a different universe") ref = conf1 conf = conf2 weights = universe.masses() weights = weights / self.mass() ref_cms = self.centerOfMass(ref).array pos = Numeric.zeros((3, ), Numeric.Float) possq = 0. cross = Numeric.zeros((3, 3), Numeric.Float) for a in self.atomList(): r = a.position(conf).array r_ref = a.position(ref).array - ref_cms w = weights[a] pos = pos + w * r possq = possq + w*Numeric.add.reduce(r*r) \ + w*Numeric.add.reduce(r_ref*r_ref) cross = cross + w * r[:, Numeric.NewAxis] * r_ref[Numeric.NewAxis, :] k = Numeric.zeros((4, 4), Numeric.Float) k[0, 0] = -cross[0, 0] - cross[1, 1] - cross[2, 2] k[0, 1] = cross[1, 2] - cross[2, 1] k[0, 2] = cross[2, 0] - cross[0, 2] k[0, 3] = cross[0, 1] - cross[1, 0] k[1, 1] = -cross[0, 0] + cross[1, 1] + cross[2, 2] k[1, 2] = -cross[0, 1] - cross[1, 0] k[1, 3] = -cross[0, 2] - cross[2, 0] k[2, 2] = cross[0, 0] - cross[1, 1] + cross[2, 2] k[2, 3] = -cross[1, 2] - cross[2, 1] k[3, 3] = cross[0, 0] + cross[1, 1] - cross[2, 2] for i in range(1, 4): for j in range(i): k[i, j] = k[j, i] k = 2. * k for i in range(4): k[i, i] = k[i, i] + possq - Numeric.add.reduce(pos * pos) from Scientific import LA e, v = LA.eigenvectors(k) i = Numeric.argmin(e) v = v[i] if v[0] < 0: v = -v if e[i] <= 0.: rms = 0. else: rms = Numeric.sqrt(e[i]) return Quaternion.Quaternion(v), Vector(ref_cms), \ Vector(pos), rms
def rigidMovement(atoms, vector): a = N.zeros((len(atoms), 3, 2, 3), N.Float) b = N.zeros((len(atoms), 3), N.Float) for i in range(len(atoms)): a[i, :, 0, :] = delta.array a[i, :, 1, :] = (epsilon * atoms[i].position()).array b[i] = vector[atoms[i]].array a.shape = (3 * len(atoms), 6) b.shape = (3 * len(atoms), ) vo = N.dot(LA.generalized_inverse(a), b) return Vector(vo[:3]), Vector(vo[3:])
def __init__(self,atoms,outfile=None): unitcell = atoms.get_cell() A = Vector(unitcell[0]) B = Vector(unitcell[1]) C = Vector(unitcell[2]) # lengths of the vectors a = A.length()#*angstroms2bohr b = B.length()#*angstroms2bohr c = C.length()#*angstroms2bohr # angles between the vectors rad2deg = 360./(2.*math.pi) alpha = B.angle(C)*rad2deg beta = A.angle(C)*rad2deg gamma = A.angle(B)*rad2deg scaledpositions = atoms.get_scaled_positions() chemicalsymbols = [atom.get_symbol() for atom in atoms] input = '' input += 'title \n' input += '0 tolerance\n' input += '2 lattice parameters in lengths and angles\n' input += '%1.3f %1.3f %1.3f %1.3f %1.3f %1.3f\n' % (a,b,c, alpha,beta,gamma) input += '1 3 basis vectors for unit cell\n' input += '1.00 0.00 0.00\n' input += '0.00 1.00 0.00\n' input += '0.00 0.00 1.00\n' input += '%i number of atoms\n' % len(atoms) types = '' for atom in atoms: types += str(atom.get_atomic_number()) + ' ' input += types + '\n' for i,atom in enumerate(atoms): input += '%1.3f %1.3f %1.3f\n' % tuple(scaledpositions[i]) pin,pout = os.popen2('findsym') pin.writelines(input) pin.close() self.output = pout.readlines() pout.close() if outfile: f = open(outfile,'w') f.writelines(self.output) f.close() if os.path.exists('findsym.log'): os.remove('findsym.log')
def boundingBox(self, conf=None): """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.""" atoms = self.atomList() min = atoms[0].position(conf).array max = min for a in atoms[1:]: r = a.position(conf).array min = Numeric.minimum(min, r) max = Numeric.maximum(max, r) return Vector(min), Vector(max)
def evaluatorParameters(self, universe, subset1, subset2, global_data): rsum = not self.options.get('no_reciprocal_sum', 0) if not universe.is_periodic and rsum: raise ValueError("Ewald method accepts only periodic universes") if not universe.is_orthogonal and rsum: raise ValueError("Ewald method implemented only for orthogonal universes") n = universe.numberOfPoints() charge = N.zeros((n,), N.Float) for o in universe: for a in o.atomList(): charge[a.index] = self._charge(o, a, global_data) charge = charge*N.sqrt(self.scale_factor) precision = self.options.get('ewald_precision', 1.e-6) p = N.sqrt(-N.log(precision)) if rsum: beta_opt = N.sqrt(N.pi) * \ (5.*universe.numberOfAtoms()/universe.cellVolume()**2)**(1./6.) max_cutoff = universe.largestDistance() beta_opt = max(p/max_cutoff, beta_opt) else: beta_opt = 0.01 options = {} options['beta'] = beta_opt options['real_cutoff'] = p/beta_opt options['reciprocal_cutoff'] = N.pi/(beta_opt*p) options['no_reciprocal_sum'] = 0 for key, value in self.options.items(): options[key] = value lx = universe.boxToRealCoordinates(Vector(1., 0., 0.)).length() ly = universe.boxToRealCoordinates(Vector(0., 1., 0.)).length() lz = universe.boxToRealCoordinates(Vector(0., 0., 1.)).length() kmax = N.array([lx,ly,lz])/options['reciprocal_cutoff'] kmax = N.ceil(kmax).astype(N.Int) excluded_pairs, one_four_pairs, atom_subset = \ self.excludedPairs(subset1, subset2, global_data) if atom_subset is not None: raise ValueError("Ewald summation not available for subsets") if options['no_reciprocal_sum']: kcutoff = 0. else: kcutoff = (2.*N.pi/options['reciprocal_cutoff'])**2 return {'electrostatic': {'algorithm': 'ewald', 'charge': charge, 'real_cutoff': options['real_cutoff'], 'reciprocal_cutoff': kcutoff, 'beta': options['beta'], 'k_max': kmax, 'one_four_factor': self.es_14_factor}, 'nonbonded': {'excluded_pairs': excluded_pairs, 'one_four_pairs': one_four_pairs, 'atom_subset': atom_subset} }
def _convertUnits(self): for residue in self.residues: for atom in residue: atom.position = atom.position * Units.Ang try: b = atom.properties['temperature_factor'] atom.properties['temperature_factor'] = b * Units.Ang**2 except KeyError: pass try: u = atom.properties['u'] atom.properties['u'] = u * Units.Ang**2 except KeyError: pass # All these attributes exist only if ScientificPython >= 2.7.5 is used. # The Scaling transformation was introduced with the same version, # so if it exists, the rest should work as well. try: from Scientific.Geometry.Transformation import Scaling except ImportError: return for attribute in ['a', 'b', 'c']: value = getattr(self, attribute) if value is not None: setattr(self, attribute, value * Units.Ang) for attribute in ['alpha', 'beta', 'gamma']: value = getattr(self, attribute) if value is not None: setattr(self, attribute, value * Units.deg) if self.to_fractional is not None: self.to_fractional = self.to_fractional * Scaling(1. / Units.Ang) v1 = self.to_fractional(Vector(1., 0., 0.)) v2 = self.to_fractional(Vector(0., 1., 0.)) v3 = self.to_fractional(Vector(0., 0., 1.)) self.reciprocal_basis = (Vector(v1[0], v2[0], v3[0]), Vector(v1[1], v2[1], v3[1]), Vector(v1[2], v2[2], v3[2])) else: self.reciprocal_basis = None if self.from_fractional is not None: self.from_fractional = Scaling(Units.Ang) * self.from_fractional self.basis = (self.from_fractional(Vector(1., 0., 0.)), self.from_fractional(Vector(0., 1., 0.)), self.from_fractional(Vector(0., 0., 1.))) else: self.basis = None for i in range(len(self.ncs_transformations)): tr = self.ncs_transformations[i] tr_new = Scaling(Units.Ang) * tr * Scaling(1. / Units.Ang) tr_new.given = tr.given tr_new.serial = tr.serial self.ncs_transformations[i] = tr_new for i in range(len(self.cs_transformations)): tr = self.cs_transformations[i] tr_new = Scaling(Units.Ang) * tr * Scaling(1. / Units.Ang) self.cs_transformations[i] = tr_new
def findPositions(self): # First atom at origin self.coordinates[self.data[0][0]] = Vector(0, 0, 0) # Second atom along x-axis self.coordinates[self.data[1][0]] = Vector(self.data[1][2], 0, 0) # Third atom in xy-plane try: pos1 = self.coordinates[self.data[2][1]] except KeyError: raise ValueError("atom %d has no defined position" % self.data[2][1].number) try: pos2 = self.coordinates[self.data[2][3]] except KeyError: raise ValueError("atom %d has no defined position" % self.data[2][3].number) sphere = Sphere(pos1, self.data[2][2]) cone = Cone(pos1, pos2 - pos1, self.data[2][4]) plane = Plane(Vector(0, 0, 0), Vector(0, 0, 1)) points = sphere.intersectWith(cone).intersectWith(plane) self.coordinates[self.data[2][0]] = points[0] # All following atoms defined by distance + angle + dihedral for entry in self.data[3:]: try: pos1 = self.coordinates[entry[1]] except KeyError: raise ValueError("atom %d has no defined position" % entry[1].number) try: pos2 = self.coordinates[entry[3]] except KeyError: raise ValueError("atom %d has no defined position" % entry[3].number) try: pos3 = self.coordinates[entry[5]] except KeyError: raise ValueError("atom %d has no defined position" % entry[5].number) distance = entry[2] angle = entry[4] dihedral = entry[6] sphere = Sphere(pos1, distance) cone = Cone(pos1, pos2 - pos1, angle) plane123 = Plane(pos3, pos2, pos1) points = sphere.intersectWith(cone).intersectWith(plane123) for p in points: if Plane(pos2, pos1, p).normal * plane123.normal > 0: break p = rotatePoint(p, Line(pos1, pos2 - pos1), dihedral) self.coordinates[entry[0]] = p
def test_P1(self): cell = UnitCell(Vector(1., 0., 0.), Vector(0., 1., 0.), Vector(0., 0., 1.)) res_max = 0.5 res_min = 10. reflections = ReflectionSet(cell, space_groups['P 1'], res_max, res_min, compact=self.compact) self.assert_(reflections.isComplete()) nr = sum([r.n_symmetry_equivalents for r in reflections]) + \ sum([r.n_symmetry_equivalents for r in reflections.systematic_absences]) self.assertEqual(reflections.totalReflectionCount(), nr) self.assert_(reflections.totalReflectionCount() == 2 * len(reflections.minimal_reflection_list)) for r in reflections: self.assert_(len(r.symmetryEquivalents()) == 2) self.assert_(res_max <= r.resolution() <= res_min) self.assert_(not r.isCentric()) self.assert_(r.symmetryFactor() == 1) self._shellTest(reflections) self._subsetTest(reflections) self._symmetryTest(reflections) self._intersectionTest(reflections) self._equalityTest(reflections) frozen = reflections.freeze() self.assert_(frozen is reflections.freeze()) self.assert_(frozen is frozen.freeze()) self.assert_(frozen.isComplete()) self.assert_(frozen.totalReflectionCount() == 2 * len(frozen._reflections)) for r in frozen: self.assert_(reflections.hasReflection(r.h, r.k, r.l)) self.assert_(len(r.symmetryEquivalents()) == 2) self.assert_(res_max <= r.resolution() <= res_min) self.assert_(not r.isCentric()) self.assert_(r.symmetryFactor() == 1) for r in reflections: self.assert_(frozen.hasReflection(r.h, r.k, r.l)) self.assert_(r.index == frozen[(r.h, r.k, r.l)].index) self._shellTest(frozen) self._subsetTest(frozen) self._symmetryTest(frozen) self._intersectionTest(frozen) self._equalityTest(frozen)
def __init__(self, universe, rigid_bodies): """ :param universe: the universe for which the subspace is created :type universe: :class:~MMTK.Universe.Universe :param rigid_bodies: a list or set of rigid bodies with some common atoms """ ex_ey_ez = [Vector(1.,0.,0.), Vector(0.,1.,0.), Vector(0.,0.,1.)] # Constructs # 1) a list of vectors describing the rigid-body motions of each # rigid body as if it were independent. # 2) a list of pair-distance constraint vectors for all pairs of # atoms inside a rigid body. # The LRB subspace is constructed from the projections of the # first set of vectors onto the orthogonal complement of the # subspace generated by the second set of vectors. vectors = [] c_vectors = [] for rb in rigid_bodies: atoms = rb.atomList() for d in ex_ey_ez: v = ParticleProperties.ParticleVector(universe) for a in atoms: v[a] = d vectors.append(v) if len(atoms) > 1: center = rb.centerOfMass() iv = len(vectors)-3 for d in ex_ey_ez: v = ParticleProperties.ParticleVector(universe) for a in atoms: v[a] = d.cross(a.position()-center) for vt in vectors[iv:]: v -= v.dotProduct(vt)*vt if v.dotProduct(v) > 0.: vectors.append(v) for a1, a2 in Utility.pairs(atoms): distance = universe.distanceVector(a1.position(), a2.position()) v = ParticleProperties.ParticleVector(universe) v[a1] = distance v[a2] = -distance c_vectors.append(v) if c_vectors: constraints = Subspace(universe, c_vectors) vectors = [constraints.projectionComplementOf(v) for v in vectors] Subspace.__init__(self, universe, vectors)
def getPosition(self, atom_id): """ :param atom_id: id of the atom whose position is requested :return: the position of the atom :rtype: Scientific.Geometry.Vector """ return Vector(self.positions[self.id_dict[atom_id]])
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 writeSpecification(self, file): d = 0.5 * self.edge semi_diag = Vector(d, d, d) file.writeString('.box') file.writeVector((self.center - semi_diag) * file.scale) file.writeVector((self.center + semi_diag) * file.scale) file.writeString('\n')
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 cell_parameters(atoms, weight=1.0, cells=None): ''' adds entries to CELL PARAMETERS for the unit cell geometry of the atoms object. ''' description = reax_hash(atoms) # get all the parameters needed for a cell parameters block uc = atoms.get_cell() a, b, c = [Vector(x) for x in uc] A = a.length() B = b.length() C = c.length() rad2deg = 360. / (2 * math.pi) alpha = b.angle(c) * rad2deg beta = a.angle(c) * rad2deg gamma = a.angle(b) * rad2deg cells['CELL PARAMETERS'].append('# created by reax.trainset') # this is an org-link to the geo file #cells['CELL PARAMETERS'].append('# file:geo::%s' % description) for key, val in [('a', A), ('b', B), ('c', C), ('alpha', alpha), ('beta', beta), ('gamma', gamma)]: s = '%(description)s %(weight)f %(key)s %(val)s' % locals() if s not in cells['CELL PARAMETERS']: cells['CELL PARAMETERS'].append(s) return cells
def gradientTest(universe, atoms=None, delta=0.0001): """ Test gradients by comparing to numerical derivatives of the energy. :param universe: the universe on which the test is performed :type universe: :class:`~MMTK.Universe.Universe` :param atoms: the atoms of the universe for which the gradient is tested (default: all atoms) :type atoms: list :param delta: the step size used in calculating the numerical derivatives :type delta: float """ e0, grad = universe.energyAndGradients() print 'Energy: ', e0 if atoms is None: atoms = universe.atomList() for a in atoms: print a print grad[a] num_grad = [] for v in [ex, ey, ez]: x = a.position() a.setPosition(x + delta * v) eplus = universe.energy() a.setPosition(x - delta * v) eminus = universe.energy() a.setPosition(x) num_grad.append(0.5 * (eplus - eminus) / delta) print Vector(num_grad)
def parseAtom(self, element): atom_spec = { 'atom_id': element.get('id', None), 'element': element.find(self.prefix + 'type_symbol').text, 'name': element.find(self.prefix + 'label_atom_id').text, 'alt_id': element.find(self.prefix + 'label_alt_id').text, 'model': int(element.find(self.prefix + 'pdbx_PDB_model_num').text), 'comp_id': element.find(self.prefix + 'label_comp_id').text, 'asym_id': element.find(self.prefix + 'label_asym_id').text, 'entity_id': element.find(self.prefix + 'label_entity_id').text, 'position': Vector(float(element.find(self.prefix + 'Cartn_x').text), float(element.find(self.prefix + 'Cartn_y').text), float(element.find(self.prefix + 'Cartn_z').text)), 'occupancy': float(element.find(self.prefix + 'occupancy').text), 'beta': float(element.find(self.prefix + 'B_iso_or_equiv').text), } seq_id = element.find(self.prefix + 'label_seq_id').text if seq_id is None: atom_spec['seq_id'] = None else: atom_spec['seq_id'] = int(seq_id) return atom_spec
def __init__(self, elementary_cell, lattice_vectors, cells, function=None, base=None): """ @param elementary_cell: a list of the points in the elementary cell @type elementary_cell: C{list} of L{Scientific.Geometry.Vector} @param lattice_vectors: the edges of the elementary cell @type lattice_vectors: C{tuple} of three L{Scientific.Geometry.Vector} @param cells: a tuple of three integers, indicating how often the elementary cell should be replicated along each lattice vector @param cells: C{tuple} of C{int} @param function: the function to be applied to each point in the lattice in order to obtain the value stored in the lattice. If no function is specified, the point itself becomes the value stored in the lattice. @type function: callable @param base: an offset added to all lattice points @type base: L{Scientific.Geometry.Vector} """ 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 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, 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 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,atoms,outfile=None): unitcell = atoms.get_cell() A = Vector(unitcell[0]) B = Vector(unitcell[1]) C = Vector(unitcell[2]) # lengths of the vectors a = A.length()#*angstroms2bohr b = B.length()#*angstroms2bohr c = C.length()#*angstroms2bohr # angles between the vectors rad2deg = 360./(2.*math.pi) alpha = B.angle(C)*rad2deg beta = A.angle(C)*rad2deg gamma = A.angle(B)*rad2deg scaledpositions = atoms.get_scaled_positions() chemicalsymbols = [atom.get_symbol() for atom in atoms] input = '' input += '%1.3f %1.3f %1.3f %1.3f %1.3f %1.3f\n' % (a,b,c, alpha,beta,gamma) input += '1 1 0.1 0.1\n' for atom in atoms: sym = atom.get_symbol() group = 1 x,y,z = atom.get_position() #format(a6,i2,6f9.5) input += str(FortranLine((sym, group, x,y,z), FortranFormat('a6,i2,3f9.5')))+'\n' pin,pout = os.popen2('symmol') pin.writelines(input) pin.close() self.output = pout.readlines() pout.close() if outfile: f = open(outfile,'w') f.writelines(self.output) f.close() if os.path.exists('symmol.log'): os.remove('symmol.log')
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 set_axis(self, axis): try: self._axis = Vector(axis) except (TypeError,ValueError): raise ProjectorError('Wrong axis definition: must be a sequence of 3 floats') try: self._axis = self._axis.normal() except ZeroDivisionError: raise ProjectorError('The axis vector can not be the null vector') self._projectionMatrix = numpy.identity(3) - numpy.outer(self._axis, self._axis)
class PlanarProjector(IProjector): type = 'planar' def set_axis(self, axis): try: self._axis = Vector(axis) except (TypeError,ValueError): raise ProjectorError('Wrong axis definition: must be a sequence of 3 floats') try: self._axis = self._axis.normal() except ZeroDivisionError: raise ProjectorError('The axis vector can not be the null vector') self._projectionMatrix = numpy.identity(3) - numpy.outer(self._axis, self._axis) def __call__(self, value): try: return numpy.dot(value,self._projectionMatrix.T) except (TypeError,ValueError): raise ProjectorError("Invalid data to apply projection on")
''' Gstar = np.dot(G, G.T) id2 = np.dot(hkl, np.dot(Gstar, hkl)) print('d_111 spacing (method 2) =',np.sqrt(1 / id2)) # http://books.google.com/books?id=nJHSqEseuIUC&lpg=PA118&ots=YA9TBldoVH # &dq=reciprocal%20metric%20tensor&pg=PA119#v=onepage # &q=reciprocal%20metric%20tensor&f=false '''Finally, many text books on crystallography use long algebraic formulas for computing the d-spacing with sin and cos, vector lengths, and angles. Below we compute these and use them in the general triclinic structure formula which applies to all the structures. ''' from Scientific.Geometry import Vector import math unitcell = ag.get_cell() A = Vector(unitcell[0]) B = Vector(unitcell[1]) C = Vector(unitcell[2]) # lengths of the vectors a = A.length()#*angstroms2bohr b = B.length()#*angstroms2bohr c = C.length()#*angstroms2bohr # angles between the vectors in radians alpha = B.angle(C) beta = A.angle(C) gamma = A.angle(B) print('') print('a b c alpha beta gamma') print('{0:1.3f} {1:1.3f} {2:1.3f} {3:1.3f} {4:1.3f} {5:1.3f}\n'.format(a,b,c, alpha,beta,gamma)) h, k, l = (1, 1, 1) from math import sin, cos
import numpy as np from Scientific.Geometry import Vector A = Vector([1,1,1]) #Scientfic a = np.array([1,1,1]) #numpy B = Vector([0.0,1.0,0.0]) print '|A| = ',A.length() #Scientific Python way print '|a| = ',np.sum(a**2)**0.5 #numpy way print '|a| = ',np.linalg.norm(a) #numpy way 2 print 'ScientificPython angle = ',A.angle(B) #in radians print 'numpy angle = ',np.arccos(np.dot(a/np.linalg.norm(a),B/np.linalg.norm(B))) #cross products print 'Scientific A .cross. B = ',A.cross(B) print 'numpy A .cross. B = ',np.cross(A,B) #you can use Vectors in numpy
def pretty_print(self): ''' __str__ function to print the calculator with a nice summary, e.g. jaspsum ''' # special case for neb calculations if self.int_params['images'] is not None: # we have an neb. s = [] s.append(': -----------------------------') s.append(' VASP NEB calculation from %s' % os.getcwd()) try: images, energies = self.get_neb() for i,e in enumerate(energies): s += ['image {0}: {1: 1.3f}'.format(i,e)] except (VaspQueued): s += ['Job is in queue'] return '\n'.join(s) s = [] s.append(': -----------------------------') s.append(' VASP calculation from %s' % os.getcwd()) if hasattr(self,'converged'): s.append(' converged: %s' % self.converged) try: atoms = self.get_atoms() uc = atoms.get_cell() try: self.converged = self.read_convergence() except IOError: # eg no outcar self.converged = False if not self.converged: try: print self.read_relaxed() except IOError: print False if self.converged: energy = atoms.get_potential_energy() forces = atoms.get_forces() else: energy = np.nan forces = [np.array([np.nan, np.nan, np.nan]) for atom in atoms] if self.converged: if hasattr(self,'stress'): stress = self.stress else: stress = None else: stress = None # get a,b,c,alpha,beta, gamma from Scientific.Geometry import Vector A = Vector(uc[0,:]) B = Vector(uc[1,:]) C = Vector(uc[2,:]) a = A.length() b = B.length() c = C.length() alpha = B.angle(C)*180/np.pi beta = A.angle(C)*180/np.pi gamma = B.angle(C)*180/np.pi volume = atoms.get_volume() s.append(' Energy = %f eV' % energy) s.append('\n Unit cell vectors (angstroms)') s.append(' x y z length') s.append(' a0 [% 3.3f % 3.3f % 3.3f] %3.3f' % (uc[0][0], uc[0][1], uc[0][2], A.length())) s.append(' a1 [% 3.3f % 3.3f % 3.3f] %3.3f' % (uc[1][0], uc[1][1], uc[1][2], B.length())) s.append(' a2 [% 3.3f % 3.3f % 3.3f] %3.3f' % (uc[2][0], uc[2][1], uc[2][2], C.length())) s.append(' a,b,c,alpha,beta,gamma (deg): %1.3f %1.3f %1.3f %1.1f %1.1f %1.1f' % (a, b, c, alpha, beta,gamma)) s.append(' Unit cell volume = {0:1.3f} Ang^3'.format(volume)) if stress is not None: s.append(' Stress (GPa):xx, yy, zz, yz, xz, xy') s.append(' % 1.3f % 1.3f % 1.3f % 1.3f % 1.3f % 1.3f' % tuple(stress)) else: s += [' Stress was not computed'] constraints = None if hasattr(atoms, 'constraints'): from ase.constraints import FixAtoms, FixScaled constraints = [[None, None, None] for atom in atoms] for constraint in atoms.constraints: if isinstance(constraint, FixAtoms): for i, constrained in enumerate(constraint.index): if constrained: constraints[i] = [True, True, True] if isinstance(constraint, FixScaled): constraints[constraint.a] = constraint.mask.tolist() if constraints is None: s.append(' Atom# sym position [x,y,z] tag rmsForce') else: s.append(' Atom# sym position [x,y,z] tag rmsForce constraints') for i,atom in enumerate(atoms): rms_f = np.sum(forces[i]**2)**0.5 ts = ' {0:^4d} {1:^4s} [{2:<9.3f}{3:^9.3f}{4:9.3f}] {5:^6d}{6:1.2f}'.format(i, atom.symbol, atom.x, atom.y, atom.z, atom.tag, rms_f) # VASP has the opposite convention of constrained # Think: F = frozen if constraints is not None: ts += ' {0} {1} {2}'.format('F' if constraints[i][0] is True else 'T', 'F' if constraints[i][1] is True else 'T', 'F' if constraints[i][2] is True else 'T') s.append(ts) s.append('--------------------------------------------------') if self.get_spin_polarized() and self.converged: s.append('Spin polarized: Magnetic moment = %1.2f' % self.get_magnetic_moment(atoms)) except AttributeError: # no atoms pass if os.path.exists('INCAR'): # print all parameters that are set self.read_incar() ppp_list = self.get_pseudopotentials() else: ppp_list=[(None, None, None)] s += ['\nINCAR Parameters:'] s += ['-----------------'] for d in [self.int_params, self.float_params, self.exp_params, self.bool_params, self.list_params, self.dict_params, self.string_params, self.special_params, self.input_params]: for key in d: if key is 'magmom': np.set_printoptions(precision=3) value = textwrap.fill(str(d[key]), width=56, subsequent_indent=' '*17) s.append(' %12s: %s' % (key, value)) elif d[key] is not None: value = textwrap.fill(str(d[key]), width=56, subsequent_indent=' '*17) s.append(' %12s: %s' % (key, value)) s += ['\nPseudopotentials used:'] s += ['----------------------'] for sym,ppp,hash in ppp_list: s += ['{0}: {1} (git-hash: {2})'.format(sym,ppp,hash)] # if ibrion in [5,6,7,8] print frequencies if self.int_params['ibrion'] in [5,6,7,8]: freq,modes = self.get_vibrational_modes() s += ['\nVibrational frequencies'] s += ['mode frequency'] s += ['------------------'] for i,f in enumerate(freq): if isinstance(f, float): s += ['{0:4d}{1: 10.3f} eV'.format(i,f)] elif isinstance(f, complex): s += ['{0:4d}{1: 10.3f} eV'.format(i,-f.real)] return '\n'.join(s)
natoms = len(atoms) try: x, V0, e0, B = analyze_eos() except TypeError: x, V0, e0, B = None, None, None, None magmom = atoms.get_magnetic_moment() # now we want to write out a row of data = [id1, composition, spacegroup, natoms, formation_energy, B, magmom] for i, d in enumerate(data): sh0.write(NROWS0, i, d) # now for sheet 1 - unit cell parameters uc = atoms.get_cell() A = Vector(uc[0, :]) B = Vector(uc[1, :]) C = Vector(uc[2, :]) a = A.length() b = B.length() c = C.length() alpha = B.angle(C) * 180.0 / np.pi beta = A.angle(C) * 180.0 / np.pi gamma = B.angle(C) * 180.0 / np.pi volume = atoms.get_volume() stress = atoms.get_stress() if stress is not None: sxx, syy, szz, sxy, syz, sxz = stress else: sxx, syy, szz, sxy, syz, sxz = [None, None, None, None, None, None]
"""testing to see in what order the points in sketchup are given Results: Right hand corkscrew in the direction of the normal""" from Scientific.Geometry import Vector import readsketchup import geometry txt = open('e.txt', 'r').read() dct = readsketchup.readsketchup(txt) for key in dct.keys(): plane = dct[key]['points'] normal = Vector(dct[key]['normal']) calcnormal = geometry.facenormal(plane) # print normal # print calcnormal print normal.angle(calcnormal) print