Example #1
0
// We want to be able to quickly look up if two atoms are bonded.
// To do this, make a matrix for all atom pairs such that
// M[numAtoms*i+j] & bondtypeflag != 0
func makeBondTypeTable(mol *amber.System) []uint8 {
	numAtoms := mol.NumAtoms()
	bondType := make([]uint8, numAtoms*numAtoms)

	bondsBlocks := []string{"BONDS_INC_HYDROGEN", "BONDS_WITHOUT_HYDROGEN"}
	for _, blockName := range bondsBlocks {
		bonds := amber.VectorAsIntArray(mol.Blocks[blockName])
		// atom_i atom_j indexintostuff
		// These are actually coordinate array indices, not atom indices
		for i := 0; i < len(bonds); i += 3 {
			a, b := bonds[i]/3, bonds[i+1]/3
			bondType[numAtoms*a+b] |= BOND
			bondType[numAtoms*b+a] |= BOND
		}
	}

	angleBlocks := []string{"ANGLES_WITHOUT_HYDROGEN", "ANGLES_INC_HYDROGEN"}
	for _, blockName := range angleBlocks {
		angles := amber.VectorAsIntArray(mol.Blocks[blockName])
		// atom_i atom_j atom_k indexintostuff
		for i := 0; i < len(angles); i += 4 {
			a, b := angles[i]/3, angles[i+2]/3
			bondType[numAtoms*a+b] |= ANGLE
			bondType[numAtoms*b+a] |= ANGLE
		}
	}

	dihedBlocks := []string{"DIHEDRALS_INC_HYDROGEN", "DIHEDRALS_WITHOUT_HYDROGEN"}
	for _, blockName := range dihedBlocks {
		diheds := amber.VectorAsIntArray(mol.Blocks[blockName])
		// atom_i atom_j atom_k atom_l indexintostuff
		for i := 0; i < len(diheds); i += 5 {
			// Fourth coordinate index is negative if this is an improper
			a, b := amber.Abs(diheds[i]/3), amber.Abs(diheds[i+3]/3)
			bondType[numAtoms*a+b] |= DIHEDRAL
			bondType[numAtoms*b+a] |= DIHEDRAL
		}
	}
	return bondType
}
Example #2
0
// Converts the RESIDUE_POINTER block into an array, index by atom, that
// provides the residue number (starting at 0) for each atom.
func makeResidueMap(mol *amber.System) []int {
	residueList := amber.VectorAsIntArray(mol.Blocks["RESIDUE_POINTER"])
	residueMap := make([]int, mol.NumAtoms()) // len(residueList) == #resideus
	for res_i := 1; res_i < len(residueList); res_i++ {
		a := residueList[res_i-1] - 1 // Fortran starts counting at 1
		b := residueList[res_i] - 1
		for i := a; i < b; i++ {
			residueMap[i] = res_i - 1
		}
	}
	// RESIDUE_POINTER doesn't specify the last residue because that's implied
	numResidues := mol.NumResidues()
	for i := residueList[numResidues-1] - 1; i < len(residueMap); i++ {
		residueMap[i] = numResidues - 1
	}
	return residueMap
}
Example #3
0
func main() {
	var prmtopFilename, rstFilename, outFilename string
	var stride int
	var savePreprocessed bool

	flag.StringVar(&prmtopFilename, "p", "prmtop", "Prmtop filename (required)")
	flag.StringVar(&rstFilename, "c", "", "Inpcrd/rst filename")
	flag.IntVar(&stride, "s", 1, "Frame stride; 1 = don't skip any")
	flag.StringVar(&outFilename, "o", "energies.bin", "Energy decomposition output filename")
	flag.BoolVar(&savePreprocessed, "e", false, "Save prmtop preprocessed output (use with -c)")
	flag.Parse()
	trjFilenames := flag.Args()

	mol := amber.LoadSystem(prmtopFilename)
	if mol == nil {
		return
	}
	fmt.Println("Number of atoms:", mol.NumAtoms())
	fmt.Println("Number of residues:", mol.NumResidues())
	hasBox := false
	fmt.Print("Periodic box in prmtop: ")
	if mol.GetInt("POINTERS", amber.IFBOX) > 0 {
		hasBox = true
		fmt.Println("Yes")
	} else {
		fmt.Println("No")
	}

	// Set up nonbonded parameters. We load them here so we don't have to keep
	// doing it later
	var params NonbondedParamsCache
	params.Ntypes = mol.GetInt("POINTERS", amber.NTYPES)
	params.NBIndices = amber.VectorAsIntArray(mol.Blocks["NONBONDED_PARM_INDEX"])  // ICO
	params.AtomTypeIndices = amber.VectorAsIntArray(mol.Blocks["ATOM_TYPE_INDEX"]) // IAC
	params.LJ12 = amber.VectorAsFloat32Array(mol.Blocks["LENNARD_JONES_ACOEF"])    // CN1
	params.LJ6 = amber.VectorAsFloat32Array(mol.Blocks["LENNARD_JONES_BCOEF"])     // CN2
	params.Charges = amber.VectorAsFloat32Array(mol.Blocks["CHARGE"])
	// If we were given a single snapshot, just do that one
	if rstFilename != "" || savePreprocessed {
		var request EnergyCalcRequest
		if rstFilename != "" {
			fmt.Printf("Calculating energies for single snapshot %s.\n", rstFilename)
			mol.LoadRst(rstFilename)
			request.Coords = mol.Coords[0]
		}

		request.NBParams = params
		request.Molecule = mol
		// Lookup table for bond types so we don't calculate electrostatics
		// and such between bonded atoms
		request.BondType = makeBondTypeTable(mol)
		request.ResidueMap = makeResidueMap(mol)
		request.Decomp = make([]float64, mol.NumResidues()*mol.NumResidues())

		// Dump the preprocessed info to a file so a C version of this program can easily load and parse it
		if savePreprocessed {
			outFile, _ := os.OpenFile("solute.top.tom", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
			defer outFile.Close()

			WriteInt32(outFile, mol.NumAtoms())
			WriteInt32(outFile, mol.NumResidues())
			WriteInt32(outFile, params.Ntypes)
			WriteInt32Array(outFile, params.NBIndices)
			WriteInt32Array(outFile, params.AtomTypeIndices)
			WriteFloat32Array(outFile, params.LJ12)
			WriteFloat32Array(outFile, params.LJ6)
			WriteFloat32Array(outFile, params.Charges)
			WriteInt8Array(outFile, request.BondType)
			WriteInt32Array(outFile, request.ResidueMap)
			if hasBox {
				WriteInt32(outFile, 1)
			} else {
				WriteInt32(outFile, 0)
			}

			fmt.Println("Wrote preprocessed prmtop data. Done!")
			os.Exit(0)
		}

		fmt.Println("Electrostatic energy:", Electro(&request), "kcal/mol")
		fmt.Println("van der Waals energy:", LennardJones(&request), "kcal/mol")
		fmt.Println(amber.Status())

		amber.DumpFloat64MatrixAsText(request.Decomp, mol.NumResidues(), "decomp.txt")
		fmt.Println("Saved decomposition matrix to decomp.txt")
	} else if len(trjFilenames) > 0 {
		fmt.Println("Frame stride:", stride)

		// Lookup table for bond types so we don't calculate nonbonded energies
		// between bonded atoms
		bondType := makeBondTypeTable(mol)
		residueMap := makeResidueMap(mol)

		ch := make(chan int)
		decompCh := make(chan []float64, 32)
		// This goroutine will be fed the decomposition matrices made by the energy functions
		fmt.Println("Writing residue decomposition matrices to", outFilename)
		go decompProcessor(outFilename, mol.NumResidues(), decompCh, ch)
		numAtoms := mol.NumAtoms()

		fileId := 0
		trj, err := openTrj(trjFilenames[fileId])
		if err != nil {
			return
		}

		numKids := 0
		frame := 0
		strideCountdown := stride

		for {
			// If there was an error reading the next frame, move on to the next trajectory file
			coords, err := amber.GetNextFrameFromTrajectory(trj, numAtoms, hasBox)
			if err != nil {
				fileId++
				if fileId >= len(trjFilenames) {
					break
				}
				trj, err = openTrj(trjFilenames[fileId])
				if err != nil {
					fmt.Println("Error opening", trjFilenames[fileId])
					break
				}
				coords, err = amber.GetNextFrameFromTrajectory(trj, numAtoms, hasBox)
				if err != nil {
					fmt.Printf("Trajectory file %s doesn't have even one valid frame\n", trjFilenames[fileId])
					break
				}
			}
			frame++
			// Only actually process the frames indicated by stride
			strideCountdown--
			if strideCountdown == 0 {
				strideCountdown = stride
				go calcSingleTrjFrame(mol, params, coords, frame, bondType, residueMap, decompCh, ch)
				numKids++
			}
		}

		if false {
			for i := 0; i < numKids; i++ {
				<-ch
			}
		}
		decompCh <- nil
		<-ch // Wait for decompProcessor to finish
	}
}
Example #4
0
func main() {
	var prmtopFilename, rstFilename, outFilename string
	var stride int
	var savePreprocessed bool

	flag.StringVar(&prmtopFilename, "p", "prmtop", "Prmtop filename (required)")
	flag.StringVar(&rstFilename, "c", "", "Inpcrd/rst filename")
	flag.IntVar(&stride, "s", 1, "Frame stride; 1 = don't skip any")
	flag.StringVar(&outFilename, "o", "energies.bin", "Energy decomposition output filename")
	flag.BoolVar(&savePreprocessed, "e", false, "Save prmtop preprocessed output (use with -c)")
	flag.Parse()

	mol := amber.LoadSystem(prmtopFilename)
	if mol == nil {
		return
	}
	fmt.Println("Number of atoms:", mol.NumAtoms())
	fmt.Println("Number of residues:", mol.NumResidues())
	hasBox := false
	fmt.Print("Periodic box in prmtop: ")
	if mol.GetInt("POINTERS", amber.IFBOX) > 0 {
		hasBox = true
		fmt.Println("Yes")
	} else {
		fmt.Println("No")
	}

	// Set up nonbonded parameters. We load them here so we don't have to keep
	// doing it later
	var params NonbondedParamsCache
	params.Ntypes = mol.GetInt("POINTERS", amber.NTYPES)
	params.NBIndices = amber.VectorAsIntArray(mol.Blocks["NONBONDED_PARM_INDEX"])  // ICO
	params.AtomTypeIndices = amber.VectorAsIntArray(mol.Blocks["ATOM_TYPE_INDEX"]) // IAC
	params.LJ12 = amber.VectorAsFloat32Array(mol.Blocks["LENNARD_JONES_ACOEF"])    // CN1
	params.LJ6 = amber.VectorAsFloat32Array(mol.Blocks["LENNARD_JONES_BCOEF"])     // CN2
	params.Charges = amber.VectorAsFloat32Array(mol.Blocks["CHARGE"])

	var request EnergyCalcRequest
	request.NBParams = params
	request.Molecule = mol
	// Lookup table for bond types so we don't calculate electrostatics
	// and such between bonded atoms
	request.BondType = makeBondTypeTable(mol)
	request.ResidueMap = makeResidueMap(mol)
	request.Decomp = make([]float64, mol.NumResidues()*mol.NumResidues())

	// Dump the preprocessed info to a file so a C version of this program can easily load and parse it
	outFile, _ := os.OpenFile("solute.top.tom", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	defer outFile.Close()

	WriteInt32(outFile, mol.NumAtoms())
	WriteInt32(outFile, mol.NumResidues())
	WriteInt32(outFile, params.Ntypes)
	WriteInt32Array(outFile, params.NBIndices)
	WriteInt32Array(outFile, params.AtomTypeIndices)
	WriteFloat32Array(outFile, params.LJ12)
	WriteFloat32Array(outFile, params.LJ6)
	WriteFloat32Array(outFile, params.Charges)
	WriteInt8Array(outFile, request.BondType)
	WriteInt32Array(outFile, request.ResidueMap)

	if hasBox {
		WriteInt32(outFile, 1)
	} else {
		WriteInt32(outFile, 0)
	}
	fmt.Println("Wrote preprocessed prmtop data. Done!")
	os.Exit(0)
}