예제 #1
0
파일: goqm.go 프로젝트: rmera/gopymol
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)
		}
	}

}
예제 #2
0
func main() {
	//flag parsing
	//Lots of options, but the defaults are sane enough that you shouldnt need to use more than the filename and qm program.
	charge := flag.Int("charge", 0, "The charge of the system.")
	multi := flag.Int("multi", 1, "The multiplicity of the system.")
	filename := flag.String("file", "file.xyz", "The XYZ file containing the coordinates for the system.")
	functional := flag.String("func", "BP86", "The density functional used. TPSS and BP86 activate RI when possible.")
	program := flag.String("program", "nwchem", "The QM program used: qcmine, nwchem, or orca.")
	basis := flag.String("basis", "def2-SVP", "the basis set to use. Use Karlsruhe basis.")
	dielectric := flag.Float64("epsilon", -1, "The dielectric constant. -1 indicates no dielectric used.")
	optimize := flag.Bool("opt", true, "Wether to optimize or run an SP calculation.")
	fixed := flag.String("fixed", "", "Fixed atoms, counting from zero, separated by spaces.")
	flag.Parse()
	//We set the calculation to the values in the flags. Not big deal.
	mol, err := chem.XYZFileRead(*filename)
	if err != nil {
		panic(err.Error())
	}
	mol.SetMulti(*multi)
	mol.SetCharge(*charge)
	calc := new(qm.Calc)
	if strings.Contains("TPSS,BP86,PBE", *functional) {
		calc.RI = true
	}
	if *fixed != "" {
		calc.CConstraints, err = scu.IndexStringParse(*fixed)
		if err != nil {
			panic(err.Error())
		}
	}
	calc.Memory = 1000
	calc.Dielectric = *dielectric
	calc.Grid = 3
	if !strings.HasPrefix(*basis, "def2") {
		fmt.Println("Told ya to use Karlsruhe basis! RI cannot be activated. Happy now?")
		calc.RI = false
	}
	calc.Basis = *basis
	calc.Job.Opti = true //for the preeliminar calculation we always optimize, regarless of the user's input, because it's, well, a preoptimization.
	if calc.Job.Opti {
		calc.SCFTightness = 1
	}
	calc.Dispersion = "D3"
	//The preeliminar optimization will have a different name.
	namep := strings.Replace(*filename, ".xyz", "OPT", -1)
	name := strings.Replace(*filename, ".xyz", "", -1)
	pre := qm.NewMopacHandle()
	pre.SetName(namep)
	pre.BuildInput(mol.Coords[0], mol, calc)
	pre.Run(true)
	ncoords, err := pre.OptimizedGeometry(mol)
	if err != nil {
		panic(err.Error())
	}
	calc.Job.Opti = *optimize //here we optimize depending on what the user wants
	//MOPAC will overwrite the method, as it doesnt support DFT. This is why we set it AFTER the preeliminar calculations
	calc.Method = *functional
	var QM qmdef
	switch *program {
	default:
		QM = qmdef(qm.NewNWChemHandle())
	case "orca":
		QM = qmdef(qm.NewOrcaHandle())
		//		default:
		//			//There is a hicup with ChemShell since I have not implemented a few methods.
		//			//I should have an interface in goChem that does not require Energy() and OptimizedGeometry()
		//			CS:=qm.NewCSHandle()
		//			CS.SetDefaults()
		//			CS.SetName(name)
		//			CS.BuildInput(ncoords,mol,calc)
	}
	if QM != nil {
		QM.SetDefaults()
		QM.SetName(name)
		QM.BuildInput(ncoords, mol, calc)
	}
	newfilename := strings.Replace(*filename, ".xyz", "_preopt.xyz", 1)
	chem.XYZFileWrite(newfilename, ncoords, mol)
	fmt.Fprintln(os.Stderr, "Apparently, we made it :-)")
}