Beispiel #1
0
//EulerRotateAbout uses Euler angles to rotate the coordinates in coordsorig around by angle
//radians around the axis given by the vector axis. It returns the rotated coordsorig,
//since the original is not affected. It seems more clunky than the RotateAbout, which uses Clifford algebra.
//I leave it for benchmark, mostly, and might remove it later. There is no test for this function!
func EulerRotateAbout(coordsorig, ax1, ax2 *v3.Matrix, angle float64) (*v3.Matrix, error) {
	r, _ := coordsorig.Dims()
	coords := v3.Zeros(r)
	translation := v3.Zeros(ax1.NVecs())
	translation.Copy(ax1)
	axis := v3.Zeros(ax2.NVecs())
	axis.Sub(ax2, ax1) //now it became the rotation axis
	f := func() { coords.SubVec(coordsorig, translation) }
	if err := gnMaybe(gnPanicker(f)); err != nil {
		return nil, CError{err.Error(), []string{"v3.Matrix.Subvec", "EulerRotateAbout"}}

	}
	Zswitch := RotatorToNewZ(axis)
	coords.Mul(coords, Zswitch) //rotated
	Zrot, err := RotatorAroundZ(angle)
	if err != nil {
		return nil, errDecorate(err, "EulerRotateAbout")
	}
	//	Zsr, _ := Zswitch.Dims()
	//	RevZ := v3.Zeros(Zsr)
	RevZ, err := gnInverse(Zswitch)
	if err != nil {
		return nil, errDecorate(err, "EulerRotateAbout")
	}
	coords.Mul(coords, Zrot) //rotated
	coords.Mul(coords, RevZ)
	coords.AddVec(coords, translation)
	return coords, nil
}
Beispiel #2
0
func EncodeCoords(coords *v3.Matrix, enc *json.Encoder) *Error {
	c := new(Coords)
	t := make([]float64, 3, 3)
	for i := 0; i < coords.NVecs(); i++ {
		c.Coords = coords.Row(t, i)
		if err := enc.Encode(c); err != nil {
			return NewError("postprocess", "chemjson.EncodeCoords", err)
		}
	}
	return nil
}
Beispiel #3
0
//SelCone, Given a set of cartesian points in sellist, obtains a vector "plane" normal to the best plane passing through the points.
//It selects atoms from the set A that are inside a cone in the direction of "plane" that starts from the geometric center of the cartesian points,
//and has an angle of angle (radians), up to a distance distance. The cone is approximated by a set of radius-increasing cilinders with height thickness.
//If one starts from one given point, 2 cgnOnes, one in each direction, are possible. If whatcone is 0, both cgnOnes are considered.
//if whatcone<0, only the cone opposite to the plane vector direction. If whatcone>0, only the cone in the plane vector direction.
//the 'initial' argument  allows the construction of a truncate cone with a radius of initial.
func SelCone(B, selection *v3.Matrix, angle, distance, thickness, initial float64, whatcone int) []int {
	A := v3.Zeros(B.NVecs())
	A.Copy(B) //We will be altering the input so its better to work with a copy.
	ar, _ := A.Dims()
	selected := make([]int, 0, 3)
	neverselected := make([]int, 0, 30000)     //waters that are too far to ever be selected
	nevercutoff := distance / math.Cos(angle)  //cutoff to be added to neverselected
	A, _, err := MassCenter(A, selection, nil) //Centrate A in the geometric center of the selection, Its easier for the following calculations
	if err != nil {
		panic(PanicMsg(err.Error()))
	}
	selection, _, _ = MassCenter(selection, selection, nil) //Centrate the selection as well
	plane, err := BestPlane(selection, nil)                 //I have NO idea which direction will this vector point. We might need its negative.
	if err != nil {
		panic(PanicMsg(err.Error()))
	}
	for i := thickness / 2; i <= distance; i += thickness {
		maxdist := math.Tan(angle)*i + initial //this should give me the radius of the cone at this point
		for j := 0; j < ar; j++ {
			if isInInt(selected, j) || isInInt(neverselected, j) { //we dont scan things that we have already selected, or are too far
				continue
			}
			atom := A.VecView(j)
			proj := Projection(atom, plane)
			norm := proj.Norm(0)
			//Now at what side of the plane is the atom?
			angle := Angle(atom, plane)
			if whatcone > 0 {
				if angle > math.Pi/2 {
					continue
				}
			} else if whatcone < 0 {
				if angle < math.Pi/2 {
					continue
				}
			}
			if norm > i+(thickness/2.0) || norm < (i-thickness/2.0) {
				continue
			}
			proj.Sub(proj, atom)
			projnorm := proj.Norm(0)
			if projnorm <= maxdist {
				selected = append(selected, j)
			}
			if projnorm >= nevercutoff {
				neverselected = append(neverselected, j)
			}
		}
	}
	return selected
}
Beispiel #4
0
//XYZStringWrite writes the mol Ref and the Coord coordinates in an XYZ-formatted string.
func XYZStringWrite(Coords *v3.Matrix, mol Atomer) (string, error) {
	var out string
	if mol.Len() != Coords.NVecs() {
		return "", CError{"Ref and Coords dont have the same number of atoms", []string{"XYZStringWrite"}}
	}
	c := make([]float64, 3, 3)
	out = fmt.Sprintf("%-4d\n\n", mol.Len())
	//towrite := Coords.Arrays() //An array of array with the data in the matrix
	for i := 0; i < mol.Len(); i++ {
		//c := towrite[i] //coordinates for the corresponding atoms
		c = Coords.Row(c, i)
		temp := fmt.Sprintf("%-2s  %12.6f%12.6f%12.6f \n", mol.Atom(i).Symbol, c[0], c[1], c[2])
		out = strings.Join([]string{out, temp}, "")
	}
	return out, nil
}
Beispiel #5
0
//RMSD returns the RSMD (root of the mean square deviation) for the sets of cartesian
//coordinates in test and template.
func RMSD(test, template *v3.Matrix) (float64, error) {
	//This is a VERY naive implementation.
	tmr, tmc := template.Dims()
	tsr, tsc := test.Dims()
	if tmr != tsr || tmc != 3 || tsc != 3 {
		return 0, fmt.Errorf("Ill formed matrices for RMSD calculation")
	}
	tr := tmr
	ctempla := v3.Zeros(template.NVecs())
	ctempla.Copy(template)
	//the maybe thing might not be needed since we check the dimensions before.
	f := func() { ctempla.Sub(ctempla, test) }
	if err := gnMaybe(gnPanicker(f)); err != nil {
		return 0, CError{err.Error(), []string{"v3.Matrix.Sub", "RMSD"}}
	}
	var RMSD float64
	for i := 0; i < template.NVecs(); i++ {
		temp := ctempla.VecView(i)
		RMSD += math.Pow(temp.Norm(0), 2)
	}
	RMSD = RMSD / float64(tr)
	RMSD = math.Sqrt(RMSD)
	return RMSD, nil
}
Beispiel #6
0
//XYZStringWrite writes the mol Ref and the Coord coordinates in an XYZ-formatted string.
func XYZWrite(out io.Writer, Coords *v3.Matrix, mol Atomer) error {
	iowriterError := func(err error) error {
		return CError{"Failed to write in io.Writer" + err.Error(), []string{"io.Writer.Write", "XYZWrite"}}
	}
	if mol.Len() != Coords.NVecs() {
		return CError{"Ref and Coords dont have the same number of atoms", []string{"XYZWrite"}}
	}
	c := make([]float64, 3, 3)
	_, err := out.Write([]byte(fmt.Sprintf("%-4d\n\n", mol.Len())))
	if err != nil {
		return iowriterError(err)
	}
	//towrite := Coords.Arrays() //An array of array with the data in the matrix
	for i := 0; i < mol.Len(); i++ {
		//c := towrite[i] //coordinates for the corresponding atoms
		c = Coords.Row(c, i)
		temp := fmt.Sprintf("%-2s  %12.6f%12.6f%12.6f \n", mol.Atom(i).Symbol, c[0], c[1], c[2])
		_, err := out.Write([]byte(temp))
		if err != nil {
			return iowriterError(err)
		}
	}
	return nil
}
Beispiel #7
0
//RotateAbout about rotates the coordinates in coordsorig around by angle radians around the axis
//given by the vector axis. It returns the rotated coordsorig, since the original is not affected.
//Uses Clifford algebra.
func RotateAbout(coordsorig, ax1, ax2 *v3.Matrix, angle float64) (*v3.Matrix, error) {
	coordsLen := coordsorig.NVecs()
	coords := v3.Zeros(coordsLen)
	translation := v3.Zeros(ax1.NVecs())
	translation.Copy(ax1)
	axis := v3.Zeros(ax2.NVecs())
	axis.Sub(ax2, ax1) // the rotation axis
	f := func() { coords.SubVec(coordsorig, translation) }
	if err := gnMaybe(gnPanicker(f)); err != nil {
		return nil, CError{err.Error(), []string{"v3.Matrix.SubVec", "RotateAbout"}}
	}
	Rot := v3.Zeros(coordsLen)
	Rot = Rotate(coords, Rot, axis, angle)
	g := func() { Rot.AddVec(Rot, translation) }
	if err := gnMaybe(gnPanicker(g)); err != nil {
		return nil, CError{err.Error(), []string{"v3.Matrix.AddVec", "RotateAbout"}}

	}
	return Rot, nil
}
Beispiel #8
0
func main() {
	//This is the part that collects all the data from PyMOL, with all  the proper error checking.
	stdin := bufio.NewReader(os.Stdin)
	options, err := chemjson.DecodeOptions(stdin)
	if err != nil {
		fmt.Fprint(os.Stderr, err.Marshal())
		log.Fatal(err)
	}
	mainName := options.SelNames[0]
	if len(options.AtomsPerSel) > 1 {
		for _, v := range options.SelNames[1:] {
			mainName = mainName + "__" + v //inefficient but there should never be THAT many selections.
		}
	}
	dielectric := options.FloatOptions[0][0]
	charge := options.IntOptions[0][0]
	multi := options.IntOptions[0][1]
	qmprogram := options.StringOptions[0][0]
	method := options.StringOptions[0][1]
	calctype := options.StringOptions[0][2]
	var osidemol *chem.Topology
	var osidecoords, sidecoords *v3.Matrix
	var sidelist, sidefrozen []int
	selindex := 0
	total := 0
	selections := len(options.AtomsPerSel)
	if options.BoolOptions[0][0] { //sidechain selections exist
		sidecoords, osidecoords, osidemol, sidelist, sidefrozen = SideChains(stdin, options)
		selections--
		total += osidemol.Len()
		selindex++
	}
	fmt.Fprint(os.Stderr, selections)
	obbmol := make([]*chem.Topology, selections, selections)
	obbcoords := make([]*v3.Matrix, selections, selections)
	bbcoords := make([]*v3.Matrix, selections, selections)
	bblist := make([][]int, selections, selections)
	bbfrozen := make([][]int, selections, selections)
	for i := 0; i < selections; i++ {
		bbcoords[i], obbcoords[i], obbmol[i], bblist[i], bbfrozen[i] = BackBone(stdin, options, selindex)
		total += obbmol[i].Len()
		selindex++
		fmt.Fprint(os.Stderr, "chetumanga")
	}
	//Now we put the juit together
	bigC := v3.Zeros(total)
	bigA := chem.NewTopology([]*chem.Atom{}, 0, 0)
	bigFroz := make([]int, 0, total)
	setoffset := 0
	if options.BoolOptions[0][0] {
		bigC.SetMatrix(0, 0, osidecoords)
		setoffset += osidecoords.NVecs()
		bigA = chem.MergeAtomers(bigA, osidemol)
		//	bigA = osidemol
		bigFroz = append(bigFroz, sidefrozen...)
	}
	for k, v := range obbcoords {
		bigC.SetMatrix(setoffset, 0, v)
		bigA = chem.MergeAtomers(bigA, obbmol[k])
		tmpfroz := SliceOffset(bbfrozen[k], setoffset)
		bigFroz = append(bigFroz, tmpfroz...)
		setoffset += v.NVecs()

	}
	bigA.SetCharge(charge)
	bigA.SetMulti(multi)
	chem.PDBFileWrite(mainName+"toOPT.pdb", bigC, bigA, nil) /////////////////////////////////////
	chem.XYZFileWrite(mainName+"toOPT.xyz", bigC, bigA)      /////////////////////////////////////
	//Ok, we have now one big matrix and one big atom set, now the optimization

	calc := new(qm.Calc)
	if calctype == "Optimization" {
		calc.Optimize = true
	}
	calc.RI = true //some options, including this one, are meaningless for MOPAC
	calc.CConstraints = bigFroz
	calc.Dielectric = dielectric
	calc.SCFTightness = 1
	calc.Dispersion = "D3"
	calc.Method = "TPSS"
	if method == "Cheap" {
		calc.BSSE = "gcp"
		if qmprogram == "ORCA" {
			calc.Method = "HF-3c"
			calc.RI = false
		} else if qmprogram == "MOPAC2012" {
			calc.Method = "PM6-D3H4 NOMM MOZYME"
		} else {
			calc.Basis = "def2-SVP"
		}
	} else {
		calc.Basis = "def2-TZVP"
	}
	//We will use the default methods and basis sets of each program. In the case of MOPAC, that is currently PM6-D3H4.
	var QM qm.Handle
	switch qmprogram {
	case "ORCA":
		orca := qm.NewOrcaHandle()
		orca.SetnCPU(runtime.NumCPU())
		QM = qm.Handle(orca)
	case "TURBOMOLE":
		QM = qm.Handle(qm.NewTMHandle())
	case "NWCHEM":
		QM = qm.Handle(qm.NewNWChemHandle())
		calc.SCFConvHelp = 1
	default:
		QM = qm.Handle(qm.NewMopacHandle())
	}

	QM.SetName(mainName)
	QM.BuildInput(bigC, bigA, calc)
	fmt.Fprint(os.Stderr, options.BoolOptions)
	if options.BoolOptions[0][2] {
		return //Dry run
	}
	if err2 := QM.Run(true); err != nil {
		log.Fatal(err2.Error())
	}
	//Now we ran the calculation, we must retrive the geometry and divide the coordinates among the original selections.
	var newBigC *v3.Matrix
	info := new(chemjson.Info) //Contains the return info
	var err2 error
	if calc.Optimize {
		newBigC, err2 = QM.OptimizedGeometry(bigA)
		if err2 != nil {
			log.Fatal(err2.Error())
		}
		if qmprogram == "NWCHEM" { //NWchem translates/rotates the system before optimizing so we need to superimpose with the original geometry in order for them to match.
			newBigC, err2 = chem.Super(newBigC, bigC, bigFroz, bigFroz)
			if err2 != nil {
				log.Fatal(err2.Error())
			}
		}
		info.Molecules = len(options.AtomsPerSel)
		geooffset := 0
		if options.BoolOptions[0][0] {
			tmp := newBigC.View(geooffset, 0, len(sidelist), 3) //This is likely to change when we agree on a change for the gonum API!!!!
			sidecoords.SetVecs(tmp, sidelist)
			info.FramesPerMolecule = []int{1}
			info.AtomsPerMolecule = []int{sidecoords.NVecs()}
			//I DO NOT understand why the next line is += len(sidelist)-1 instead of len(sidelist), but it works. If a bug appears
			//take a look at this line, and the equivalent in the for loop that follows.
			geooffset += (len(sidelist) - 1)
		}
		for k, v := range bbcoords {
			//Take a look here in case of bugs.
			tmp := newBigC.View(geooffset, 0, len(bblist[k]), 3) //This is likely to change when we agree on a change for the gonum API!!!!
			v.SetVecs(tmp, bblist[k])
			info.FramesPerMolecule = append(info.FramesPerMolecule, 1)
			info.AtomsPerMolecule = append(info.AtomsPerMolecule, v.NVecs())
			geooffset += (len(bblist[k]) - 1)

		}
		//	for k,v:=range(bbcoords){
		//		chem.XYZWrite(fmt.Sprintf("opti%d.xyz",k), , newcoords)
		//	}
	} else {
		//nothing here, the else part will get deleted after tests
	}
	energy, err2 := QM.Energy()
	if err2 != nil {
		log.Fatal(err2.Error())
	}
	//Start transfering data back

	info.Energies = []float64{energy}
	if err2 := info.Send(os.Stdout); err2 != nil {
		fmt.Fprint(os.Stderr, err2)
		log.Fatal(err2)
	}
	//	fmt.Fprint(os.Stdout,mar)
	//	fmt.Fprint(os.Stdout,"\n")

	// A loop again to transmit the info.

	if options.BoolOptions[0][0] {
		if err := chemjson.SendMolecule(nil, []*v3.Matrix{sidecoords}, nil, nil, os.Stdout); err2 != nil {
			fmt.Fprint(os.Stderr, err)
			log.Fatal(err)
		}
	}
	for _, v := range bbcoords {
		fmt.Fprintln(os.Stderr, "BB transmit!", v.NVecs())
		if err := chemjson.SendMolecule(nil, []*v3.Matrix{v}, nil, nil, os.Stdout); err2 != nil {
			fmt.Fprint(os.Stderr, err)
			log.Fatal(err)
		}
	}

}