Пример #1
0
    def __init__(self, atomlist):
        # convert the list of atoms into a list of 3d points
        nat = len(atomlist)
        pos = XYZ.atomlist2vector(atomlist)
        points = []
        for i in range(0, nat):
            points.append(pos[3 * i:3 * (i + 1)])
        # QHull needs at least 4 point to construct the initial
        # simplex.
        if nat < 4:
            # If there are less than 4 atoms,
            # we add the center of mass as an additional point
            masses = AtomicData.atomlist2masses(atomlist)
            com = MolCo.center_of_mass(masses, pos)
            points.append(com)
        if nat < 3:
            # If there are less than 3 atoms we add
            # an arbitrary point on the x-axis
            points.append(com + np.array([0.0005, 0.0, 0.0]))
        if nat < 2:
            # If there is only one atom, we add another arbitrary
            # point on the y-axis
            points.append(com + np.array([0.0, 0.0005, 0.0]))
        # We add small random numbers to the input coordinates, so that
        # we get a 3D convex hull even if the molecule is planar
        points = np.array(points) + 0.0001 * np.random.rand(len(points), 3)
        # find the convex hull using the qhull code
        hull = ConvexHull(points, qhull_options="QbB Qt")

        # call the constructor of the parent class (MinimalEnclosingBox)
        super(MoleculeBox, self).__init__(hull)
Пример #2
0
    def _update_visualization(self, atomlist, charges, fragments):
        """
        only change the underlying data but do not recreate visualization.
        This is faster and avoids jerky animations.
        """
        mlab = self.scene.mlab
        if self.show_flags["charges"] == True:
            i = 0
            for q,(Z,pos) in zip(charges, atomlist):
                x,y,z = pos
                if q < 0.0:
                    color = (0.,0.,1.)
                elif q > 0.0:
                    color = (1.,0.,0.)
                else:
                    color = (1.,1.,1.)
                # color does not work so far
                txt = "%+2.3f" % q
                if self.show_flags["labels"] == True:
                    # maybe charges should not overlap with labels
                    txt = "%s" % txt
                # update label position and text
                label = self.charge_labels[i]
                label.remove()
                label = mlab.text(x,y, txt, z=z, figure=self.scene.mayavi_scene)
                self.charge_labels[i] = label
                label.actor.set(text_scale_mode='none', width=0.05, height=0.1)
                label.property.set(justification='centered', vertical_justification='centered')

                i += 1
        if self.show_flags["frag. charges"] == True:
            i = 0
            for ifrag,(fragment_indeces, fragment_atomlist) in enumerate(fragments):
                # compute the charges on fragment 
                qfrag = np.sum(charges[fragment_indeces])
                print "Fragment charges: %s" % charges[fragment_indeces]
                # compute the center of the molecule,
                pos_frag = XYZ.atomlist2vector(fragment_atomlist)
                masses_frag = AtomicData.atomlist2masses(fragment_atomlist)
                com = MolCo.center_of_mass(masses_frag, pos_frag)
                #
                print "Fragment %d  charge = %s" % (ifrag, qfrag)
                txt = "%+2.3f" % qfrag
                label = self.frag_charge_labels[i]
                label.remove()
                label = mlab.text(com[0],com[1], txt, z=com[2], line_width=0.8, figure=self.scene.mayavi_scene)
                self.frag_charge_labels[i] = label
                label.actor.set(text_scale_mode='none', width=0.05, height=0.1)
                label.property.set(justification='centered', vertical_justification='centered')

                i += 1
        if self.show_flags["charge clouds"] == True:

            vec = XYZ.atomlist2vector(atomlist)
            x, y, z = vec[::3], vec[1::3], vec[2::3]
            s = abs(charges)

            # The charge clouds represent surfaces of equal charge density around each atoms.
            # In DFTB the charge fluctuations are modelled by a Gaussian:
            #  F(r) = 1/(2*pi*sA^2)^(3/2) * exp(-r^2/(2*sA^2))
            # The radii of the charge clouds are scaled by the charge on the atom:
            #  r = q * r0
            # The radius r0 belongs to a charge cloud containing exactly 1 electron, it depends
            # on the hubbard parameter through sA and on the isoValue:
            #  F(r0) = F(0) * isoValue
            #
            r0s = self.charge_cloud_radii.getRadii(atomlist)
            s *= r0s

            self.cloud.mlab_source.set(x=x,y=y,z=z,u=s,v=s,w=s, scalars=charges, scale_factor=1.0)
            # atoms are coloured by their atomic number
            self.cloud.glyph.color_mode = "color_by_scalar"
            self.cloud.glyph.glyph_source.glyph_source.center = [0,0,0]
            self.cloud.module_manager.scalar_lut_manager.lut.table = self.lut
            self.cloud.module_manager.scalar_lut_manager.data_range = (-1.0, 1.0)
Пример #3
0
    def _create_visualization(self, atomlist, charges, fragments):
        mlab = self.scene.mlab
        
        if self.show_flags["charges"] == True and type(charges) != type(None):
            self.charge_labels = []
            for q,(Z,pos) in zip(charges, atomlist):
                x,y,z = pos
                if q < 0.0:
                    color = (0.,0.,1.)
                elif q > 0.0:
                    color = (1.,0.,0.)
                else:
                    color = (1.,1.,1.)
                # color does not work so far
                txt = "%+2.3f" % q
                if self.show_flags["labels"] == True:
                    # maybe charges should not overlap with labels
                    txt = "%s" % txt
                label = mlab.text(x,y, txt, z=z, figure=self.scene.mayavi_scene)
                label.actor.set(text_scale_mode='none', width=0.05, height=0.1)
                label.property.set(justification='centered', vertical_justification='centered')
                self.charge_labels.append( label )
            self.shown_charges = True
        else:
            self.shown_charges = False
            
        if self.show_flags["frag. charges"] == True and type(charges) != type(None):
            self.frag_charge_labels = []
            for ifrag,(fragment_indeces, fragment_atomlist, fragment_box) in enumerate(fragments):
                # compute the charges on fragment 
                qfrag = np.sum(charges[fragment_indeces])
                print "Fragment charges: %s" % charges[fragment_indeces]
                # compute the center of the molecule,
                pos_frag = XYZ.atomlist2vector(fragment_atomlist)
                masses_frag = AtomicData.atomlist2masses(fragment_atomlist)
                com = MolCo.center_of_mass(masses_frag, pos_frag)
                #
                print "Fragment %d  charge = %s" % (ifrag, qfrag)
                txt = "%+2.3f" % qfrag
                label = mlab.text(com[0],com[1], txt, z=com[2], line_width=0.8, figure=self.scene.mayavi_scene)
                label.actor.set(text_scale_mode='none', width=0.05, height=0.1)
                label.property.set(justification='centered', vertical_justification='centered')
                self.frag_charge_labels.append( label )
            self.shown_frag_charges = True
        else:
            self.shown_frag_charges = False
            
        if self.show_flags["charge clouds"] == True and type(charges) != type(None):
            self.charge_clouds = []

            vec = XYZ.atomlist2vector(atomlist)
            x, y, z = vec[::3], vec[1::3], vec[2::3]
            s = abs(charges)

            # The charge clouds represent surfaces of equal charge density around each atoms.
            # In DFTB the charge fluctuations are modelled by a Gaussian:
            #  F(r) = 1/(2*pi*sA^2)^(3/2) * exp(-r^2/(2*sA^2))
            # The radii of the charge clouds are scaled by the charge on the atom:
            #  r = q * r0
            # The radius r0 belongs to a charge cloud containing exactly 1 electron, it depends
            # on the hubbard parameter through sA and on the isoValue:
            #  F(r0) = F(0) * isoValue
            #
            r0s = self.charge_cloud_radii.getRadii(atomlist)
            s *= r0s
            
            cloud = mlab.quiver3d(x,y,z,s,s,s, scalars=charges, 
                                           mode="sphere", scale_factor=1.0, resolution=20,
                                           opacity = 0.4, 
                                           figure=self.scene.mayavi_scene)

            # atoms are coloured by their atomic number
            cloud.glyph.color_mode = "color_by_scalar"
            cloud.glyph.glyph_source.glyph_source.center = [0,0,0]
            self.lut = cloud.module_manager.scalar_lut_manager.lut.table.to_array()
            red = np.array((255.0, 0.0, 0.0)).astype('uint8')
            blue = np.array((0.0, 0.0, 255.0)).astype('uint8')
            for i in range(0, 255):
                if i < 128:
                    color = blue
                else:
                    color = red
                self.lut[i,0:3] = color
            cloud.module_manager.scalar_lut_manager.lut.table = self.lut
            cloud.module_manager.scalar_lut_manager.data_range = (-1.0, 1.0)

            self.cloud = cloud
            self.charge_clouds.append( cloud )
            
            self.shown_charge_clouds = True
            
        else:
            self.shown_charge_clouds = False

        if self.show_flags["dipole moment"] == True and type(charges) != type(None):
            self.dipole_vectors = []
            # The dipole vector is placed at the center of mass
            pos = XYZ.atomlist2vector(atomlist)
            masses = AtomicData.atomlist2masses(atomlist)
            com = MolCo.center_of_mass(masses, pos)
            # compute dipole moment from charge distribution
            dipole = np.zeros(3)
            for i,q in enumerate(charges):
                dipole += q * pos[3*i:3*(i+1)]
            print "Dipole moment  D = %s a.u." % dipole
            # For plotting the dipole vector is converted to Debye
            dipole *= AtomicData.ebohr_to_debye
            print "Dipole moment  D = %s Debye" % dipole
            print "Length of dipole moment |D| = %s Debye" % la.norm(dipole)
            
            quiver3d = mlab.quiver3d(com[0],com[1],com[2],
                                     dipole[0], dipole[1], dipole[2], line_width=5.0,
                                     scale_mode='vector',
                                     color=(0,0,1), 
                                     scale_factor=1.0)
            
            self.dipole_vectors.append(quiver3d)
        else:
            self.shown_dipole_moment = False    
            
        if self.show_flags["enclosing box"] == True:
            self.frag_enclosing_boxes = []
            for ifrag,(fragment_indeces, fragment_atomlist, fragment_box) in enumerate(fragments):
                box = fragment_box
                # plot edges of the enclosing box
                for edge in box.edges:
                    l = mlab.plot3d(box.vertices[edge,0], box.vertices[edge,1], box.vertices[edge,2],
                                    color=(1,0,0),
                                    figure=self.scene.mayavi_scene)
                    self.frag_enclosing_boxes.append(l)
                # plot axes
                for axis, color in zip(box.axes, [(1.,0.,0.),(0.,1.,0.), (0.,0.,1.)]):
                    ax = mlab.quiver3d(float(box.center[0]), float(box.center[1]), float(box.center[2]),
                                       float(axis[0]), float(axis[1]), float(axis[2]),
                                       color=color, scale_factor=3.0, mode='arrow', resolution=20,
                                       figure=self.scene.mayavi_scene)
                    self.frag_enclosing_boxes.append(ax)
            self.shown_enclosing_boxes = True
        else:
            self.shown_enclosing_boxes = False    

        if self.show_flags["screening charges (COSMO)"] == True:
            # read parameter for solvent model from command line
            # or configuration file
            parser = OptionParserFuncWrapper([ImplicitSolvent.SolventCavity.__init__], "",
                                             unknown_options="ignore")
            # extract only arguments for constructor of solvent cavity
            (solvent_options, args) = parser.parse_args(ImplicitSolvent.SolventCavity.__init__)
            # 
            cavity = ImplicitSolvent.SolventCavity(**solvent_options)
            cavity.constructSAS(atomlist)
            area = cavity.getSurfaceArea()
            print "solvent accessible surface area: %8.6f bohr^2   %8.6f Ang^2" % (area, area*AtomicData.bohr_to_angs**2)
            points = cavity.getSurfacePoints()
            x,y,z = points[:,0], points[:,1], points[:,2]
            if type(charges) != type(None):
                # If there are Mulliken charges we can compute the
                # induced charges on the surface of the cavity
                # according to COSMO
                cavity.constructCOSMO()
                induced_charges = cavity.getInducedCharges(charges)
                screening_energy = cavity.getScreeningEnergy(charges)
                print "screening energy: %10.6f Hartree  %10.6f kcal/mol" \
                    % (screening_energy, screening_energy * AtomicData.hartree_to_kcalmol)
                # The surface points are colored and scaled
                # according to their charge
                #  negative -> blue   positive -> red
                points3d = mlab.points3d(x,y,z,induced_charges,
                                         colormap="blue-red",
                                         mode='2dcross',
                                         scale_factor=10)
#                                         mode='2dvertex')
                points3d.glyph.color_mode = "color_by_scalar"
            else:
                # 
                points3d = mlab.points3d(x,y,z,color=(0.0,0.0,0.8), mode='2dvertex')
            self.sas_points.append( points3d )
        else:
            self.shown_solvent_screening_charges = False

        if self.show_flags["non-adiab. coupling vectors"] == True:
            vec = XYZ.atomlist2vector(atomlist)
            x, y, z = vec[::3], vec[1::3], vec[2::3]
            
            # assume that charges are transition charges
            transition_charges = charges
            
            # Because we don't know the energy here, the energy difference
            # in the denominator is set to 1, so only the direction and relative
            # lengths are correct.
            nac = NACsApprox.coupling_vector(atomlist, transition_charges, 1.0)
            # directions of NAC vectors
            u,v,w = nac[0,:], nac[1,:], nac[2,:]
            # Add a NAC vector at each atom
            quiver3d = mlab.quiver3d(x,y,z, u,v,w, line_width=5.0)
            
            self.nac_vectors.append(quiver3d)
            
        else:
            self.shown_nacs = False