// 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 }
// Calculates the nonbonded energies for a single snapshot. // Results are returned through reqOutCh. func calcSingleTrjFrame(mol *amber.System, params NonbondedParamsCache, coords []float32, frame int, bondType []uint8, residueMap []int, reqOutCh chan []float64, ch chan int) { var request EnergyCalcRequest request.Molecule = mol request.Frame = frame request.NBParams = params request.Coords = coords request.BondType = bondType request.ResidueMap = residueMap var ok bool request.Decomp = <-decompFreeList if !ok { fmt.Println("Allocating a new decomposition matrix buffer.") request.Decomp = make([]float64, mol.NumResidues()*mol.NumResidues()) } // Since we're reusing buffers, we need to zero them out for i := 0; i < len(request.Decomp); i++ { request.Decomp[i] = 0.0 } /* //DEBUG: print first few coordinates fmt.Printf("%d [%d]:", frame, len(coords)); for i := 0; i < 6; i++ { fmt.Printf(" %f", coords[i]); } fmt.Println(); */ elec := Electro(&request) vdw := LennardJones(&request) if math.IsNaN(elec) || math.IsNaN(vdw) { fmt.Println("Weird energies. Does your trajectory have boxes but your prmtop doesn't, or vice versa?") os.Exit(1) } fmt.Printf("%d: Electrostatic: %f vdW: %f Total: %f\n", frame, elec, vdw, elec+vdw) // Release coords buffer so it can be reused amber.ReleaseCoordsBuffer(coords) // Send request to listening something that will probably average the decomp matrix // but could in theory do whatever it wants. reqOutCh <- request.Decomp // Return frame ID through channel //ch <- frame }
// 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 }