Пример #1
1
//RotatorTranslatorToSuper superimposes the set of cartesian coordinates given as the rows of the matrix test on the gnOnes of the rows
//of the matrix templa. Returns the transformed matrix, the rotation matrix, 2 translation row vectors
//For the superposition plus an error. In order to perform the superposition, without using the transformed
//the first translation vector has to be added first to the moving matrix, then the rotation must be performed
//and finally the second translation has to be added.
//This is a low level function, although one can use it directly since it returns the transformed matrix.
//The math for this function is by Prof. Veronica Jimenez-Curihual, University of Concepcion, Chile.
func RotatorTranslatorToSuper(test, templa *v3.Matrix) (*v3.Matrix, *v3.Matrix, *v3.Matrix, *v3.Matrix, error) {
	tmr, tmc := templa.Dims()
	tsr, tsc := test.Dims()
	if tmr != tsr || tmc != 3 || tsc != 3 {
		return nil, nil, nil, nil, CError{"goChem: Ill-formed matrices", []string{"RotatorTranslatorToSuper"}}
	}
	var Scal float64
	Scal = float64(1.0) / float64(tmr)
	j := gnOnes(tmr, 1) //Mass is not important for this matter so we'll just use this.
	ctest, distest, err := MassCenter(test, test, j)
	if err != nil {
		return nil, nil, nil, nil, errDecorate(err, "RotatorTranslatorToSuper")
	}
	ctempla, distempla, err := MassCenter(templa, templa, j)
	if err != nil {
		return nil, nil, nil, nil, errDecorate(err, "RotatorTranslatorToSuper")

	}
	Mid := gnEye(tmr)
	jT := gnT(j)
	ScaledjProd := gnMul(j, jT)
	ScaledjProd.Scale(Scal, ScaledjProd)
	aux2 := gnMul(gnT(ctempla), Mid)
	r, _ := aux2.Dims()
	Maux := v3.Zeros(r)
	Maux.Mul(aux2, ctest)
	Maux.Tr() //Dont understand why this is needed
	factors := mat64.SVD(v3.Matrix2Dense(Maux), appzero, math.SmallestNonzeroFloat64, true, true)
	U := factors.U
	V := factors.V
	//	if err != nil {
	//		return nil, nil, nil, nil, err  //I'm not sure what err is this one
	//	}
	U.Scale(-1, U)
	V.Scale(-1, V)
	//SVD gives different results here than in numpy. U and V are multiplide by -1 in one of them
	//and gomatrix gives as V the transpose of the matrix given as V by numpy. I guess is not an
	//error, but don't know for sure.
	vtr, _ := V.Dims()
	Rotation := v3.Zeros(vtr)
	Rotation.Mul(V, gnT(U))
	Rotation.Tr() //Don't know why does this work :(
	RightHand := gnEye(3)
	if det(Rotation) < 0 {
		RightHand.Set(2, 2, -1)
		Rotation.Mul(V, RightHand)
		Rotation.Mul(Rotation, gnT(U)) //If I get this to work Ill arrange so gnT(U) is calculated once, not twice as now.
		Rotation.Tr()                  //TransposeTMP contains the transpose of the original Rotation      //Same, no ide why I need this
		//return nil, nil, nil, nil, fmt.Errorf("Got a reflection instead of a translations. The objects may be specular images of each others")
	}
	jT.Scale(Scal, jT)
	subtempla := v3.Zeros(tmr)
	subtempla.Copy(ctempla)
	sub := v3.Zeros(ctest.NVecs())
	sub.Mul(ctest, Rotation)
	subtempla.Sub(subtempla, sub)
	jtr, _ := jT.Dims()
	Translation := v3.Zeros(jtr)
	Translation.Mul(jT, subtempla)
	Translation.Add(Translation, distempla)
	//This alings the transformed with the original template, not the mean centrate one
	transformed := v3.Zeros(ctest.NVecs())
	transformed.Mul(ctest, Rotation)
	transformed.AddVec(transformed, Translation)
	//end transformed
	distest.Scale(-1, distest)
	return transformed, Rotation, distest, Translation, nil
}
Пример #2
0
//Next Reads the next frame in a XTCObj that has been initialized for read
//With initread. If keep is true, returns a pointer to matrix.DenseMatrix
//With the coordinates read, otherwiser, it discards the coordinates and
//returns nil.
func (X *XTCObj) Next(output *v3.Matrix) error {
	if !X.Readable() {
		return Error{TrajUnIni, X.filename, []string{"Next"}, true}
	}
	cnatoms := C.int(X.natoms)
	worked := C.get_coords(X.fp, &X.cCoords[0], cnatoms)
	if worked == 11 {
		X.readable = false
		return newlastFrameError(X.filename, "Next") //This is not really an error and should be catched in the calling function
	}
	if worked != 0 {
		X.readable = false
		return Error{ReadError, X.filename, []string{"Next"}, true}
	}
	if output != nil { //col the frame
		r, c := output.Dims()
		if r < (X.natoms) {
			panic("Buffer v3.Matrix too small to hold trajectory frame")
		}
		for j := 0; j < r; j++ {
			for k := 0; k < c; k++ {
				l := k + (3 * j)
				output.Set(j, k, (10 * float64(X.cCoords[l]))) //nm to Angstroms
			}
		}
		return nil
	}
	return nil //Just drop the frame
}
Пример #3
0
//BestPlane returns a row vector that is normal to the plane that best contains the molecule
//if passed a nil Masser, it will simply set all masses to 1.
func BestPlane(coords *v3.Matrix, mol Masser) (*v3.Matrix, error) {
	var err error
	var Mmass []float64
	cr, _ := coords.Dims()
	if mol != nil {
		Mmass, err = mol.Masses()
		if err != nil {
			return nil, errDecorate(err, "BestPlane")
		}
		if len(Mmass) != cr {
			return nil, CError{fmt.Sprintf("Inconsistent coordinates(%d)/atoms(%d)", len(Mmass), cr), []string{"BestPlane"}}
		}
	}
	moment, err := MomentTensor(coords, Mmass)
	if err != nil {
		return nil, errDecorate(err, "BestPlane")
	}
	evecs, _, err := v3.EigenWrap(moment, appzero)
	if err != nil {
		return nil, errDecorate(err, "BestPlane")
	}
	normal, err := BestPlaneP(evecs)
	if err != nil {
		return nil, errDecorate(err, "BestPlane")
	}
	//MomentTensor(, mass)
	return normal, err
}
Пример #4
0
//MomentTensor returns the moment tensor for a matrix A of coordinates and a column
//vector mass with the respective massess.
func MomentTensor(A *v3.Matrix, massslice []float64) (*v3.Matrix, error) {
	ar, ac := A.Dims()
	var err error
	var mass *mat64.Dense
	if massslice == nil {
		mass = gnOnes(ar, 1)
	} else {
		mass = mat64.NewDense(ar, 1, massslice)
		//		if err != nil {
		//			return nil, err
		//		}
	}
	center, _, err := MassCenter(A, v3.Dense2Matrix(gnCopy(A)), mass)
	if err != nil {
		return nil, errDecorate(err, "MomentTensor")
	}
	sqrmass := gnZeros(ar, 1)
	//	sqrmass.Pow(mass,0.5)
	pow(mass, sqrmass, 0.5) //the result is stored in sqrmass
	//	fmt.Println(center,sqrmass) ////////////////////////
	center.ScaleByCol(center, sqrmass)
	//	fmt.Println(center,"scaled center")
	centerT := gnZeros(ac, ar)
	centerT.Copy(center.T())
	moment := gnMul(centerT, center)
	return v3.Dense2Matrix(moment), nil
}
Пример #5
0
//MassCenter centers in in the center of mass of oref. Mass must be
//A column vector. Returns the centered matrix and the displacement matrix.
func MassCenter(in, oref *v3.Matrix, mass *mat64.Dense) (*v3.Matrix, *v3.Matrix, error) {
	or, _ := oref.Dims()
	ir, _ := in.Dims()
	if mass == nil { //just obtain the geometric center
		tmp := ones(or)
		mass = mat64.NewDense(or, 1, tmp) //gnOnes(or, 1)
	}
	ref := v3.Zeros(or)
	ref.Copy(oref)
	gnOnesvector := gnOnes(1, or)
	f := func() { ref.ScaleByCol(ref, mass) }
	if err := gnMaybe(gnPanicker(f)); err != nil {
		return nil, nil, CError{err.Error(), []string{"v3.Matrix.ScaleByCol", "MassCenter"}}
	}
	ref2 := v3.Zeros(1)
	g := func() { ref2.Mul(gnOnesvector, ref) }
	if err := gnMaybe(gnPanicker(g)); err != nil {
		return nil, nil, CError{err.Error(), []string{"v3.gOnesVector", "MassCenter"}}
	}
	ref2.Scale(1.0/mass.Sum(), ref2)
	returned := v3.Zeros(ir)
	returned.Copy(in)
	returned.SubVec(returned, ref2)
	/*	for i := 0; i < ir; i++ {
			if err := returned.GetRowVector(i).Subtract(ref2); err != nil {
				return nil, nil, err
			}
		}
	*/
	return returned, ref2, nil
}
Пример #6
0
//PDBStringWrite writes a string in PDB format for a given reference, coordinate set and bfactor set, which must match each other
//returns the written string and error or nil.
func PDBStringWrite(coords *v3.Matrix, mol Atomer, bfact []float64) (string, error) {
	if bfact == nil {
		bfact = make([]float64, mol.Len())
	}
	cr, _ := coords.Dims()
	br := len(bfact)
	if cr != mol.Len() || cr != br {
		return "", CError{"Ref and Coords and/or Bfactors dont have the same number of atoms", []string{"PDBStringWrite"}}
	}
	chainprev := mol.Atom(0).Chain //this is to know when the chain changes.
	var outline string
	var outstring string
	var err error
	for i := 0; i < mol.Len(); i++ {
		//	r,c:=coords.Dims()
		//	fmt.Println("IIIIIIIIIIIi", i,coords,r,c, "lllllll")
		writecoord := coords.VecView(i)
		outline, chainprev, err = writePDBLine(mol.Atom(i), writecoord, bfact[i], chainprev)
		if err != nil {
			return "", errDecorate(err, "PDBStringWrite "+fmt.Sprintf("Could not print PDB line: %d", i))
		}
		outstring = strings.Join([]string{outstring, outline}, "")
	}
	outstring = strings.Join([]string{outstring, "END\n"}, "")
	return outstring, nil
}
Пример #7
0
func pdbWrite(out io.Writer, coords *v3.Matrix, mol Atomer, bfact []float64) error {
	if bfact == nil {
		bfact = make([]float64, mol.Len())
	}
	cr, _ := coords.Dims()
	br := len(bfact)
	if cr != mol.Len() || cr != br {
		return CError{"Ref and Coords and/or Bfactors dont have the same number of atoms", []string{"pdbWrite"}}
	}
	chainprev := mol.Atom(0).Chain //this is to know when the chain changes.
	var outline string
	var err error
	iowriteError := func(err error) error {
		return CError{"Failed to write in io.Writer" + err.Error(), []string{"io.Write.Write", "pdbWrite"}}
	}
	for i := 0; i < mol.Len(); i++ {
		//	r,c:=coords.Dims()
		//	fmt.Println("IIIIIIIIIIIi", i,coords,r,c, "lllllll")
		writecoord := coords.VecView(i)
		outline, chainprev, err = writePDBLine(mol.Atom(i), writecoord, bfact[i], chainprev)
		if err != nil {
			return errDecorate(err, "pdbWrite "+fmt.Sprintf("Could not print PDB line: %d", i))
		}
		_, err := out.Write([]byte(outline))
		if err != nil {
			return iowriteError(err)
		}
	}
	_, err = out.Write([]byte("END")) //no newline, this is in case the write is part of a PDB and one needs to write "ENDMODEL".
	if err != nil {
		return iowriteError(err)
	}
	return nil
}
Пример #8
0
//ScaleBond takes a C-H bond and moves the H (in place) so the distance between them is the one given (bond).
//CAUTION: I have only tested it for the case where the original distance>bond, although I expect it to also work in the other case.
func ScaleBond(C, H *v3.Matrix, bond float64) {
	Odist := v3.Zeros(1)
	Odist.Sub(H, C)
	distance := Odist.Norm(0)
	Odist.Scale((distance-bond)/distance, Odist)
	H.Sub(H, Odist)
}
Пример #9
0
//Projection returns the projection of test in ref.
func Projection(test, ref *v3.Matrix) *v3.Matrix {
	rr, _ := ref.Dims()
	Uref := v3.Zeros(rr)
	Uref.Unit(ref)
	scalar := test.Dot(Uref) //math.Abs(la)*math.Cos(angle)
	Uref.Scale(scalar, Uref)
	return Uref
}
Пример #10
0
//BestPlaneP takes sorted evecs, according to the eval,s and returns a row vector that is normal to the
//Plane that best contains the molecule. Notice that the function can't possibly check
//that the vectors are sorted. The P at the end of the name is for Performance. If
//That is not an issue it is safer to use the BestPlane function that wraps this one.
func BestPlaneP(evecs *v3.Matrix) (*v3.Matrix, error) {
	evr, evc := evecs.Dims()
	if evr != 3 || evc != 3 {
		return evecs, CError{"goChem: Eigenvectors matrix must be 3x3", []string{"BestPlaneP"}} //maybe this should be a panic
	}
	v1 := evecs.VecView(2)
	v2 := evecs.VecView(1)
	normal := v3.Zeros(1)
	normal.Cross(v1, v2)
	return normal, nil
}
Пример #11
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
}
Пример #12
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
}
Пример #13
0
//ScaleBonds scales all bonds between atoms in the same residue with names n1, n2 to a final lenght finallengt, by moving the atoms n2.
//the operation is executed in place.
func ScaleBonds(coords *v3.Matrix, mol Atomer, n1, n2 string, finallenght float64) {
	for i := 0; i < mol.Len(); i++ {
		c1 := mol.Atom(i)
		if c1.Name != n1 {
			continue
		}
		for j := 0; j < mol.Len(); j++ {
			c2 := mol.Atom(j)
			if c1.MolID == c2.MolID && c1.Name == n1 && c2.Name == n2 {
				A := coords.VecView(i)
				B := coords.VecView(j)
				ScaleBond(A, B, finallenght)
			}
		}
	}
}
Пример #14
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
}
Пример #15
0
//CenterOfMass returns the center of mass the atoms represented by the coordinates in geometry
//and the masses in mass, and an error. If mass is nil, it calculates the geometric center
func CenterOfMass(geometry *v3.Matrix, mass *mat64.Dense) (*v3.Matrix, error) {
	if geometry == nil {
		return nil, CError{"goChem: nil matrix to get the center of mass", []string{"CenterOfMass"}}
	}
	gr, _ := geometry.Dims()
	if mass == nil { //just obtain the geometric center
		tmp := ones(gr)
		mass = mat64.NewDense(gr, 1, tmp) //gnOnes(gr, 1)
	}
	tmp2 := ones(gr)
	gnOnesvector := mat64.NewDense(1, gr, tmp2) //gnOnes(1, gr)

	ref := v3.Zeros(gr)
	ref.ScaleByCol(geometry, mass)
	ref2 := v3.Zeros(1)
	ref2.Mul(gnOnesvector, ref)
	ref2.Scale(1.0/mass.Sum(), ref2)
	return ref2, nil
}
Пример #16
0
//Super determines the best rotation and translations to superimpose the coords in test
//listed in testlst on te atoms of molecule templa, frame frametempla, listed in templalst.
//It applies those rotation and translations to the whole frame frametest of molecule test, in palce.
//testlst and templalst must have the same number of elements. If any of the two slices, or both, are
//nil or have a zero lenght, they will be replaced by a list containing the number of all atoms in the
//corresponding molecule.
func Super(test, templa *v3.Matrix, testlst, templalst []int) (*v3.Matrix, error) {
	//_, testcols := test.Dims()
	//_, templacols := templa.Dims()
	structs := []*v3.Matrix{test, templa}
	lists := [][]int{testlst, templalst}
	//In case one or both lists are nil or have lenght zero.
	for k, v := range lists {
		if v == nil || len(v) == 0 {
			lists[k] = make([]int, structs[k].NVecs(), structs[k].NVecs())
			for k2, _ := range lists[k] {
				lists[k][k2] = k2
			}
		}
	}
	//fmt.Println(lists[0])
	if len(lists[0]) != len(lists[1]) {
		return nil, CError{fmt.Sprintf("Mismatched template and test atom numbers: %d, %d", len(lists[1]), len(lists[0])), []string{"Super"}}
	}
	ctest := v3.Zeros(len(lists[0]))
	ctest.SomeVecs(test, lists[0])
	ctempla := v3.Zeros(len(lists[1]))
	ctempla.SomeVecs(templa, lists[1])
	_, rotation, trans1, trans2, err1 := RotatorTranslatorToSuper(ctest, ctempla)
	if err1 != nil {
		return nil, errDecorate(err1, "Super")
	}
	test.AddVec(test, trans1)
	//	fmt.Println("test1",test, rotation) /////////////77
	test.Mul(test, rotation)
	//	fmt.Println("test2",test) ///////////
	test.AddVec(test, trans2)
	//	fmt.Println("test3",test) ///////
	return test, nil
}
Пример #17
0
//writePDBLine writes a line in PDB format from the data passed as a parameters. It takes the chain of the previous atom
//and returns the written line, the chain of the just-written atom, and error or nil.
func writePDBLine(atom *Atom, coord *v3.Matrix, bfact float64, chainprev string) (string, string, error) {
	var ter string
	var out string
	if atom.Chain != chainprev {
		ter = fmt.Sprint(out, "TER\n")
		chainprev = atom.Chain
	}
	first := "ATOM"
	if atom.Het {
		first = "HETATM"
	}
	formatstring := "%-6s%5d  %-3s %-4s%1s%4d    %8.3f%8.3f%8.3f%6.2f%6.2f          %2s  \n"
	//4 chars for the atom name are used when hydrogens are included.
	//This has not been tested
	if len(atom.Name) == 4 {
		formatstring = strings.Replace(formatstring, "%-3s ", "%-4s", 1)
	} else if len(atom.Name) > 4 {
		return "", chainprev, CError{"Cant print PDB line", []string{"writePDBLine"}}
	}
	//"%-6s%5d  %-3s %3s %1c%4d    %8.3f%8.3f%8.3f%6.2f%6.2f          %2s  \n"
	out = fmt.Sprintf(formatstring, first, atom.ID, atom.Name, atom.Molname, atom.Chain,
		atom.MolID, coord.At(0, 0), coord.At(0, 1), coord.At(0, 2), atom.Occupancy, bfact, atom.Symbol)
	out = strings.Join([]string{ter, out}, "")
	return out, chainprev, nil
}
Пример #18
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
}
Пример #19
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
}
Пример #20
0
//AntiProjection returns a vector in the direction of ref with the magnitude of
//a vector A would have if |test| was the magnitude of its projection
//in the direction of test.
func AntiProjection(test, ref *v3.Matrix) *v3.Matrix {
	rr, _ := ref.Dims()
	testnorm := test.Norm(0)
	Uref := v3.Zeros(rr)
	Uref.Unit(ref)
	scalar := test.Dot(Uref)
	scalar = (testnorm * testnorm) / scalar
	Uref.Scale(scalar, Uref)
	return Uref
}
Пример #21
0
//Angle takes 2 vectors and calculate the angle in radians between them
//It does not check for correctness or return errors!
func Angle(v1, v2 *v3.Matrix) float64 {
	normproduct := v1.Norm(0) * v2.Norm(0)
	dotprod := v1.Dot(v2)
	argument := dotprod / normproduct
	//Take care of floating point math errors
	if math.Abs(argument-1) <= appzero {
		argument = 1
	} else if math.Abs(argument+1) <= appzero {
		argument = -1
	}
	//fmt.Println(dotprod/normproduct,argument) //dotprod/normproduct, dotprod, normproduct,v1.TwoNorm(),v2.TwoNorm())
	angle := math.Acos(argument)
	if math.Abs(angle) <= appzero {
		return 0.00
	}
	return angle
}
Пример #22
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
}
Пример #23
0
//RotatorToNewY takes a set of coordinates (mol) and a vector (y). It returns
//a rotation matrix that, when applied to mol, will rotate it around the Z axis
//in such a way that the projection of newy in the XY plane will be aligned with
//the Y axis.
func RotatorAroundZToNewY(newy *v3.Matrix) (*v3.Matrix, error) {
	nr, nc := newy.Dims()
	if nc != 3 || nr != 1 {
		return nil, CError{"Wrong newy vector", []string{"RotatorAroundZtoNewY"}}
	}
	if nc != 3 {
		return nil, CError{"Wrong mol vector", []string{"RotatorAroundZtoNewY"}} //this one doesn't seem reachable

	}
	gamma := math.Atan2(newy.At(0, 0), newy.At(0, 1))
	singamma := math.Sin(gamma)
	cosgamma := math.Cos(gamma)
	operator := []float64{cosgamma, singamma, 0,
		-singamma, cosgamma, 0,
		0, 0, 1}
	return v3.NewMatrix(operator)

}
Пример #24
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
}
Пример #25
0
// RamaCalc Obtains the values for the phi and psi dihedrals indicated in []Ramaset, for the
// structure M.  It returns a slice of 2-element slices, one for the phi the next for the psi
// dihedral, a and an error or nil.
func RamaCalc(M *v3.Matrix, dihedrals []RamaSet) ([][]float64, error) {
	if M == nil || dihedrals == nil {
		return nil, Error{ErrNilData, "", "RamaCalc", "", true}
	}
	r, _ := M.Dims()
	Rama := make([][]float64, 0, len(dihedrals))
	for _, j := range dihedrals {
		if j.Npost >= r {
			return nil, Error{ErrOutOfRange, "", "RamaCalc", "", true}
		}
		Cprev := M.VecView(j.Cprev)
		N := M.VecView(j.N)
		Ca := M.VecView(j.Ca)
		C := M.VecView(j.C)
		Npost := M.VecView(j.Npost)
		phi := chem.Dihedral(Cprev, N, Ca, C)
		psi := chem.Dihedral(N, Ca, C, Npost)
		temp := []float64{phi * (180 / math.Pi), psi * (180 / math.Pi)}
		Rama = append(Rama, temp)
	}
	return Rama, nil
}
Пример #26
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)
		}
	}

}
Пример #27
0
//BuildInput builds an input for NWChem based int the data in atoms, coords and C.
//returns only error.
func (O *NWChemHandle) BuildInput(coords *v3.Matrix, atoms chem.AtomMultiCharger, Q *Calc) error {
	//Only error so far
	if atoms == nil || coords == nil {
		return Error{ErrMissingCharges, NWChem, O.inputname, "", []string{"BuildInput"}, true}
	}
	if Q.Basis == "" {
		log.Printf("no basis set assigned for NWChem calculation, will use the default %s, \n", O.defbasis)
		Q.Basis = O.defbasis
	}
	if Q.Method == "" {
		log.Printf("no method assigned for NWChem calculation, will use the default %s, \n", O.defmethod)
		Q.Method = O.defmethod
		Q.RI = true
	}
	if O.inputname == "" {
		O.inputname = "gochem"
	}
	//The initial guess
	vectors := fmt.Sprintf("output  %s.movecs", O.inputname) //The initial guess
	switch Q.Guess {
	case "":
	case "hcore": //This option is not a great idea, apparently.
		vectors = fmt.Sprintf("input hcore %s", vectors)
	default:
		if !Q.OldMO {
			//If the user gives something in Q.Guess but DOES NOT want an old MO to be used, I assume he/she wants to put whatever
			//is in Q.Guess directly  in the vector keyword. If you want the default put an empty string in Q.Guess.
			vectors = fmt.Sprintf("%s %s", Q.Guess, vectors)
			break
		}
		//I assume the user gave a basis set name in Q.Guess which I can use to project vectors from a previous run.
		moname := getOldMO(O.previousMO)
		if moname == "" {
			break
		}
		if strings.ToLower(Q.Guess) == strings.ToLower(Q.Basis) {
			//Useful if you only change functionals.
			vectors = fmt.Sprintf("input %s %s", moname, vectors)
		} else {
			//This will NOT work if one assigns different basis sets to different atoms.
			vectors = fmt.Sprintf("input project %s %s %s", strings.ToLower(Q.Guess), moname, vectors)
		}
	}
	vectors = "vectors " + vectors

	disp, ok := nwchemDisp[Q.Dispersion]
	if !ok {
		disp = "vdw 3"
	}
	tightness := ""
	switch Q.SCFTightness {
	case 1:
		tightness = "convergence energy 5.000000E-08\n convergence density 5.000000E-09\n convergence gradient 1E-05"
	case 2:
		//NO idea if this will work, or the criteria will be stronger than the criteria for the intergral evaluation
		//and thus the SCF will never converge. Delete when properly tested.
		tightness = "convergence energy 1.000000E-10\n convergence density 5.000000E-11\n convergence gradient 1E-07"
	}

	//For  now, the only convergence help I trust is to run a little HF calculation before and use the orbitals as a guess.
	//It works quite nicely. When the NWChem people get their shit together and fix the bugs with cgmin and RI and cgmin and
	//COSMO, cgmin will be a great option also.
	scfiters := "iterations 60"
	prevscf := ""
	if Q.SCFConvHelp > 0 {
		scfiters = "iterations 200"
		if Q.Guess == "" {
			prevscf = fmt.Sprintf("\nbasis \"3-21g\"\n * library 3-21g\nend\nset \"ao basis\" 3-21g\nscf\n maxiter 200\n vectors output hf.movecs\n %s\nend\ntask scf energy\n\n", strings.ToLower(mopacMultiplicity[atoms.Multi()]))
			vectors = fmt.Sprintf("vectors input project \"3-21g\" hf.movecs output %s.movecs", O.inputname)
		}
	}
	grid, ok := nwchemGrid[Q.Grid]
	if !ok {
		grid = "medium"
	}
	if Q.SCFTightness > 0 { //We need this if we want the SCF to converge.
		grid = "xfine"
	}
	grid = fmt.Sprintf("grid %s", grid)
	var err error

	//Only cartesian constraints supported by now.
	constraints := ""
	if len(Q.CConstraints) > 0 {
		constraints = "constraints\n fix atom"
		for _, v := range Q.CConstraints {
			constraints = fmt.Sprintf("%s %d", constraints, v+1) //goChem numbering starts from 0, apparently NWChem starts from 1, hence the v+1
		}
		constraints = constraints + "\nend"
	}

	cosmo := ""
	if Q.Dielectric > 0 {
		//SmartCosmo in a single-point means that do_gasphase False is used, nothing fancy.
		if Q.Job.Opti || O.smartCosmo {
			cosmo = fmt.Sprintf("cosmo\n dielec %4.1f\n do_gasphase False\nend", Q.Dielectric)
		} else {
			cosmo = fmt.Sprintf("cosmo\n dielec %4.1f\n do_gasphase True\nend", Q.Dielectric)
		}
	}
	memory := ""
	if Q.Memory != 0 {
		memory = fmt.Sprintf("memory total %d mb", Q.Memory)
	}
	m := strings.ToLower(Q.Method)
	method, ok := nwchemMethods[m]
	if !ok {
		method = "xtpss03 ctpss03"
	}
	method = fmt.Sprintf("xc %s", method)

	task := "dft energy"
	driver := ""
	preopt := ""
	jc := jobChoose{}

	jc.opti = func() {
		eprec := "" //The available presition is set to default except if tighter SCF convergene criteria are being used.
		if Q.SCFTightness > 0 {
			eprec = " eprec 1E-7\n"
		}
		if Q.Dielectric > 0 && O.smartCosmo {
			//If COSMO is used, and O.SmartCosmo is enabled, we start the optimization with a rather loose SCF (the default).
			//and use that denisty as a starting point for the next calculation. The idea is to
			//avoid the gas phase calculation in COSMO.
			//This procedure doesn't seem to help at all, and just using do_gasphase False appears to be good enough in my tests.
			preopt = fmt.Sprintf("cosmo\n dielec %4.1f\n do_gasphase True\nend\n", Q.Dielectric)
			preopt = fmt.Sprintf("%sdft\n iterations 100\n %s\n %s\n print low\nend\ntask dft energy\n", preopt, vectors, method)
			vectors = fmt.Sprintf("vectors input %s.movecs output  %s.movecs", O.inputname, O.inputname) //We must modify the initial guess so we use the vectors we have just generated
		}
		//The NWCHem optimizer is horrible. To try to get something out of it we use this 3-step optimization scheme where we try to compensate for the lack of
		//variable trust radius in nwchem.
		task = "dft optimize"
		//First an optimization with very loose convergency and the standard trust radius.
		driver = fmt.Sprintf("driver\n maxiter 200\n%s trust 0.3\n gmax 0.0500\n grms 0.0300\n xmax 0.1800\n xrms 0.1200\n xyz %s_prev\nend\ntask dft optimize", eprec, O.inputname)
		//Then a second optimization with a looser convergency and a 0.1 trust radius
		driver = fmt.Sprintf("%s\ndriver\n maxiter 200\n%s trust 0.1\n gmax 0.009\n grms 0.001\n xmax 0.04 \n xrms 0.02\n xyz %s_prev2\nend\ntask dft optimize", driver, eprec, O.inputname)
		//Then the final optimization with a small trust radius and the NWChem default convergence criteria.
		driver = fmt.Sprintf("%s\ndriver\n maxiter 200\n%s trust 0.05\n xyz %s\nend\n", driver, eprec, O.inputname)
		//Old criteria (ORCA): gmax 0.003\n grms 0.0001\n xmax 0.004 \n xrms 0.002\n
	}
	Q.Job.Do(jc)
	//////////////////////////////////////////////////////////////
	//Now lets write the thing. Ill process/write the basis later
	//////////////////////////////////////////////////////////////
	file, err := os.Create(fmt.Sprintf("%s.nw", O.inputname))
	if err != nil {
		return Error{err.Error(), NWChem, O.inputname, "", []string{"os.Create", "BuildInput"}, true}

	}
	defer file.Close()
	start := "start"
	if O.restart {
		start = "restart"
	}
	_, err = fmt.Fprintf(file, "%s %s\n", start, O.inputname)
	//after this check its assumed that the file is ok.
	if err != nil {
		return Error{err.Error(), NWChem, O.inputname, "", []string{"fmt.Fprintf", "BuildInput"}, true}
	}
	fmt.Fprint(file, "echo\n") //echo input in the output.
	fmt.Fprintf(file, "charge %d\n", atoms.Charge())
	if memory != "" {
		fmt.Fprintf(file, "%s\n", memory) //the memory
	}
	//Now the geometry:
	//If we have cartesian constraints we give the directive noautoz to optimize in cartesian coordinates.
	autoz := ""
	if len(Q.CConstraints) > 0 {
		autoz = "noautoz"
	}
	fmt.Fprintf(file, "geometry units angstroms noautosym %s\n", autoz)
	elements := make([]string, 0, 5) //I will collect the different elements that are in the molecule using the same loop as the geometry.
	for i := 0; i < atoms.Len(); i++ {
		symbol := atoms.Atom(i).Symbol
		//In the following if/else I try to set up basis for specific atoms. Not SO sure it works.
		if isInInt(Q.HBAtoms, i) {
			symbol = symbol + "1"
		} else if isInInt(Q.LBAtoms, i) {
			symbol = symbol + "2"
		}
		fmt.Fprintf(file, " %-2s  %8.3f%8.3f%8.3f \n", symbol, coords.At(i, 0), coords.At(i, 1), coords.At(i, 2))

		if !isInString(elements, symbol) {
			elements = append(elements, symbol)
		}
	}
	fmt.Fprintf(file, "end\n")
	fmt.Fprintf(file, prevscf) //The preeliminar SCF if exists.
	//The basis. First the ao basis (required)
	decap := strings.ToLower //hoping to make the next for loop less ugly
	basis := make([]string, 1, 2)
	basis[0] = "\"ao basis\""
	fmt.Fprintf(file, "basis \"large\" spherical\n") //According to the manual this fails with COSMO. The calculations dont crash. Need to compare energies and geometries with Turbomole in order to be sure.
	for _, el := range elements {
		if isInString(Q.HBElements, el) || strings.HasSuffix(el, "1") {
			fmt.Fprintf(file, " %-2s library %s\n", el, decap(Q.HighBasis))
		} else if isInString(Q.LBElements, el) || strings.HasSuffix(el, "2") {
			fmt.Fprintf(file, " %-2s library %s\n", el, decap(Q.LowBasis))
		} else {
			fmt.Fprintf(file, " %-2s library %s\n", el, decap(Q.Basis))
		}
	}
	fmt.Fprintf(file, "end\n")
	fmt.Fprintf(file, "set \"ao basis\" large\n")
	//Only Ahlrichs basis are supported for RI. USE AHLRICHS BASIS, PERKELE! :-)
	//The only Ahlrichs J basis in NWchem appear to be equivalent to def2-TZVPP/J (orca nomenclature). I suppose that they are still faster
	//than not using RI if the main basis is SVP. One can also hope that they are good enough if the main basis is QZVPP or something.
	//(about the last point, it appears that in Turbomole, the aux basis also go up to TZVPP).
	//This comment is based on the H, Be and C basis.
	if Q.RI {
		fmt.Fprint(file, "basis \"cd basis\"\n * library \"Ahlrichs Coulomb Fitting\"\nend\n")
	}
	//Now the geometry constraints. I kind of assume they are
	if constraints != "" {
		fmt.Fprintf(file, "%s\n", constraints)
	}
	fmt.Fprintf(file, preopt)
	if cosmo != "" {
		fmt.Fprintf(file, "%s\n", cosmo)
	}
	//The DFT block
	fmt.Fprint(file, "dft\n")
	fmt.Fprintf(file, " %s\n", vectors)
	fmt.Fprintf(file, " %s\n", scfiters)
	if tightness != "" {
		fmt.Fprintf(file, " %s\n", tightness)
	}
	fmt.Fprintf(file, " %s\n", grid)
	fmt.Fprintf(file, " %s\n", method)
	if disp != "" {
		fmt.Fprintf(file, " disp %s\n", disp)
	}
	if Q.Job.Opti {
		fmt.Fprintf(file, " print convergence\n")
	}
	//task part
	fmt.Fprintf(file, " mult %d\n", atoms.Multi())
	fmt.Fprint(file, "end\n")
	fmt.Fprintf(file, "%s", driver)
	fmt.Fprintf(file, "task %s\n", task)

	return nil
}
Пример #28
0
//MakeWater Creates a water molecule at distance Angstroms from a2, in a direction that is angle radians from the axis defined by a1 and a2.
//Notice that the exact position of the water is not well defined when angle is not zero. One can always use the RotateAbout
//function to move the molecule to the desired location. If oxygen is true, the oxygen will be pointing to a2. Otherwise,
//one of the hydrogens will.
func MakeWater(a1, a2 *v3.Matrix, distance, angle float64, oxygen bool) *v3.Matrix {
	water := v3.Zeros(3)
	const WaterOHDist = 0.96
	const WaterAngle = 52.25
	const deg2rad = 0.0174533
	w := water.VecView(0) //we first set the O coordinates
	w.Copy(a2)
	w.Sub(w, a1)
	w.Unit(w)
	dist := v3.Zeros(1)
	dist.Sub(a1, a2)
	a1a2dist := dist.Norm(0)
	fmt.Println("ala2dist", a1a2dist, distance) ////////////////7777
	w.Scale(distance+a1a2dist, w)
	w.Add(w, a1)
	for i := 0; i <= 1; i++ {
		o := water.VecView(0)
		w = water.VecView(i + 1)
		w.Copy(o)
		fmt.Println("w1", w) ////////
		w.Sub(w, a2)
		fmt.Println("w12", w) ///////////////
		w.Unit(w)
		fmt.Println("w4", w)
		w.Scale(WaterOHDist+distance, w)
		fmt.Println("w3", w, WaterOHDist, distance)
		o.Sub(o, a2)
		t, _ := v3.NewMatrix([]float64{0, 0, 1})
		upp := v3.Zeros(1)
		upp.Cross(w, t)
		fmt.Println("upp", upp, w, t)
		upp.Add(upp, o)
		upp.Add(upp, a2)
		//water.SetMatrix(3,0,upp)
		w.Add(w, a2)
		o.Add(o, a2)
		sign := 1.0
		if i == 1 {
			sign = -1.0
		}
		temp, _ := RotateAbout(w, o, upp, deg2rad*WaterAngle*sign)
		w.SetMatrix(0, 0, temp)
	}
	var v1, v2 *v3.Matrix
	if angle != 0 {
		v1 = v3.Zeros(1)
		v2 = v3.Zeros(1)
		v1.Sub(a2, a1)
		v2.Copy(v1)
		v2.Set(0, 2, v2.At(0, 2)+1) //a "random" modification. The idea is that its not colinear with v1
		v3 := cross(v1, v2)
		v3.Add(v3, a2)
		water, _ = RotateAbout(water, a2, v3, angle)
	}
	if oxygen {
		return water
	}
	//we move things so an hydrogen points to a2 and modify the distance acordingly.
	e1 := water.VecView(0)
	e2 := water.VecView(1)
	e3 := water.VecView(2)
	if v1 == nil {
		v1 = v3.Zeros(1)
	}
	if v2 == nil {
		v2 = v3.Zeros(1)
	}
	v1.Sub(e2, e1)
	v2.Sub(e3, e1)
	axis := cross(v1, v2)
	axis.Add(axis, e1)
	water, _ = RotateAbout(water, e1, axis, deg2rad*(180-WaterAngle))
	v1.Sub(e1, a2)
	v1.Unit(v1)
	v1.Scale(WaterOHDist, v1)
	water.AddVec(water, v1)
	return water
}
Пример #29
0
//RotatorToNewZ takes a matrix a row vector (newz).
//It returns a linear operator such that, when applied to a matrix mol ( with the operator on the right side)
//it will rotate mol such that the z axis is aligned with newz.
func RotatorToNewZ(newz *v3.Matrix) *v3.Matrix {
	r, c := newz.Dims()
	if c != 3 || r != 1 {
		panic("Wrong newz vector")
	}
	normxy := math.Sqrt(math.Pow(newz.At(0, 0), 2) + math.Pow(newz.At(0, 1), 2))
	theta := math.Atan2(normxy, newz.At(0, 2))      //Around the new y
	phi := math.Atan2(newz.At(0, 1), newz.At(0, 0)) //First around z
	psi := 0.000000000000                           // second around z
	sinphi := math.Sin(phi)
	cosphi := math.Cos(phi)
	sintheta := math.Sin(theta)
	costheta := math.Cos(theta)
	sinpsi := math.Sin(psi)
	cospsi := math.Cos(psi)
	operator := []float64{cosphi*costheta*cospsi - sinphi*sinpsi, -sinphi*cospsi - cosphi*costheta*sinpsi, cosphi * sintheta,
		sinphi*costheta*cospsi + cosphi*sinpsi, -sinphi*costheta*sinpsi + cosphi*cospsi, sintheta * sinphi,
		-sintheta * cospsi, sintheta * sinpsi, costheta}
	finalop, _ := v3.NewMatrix(operator) //we are hardcoding opperator so it must have the right dimensions.
	return finalop

}
Пример #30
0
//BuildInput builds an input for Fermions++ based int the data in atoms, coords and C.
//returns only error.
func (O *FermionsHandle) BuildInput(coords *v3.Matrix, atoms chem.AtomMultiCharger, Q *Calc) error {
	//Only error so far

	if atoms == nil || coords == nil {
		return Error{ErrMissingCharges, Fermions, O.inputname, "", []string{"BuildInput"}, true}
	}
	if Q.Basis == "" {
		log.Printf("no basis set assigned for Fermions++ calculation, will used the default %s, \n", O.defbasis)
		Q.Basis = O.defbasis
	}
	if Q.Method == "" {
		log.Printf("no method assigned for Fermions++ calculation, will used the default %s, \n", O.defmethod)
		Q.Method = O.defmethod
	}

	disp, ok := fermionsDisp[strings.ToLower(Q.Dispersion)]
	if !ok {
		disp = "disp_corr  D3"
	}

	grid, ok := fermionsGrid[Q.Grid]
	if !ok {
		grid = "M3"
	}
	grid = fmt.Sprintf("GRID_RAD_TYPE %s", grid)
	var err error

	m := strings.ToLower(Q.Method)
	method, ok := fermionsMethods[m]
	if !ok {
		method = "EXC XC_GGA_X_PBE_R\n ECORR XC_GGA_C_PBE"
	}
	task := "SinglePoint"
	dloptions := ""
	jc := jobChoose{}
	jc.opti = func() {
		task = "DLF_OPTIMIZE"
		dloptions = fmt.Sprintf("*start::dlfind\n JOB std\n method l-bfgs\n trust_radius energy\n dcd %s.dcd\n maxcycle 300\n maxene 200\n coord_type cartesian\n*end\n", O.inputname)
		//Only cartesian constraints supported by now.
		if len(Q.CConstraints) > 0 {
			dloptions = fmt.Sprintf("%s\n*start::dlf_constraints\n", dloptions)
			for _, v := range Q.CConstraints {
				dloptions = fmt.Sprintf("%s cart %d\n", dloptions, v+1) //fortran numbering, starts with 1.
			}
			dloptions = fmt.Sprintf("%s*end\n", dloptions)
		}
	}
	Q.Job.Do(jc)
	cosmo := ""
	if Q.Dielectric > 0 {
		cosmo = fmt.Sprintf("*start::solvate\n pcm_model cpcm\n epsilon %f\n cavity_model bondi\n*end\n", Q.Dielectric)
	}

	//////////////////////////////////////////////////////////////
	//Now lets write the thing.
	//////////////////////////////////////////////////////////////
	file, err := os.Create(fmt.Sprintf("%s.in", O.inputname))
	if err != nil {
		return Error{ErrCantInput, Fermions, O.inputname, err.Error(), []string{"os.Create", "BuildInput"}, true}
	}
	defer file.Close()
	//Start with the geometry part (coords, charge and multiplicity)
	fmt.Fprintf(file, "*start::geo\n")
	fmt.Fprintf(file, "%d %d\n", atoms.Charge(), atoms.Multi())
	for i := 0; i < atoms.Len(); i++ {
		fmt.Fprintf(file, "%-2s  %8.3f%8.3f%8.3f\n", atoms.Atom(i).Symbol, coords.At(i, 0), coords.At(i, 1), coords.At(i, 2))
	}
	fmt.Fprintf(file, "*end\n\n")
	fmt.Fprintf(file, "*start::sys\n")
	fmt.Fprintf(file, " TODO %s\n", task)
	fmt.Fprintf(file, " BASIS %s\n PC pure\n", strings.ToLower(Q.Basis))
	fmt.Fprintf(file, " %s\n", method)
	fmt.Fprintf(file, " %s\n", grid)
	fmt.Fprintf(file, " %s\n", disp)
	fmt.Fprintf(file, " %s\n", O.gpu)
	if !Q.Job.Opti {
		fmt.Fprintf(file, " INFO 2\n")
	}
	fmt.Fprintf(file, "*end\n\n")
	fmt.Fprintf(file, "%s\n", cosmo)
	fmt.Fprintf(file, "%s\n", dloptions)
	return nil
}