public void GetHess4PwIntrActNonbondeds(List <ForceField.IForceField> frcflds, Vector[] coords, Dictionary <Pair <int, int>, ForceField.PwIntrActInfo> pwintractinfos) { List <ForceField.INonbonded> frcfld_nonbondeds = SelectInFrcflds(frcflds, new List <ForceField.INonbonded>()); Nonbondeds_v1 nonbondeds = null; { // compute all non-bondeds double nonbondeds_maxdist = double.PositiveInfinity; nonbondeds = new Nonbondeds_v1(atoms, size, nonbondeds_maxdist); nonbondeds.UpdateNonbondeds(coords, 0); } Vector[] lcoords = new Vector[2]; Vector[] lforces = new Vector[2]; foreach (Nonbonded nonbond in nonbondeds) { int id0 = nonbond.atoms[0].ID; lcoords[0] = coords[id0]; int id1 = nonbond.atoms[1].ID; lcoords[1] = coords[id1]; int[] ids = new int[] { id0, id1 }; foreach (ForceField.IHessBuilder4PwIntrAct frcfld in frcfld_nonbondeds) { Pair <int, int>[] lpwidxs; ForceField.PwIntrActInfo[] lpwintractinfos; frcfld.BuildHess4PwIntrAct(nonbond, lcoords, out lpwidxs, out lpwintractinfos); // rearrange index as {(min1,max1), (min2,max2), ... } for (int j = 0; j < lpwidxs.Length; j++) { int idxmin = Math.Min(ids[lpwidxs[j].Item1], ids[lpwidxs[j].Item2]); int idxmax = Math.Max(ids[lpwidxs[j].Item1], ids[lpwidxs[j].Item2]); Pair <int, int> key = new Pair <int, int>(idxmin, idxmax); pwintractinfos[key] += lpwintractinfos[j]; } } } }
public double GetPotentialUpdated_ComputeCustomsNonbonded(List <ForceField.IForceField> frcflds, bool[] updated , double energy0, Vector[] coords0, Vector[] coords , Vector[] dforces , ref Nonbondeds_v1 nonbondeds ) //, Vector[] coords0, Vector[] coords, ref Nonbondeds nonbondeds, List<GetForcesCompUnit> compunits) { List <ForceField.INonbonded> frcfld_nonbondeds = SelectInFrcflds(frcflds, new List <ForceField.INonbonded>()); Vector[] buffCoords = Vector.NewVectors(2, new double[3]); Vector[] buffForces = Vector.NewVectors(2, new double[3]); int[] buffIdx = new int[2]; double energy = energy0; ///////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////// // Nonbonded14 { foreach (Nonbonded14 nonbond in nonbonded14s) { bool updated0 = updated[nonbond.atoms[0].ID]; bool updated1 = updated[nonbond.atoms[1].ID]; if (updated0 || updated1) { foreach (ForceField.INonbonded frcfld in frcfld_nonbondeds) { energy += GetPotentialUpdated_Compute(nonbond, frcfld.Compute, coords0, coords, dforces, buffIdx, buffCoords, buffForces, true, true); } } } } ///////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////// // Nonbonded { /////////////////////////////////////////// // compute old nonbondeds if (nonbondeds == null) { /////////////////////////////////////////// // build nonbondeds structure HDebug.Assert(nonbondeds == null); double nonbondeds_maxdist = 12; nonbondeds = new Nonbondeds_v1(atoms, size, nonbondeds_maxdist); nonbondeds.UpdateNonbondeds(coords, 0); } else { /////////////////////////////////////////// // remove updated old nonbondeds structure if (coords0 != null) { foreach (Nonbonded nonbond in nonbondeds) { bool updated0 = updated[nonbond.atoms[0].ID]; bool updated1 = updated[nonbond.atoms[1].ID]; if (updated0 || updated1) { foreach (ForceField.INonbonded frcfld in frcfld_nonbondeds) { energy += GetPotentialUpdated_Compute(nonbond, frcfld.Compute, coords0, coords, dforces, buffIdx, buffCoords, buffForces, true, false); } } } } /////////////////////////////////////////// // updated nonbondeds structure nonbondeds.UpdateNonbondeds(coords, 0.01); } /////////////////////////////////////////// // compute new nonbondeds foreach (Nonbonded nonbond in nonbondeds) { bool updated0 = updated[nonbond.atoms[0].ID]; bool updated1 = updated[nonbond.atoms[1].ID]; if (updated0 || updated1) { foreach (ForceField.INonbonded frcfld in frcfld_nonbondeds) { energy += GetPotentialUpdated_Compute(nonbond, frcfld.Compute, coords0, coords, dforces, buffIdx, buffCoords, buffForces, false, true); } } } } return(energy); }
static double GetPotentialUpdated_ProbToCheckWithGetPotential = 0;//1;//0.1; public double GetPotentialUpdated(List <ForceField.IForceField> frcflds , double?energy0, Vector[] coords0, Vector[] forces0 , Vector[] coords, Vector[] forces , ref Nonbondeds_v1 nonbondeds ) { if (GetPotentialUpdated_SelfTestDo == true) #region selftest { GetPotentialUpdated_SelfTest(frcflds, energy0, coords0, forces0, coords, forces); } #endregion bool[] updated = new bool[size]; if ((energy0 == null) || (nonbondeds == null)) { HDebug.AssertIf(energy0 == null, coords0 == null); HDebug.AssertIf(energy0 == null, forces0 == null); energy0 = 0; coords0 = null; forces0 = null; for (int i = 0; i < size; i++) { forces[i] = new double[3]; } for (int i = 0; i < size; i++) { updated[i] = true; } } else { HDebug.Assert(size == coords0.Length); HDebug.Assert(size == forces0.Length); HDebug.Assert(size == coords.Length); HDebug.Assert(size == forces.Length); for (int i = 0; i < size; i++) { forces[i] = forces0[i].Clone(); } int countskip = 0; //double[] dist2s = new double[size]; //for(int i=0; i<size; i++) // dist2s[i] = (coords0[i] - coords[i]).Dist2; //int[] idxsorted = dist2s.IdxSorted(); //for(int i=0; i<size; i++) // updated[i] = (dist2s[i] > (0.000001*0.000001)); //for(int i=size/2; i<size; i++) // updated[idxsorted[i]] = true; for (int i = 0; i < size; i++) { updated[i] = (coords0[i] != coords[i]); } for (int i = 0; i < size; i++) { countskip += (updated[i] == false) ? 1 : 0; } if ((size - countskip) * 10 > size) { energy0 = 0; coords0 = null; forces0 = null; for (int i = 0; i < size; i++) { forces[i] = new double[3]; } for (int i = 0; i < size; i++) { updated[i] = true; } } System.Console.Write(" countskip({0:000}) ", countskip); } Vector[] dforces = GetVectorsZero(); double denergy = 0; denergy += GetPotentialUpdated_ComputeCustomsBond(frcflds, updated, 0, coords0, coords, dforces); denergy += GetPotentialUpdated_ComputeCustomsAngle(frcflds, updated, 0, coords0, coords, dforces); denergy += GetPotentialUpdated_ComputeCustomsDihedral(frcflds, updated, 0, coords0, coords, dforces); denergy += GetPotentialUpdated_ComputeCustomsImproper(frcflds, updated, 0, coords0, coords, dforces); denergy += GetPotentialUpdated_ComputeCustomsNonbonded(frcflds, updated, 0, coords0, coords, dforces, ref nonbondeds); //energy += GetPotentialUpdated_ComputeCustomsCustoms (frcflds, updated, 0, coords0, forces0, coords, forces); double energy = energy0.Value + denergy; for (int i = 0; i < size; i++) { forces[i] += dforces[i]; } #region commented from threading //Nonbondeds lnonbondeds = nonbondeds; // //double energy = energy0.Value; // //object lockobj = new object(); //System.Threading.Tasks.ParallelOptions parallelOptions = new ParallelOptions(); ////parallelOptions.MaxDegreeOfParallelism = 1; //Parallel.ForEach(compunits_bonded, parallelOptions, delegate(GetForcesCompUnit compunit) //{ // if(compunit == null) // { // // in the first iteration, collect nonbonded components // GetForces_CollectCompUnitNonbonded(frcflds, updated, coords0, coords, ref lnonbondeds, compunits_nonbonded); // } // else // { // Triple<double, int[], Vector[]> denergy_idx_dforces = compunit.Compute(coords0, coords); // double denergy = denergy_idx_dforces.first; // int[] idx = denergy_idx_dforces.second; // Vector[] dforces = denergy_idx_dforces.third; // Debug.Assert(idx.Length == dforces.Length); // lock(lockobj) // { // energy += denergy; // for(int i=0; i<idx.Length; i++) // forces[idx[i]] += dforces[i]; // } // } //}); //nonbondeds = lnonbondeds; //Parallel.ForEach(compunits_nonbonded, parallelOptions, delegate(GetForcesCompUnit compunit) //{ // Triple<double, int[], Vector[]> denergy_idx_dforces = compunit.Compute(coords0, coords); // double denergy = denergy_idx_dforces.first; // int[] idx = denergy_idx_dforces.second; // Vector[] dforces = denergy_idx_dforces.third; // Debug.Assert(idx.Length == dforces.Length); // lock(lockobj) // { // energy += denergy; // for(int i=0; i<idx.Length; i++) // forces[idx[i]] += dforces[i]; // } //}); #endregion if (HDebug.IsDebuggerAttachedWithProb(GetPotentialUpdated_ProbToCheckWithGetPotential)) #region check force with GetPotential(...) { //Vector[] _forces0 = GetVectorsZero(); //Matrix _hessian0 = null; //double _energy0 = GetPotential(frcflds, coords0, ref _forces0, ref _hessian0, new Dictionary<string,object>()); //Debug.AssertTolerance(0.00000001, energy0 - _energy0); //Debug.AssertTolerance(0.00000001, Vector.Sub(forces0, _forces0)); Vector[] _forces = GetVectorsZero(); MatrixByArr _hessian = null; double _energy = GetPotential(frcflds, coords, ref _forces, ref _hessian, new Dictionary <string, object>()); HDebug.AssertTolerance(0.00000001, energy - _energy); HDebug.AssertToleranceVector(0.00000001, Vector.Sub(forces, _forces)); } #endregion //if(cache != null) //{ // if(cache.ContainsKey("energy_bonds ") == false) cache.Add("energy_bonds ", 0); cache["energy_bonds "] = energy_bonds ; // if(cache.ContainsKey("energy_angles ") == false) cache.Add("energy_angles ", 0); cache["energy_angles "] = energy_angles ; // if(cache.ContainsKey("energy_dihedrals ") == false) cache.Add("energy_dihedrals ", 0); cache["energy_dihedrals "] = energy_dihedrals ; // if(cache.ContainsKey("energy_impropers ") == false) cache.Add("energy_impropers ", 0); cache["energy_impropers "] = energy_impropers ; // if(cache.ContainsKey("energy_nonbondeds") == false) cache.Add("energy_nonbondeds", 0); cache["energy_nonbondeds"] = energy_nonbondeds; // if(cache.ContainsKey("energy_customs ") == false) cache.Add("energy_customs ", 0); cache["energy_customs "] = energy_customs ; //} return(energy); }
public int Minimize_ConjugateGradient_AtomwiseUpdate( List <ForceField.IForceField> frcflds , double threshold = 0.001 // * threshold for forces.NormInf , double?k = null // * step step // 0.0001 , double max_atom_movement = 0.1 // * maximum atom movement , int?max_iteration = null // null for the infinite iteration until converged , bool[] atomsMovable = null // * selection of movable atoms // move all atoms if (atomsMovable == null) or (atomsMovable[all] == true) // move only atom whose (atomsMovable[id] == true) , IMinimizeLogger logger = null // * write log // = new MinimizeLogger_PrintEnergyForceMag() , InfoPack extra = null // get extra information , bool?doSteepDeescent = null // null or true for default , HPack <double> optOutEnergy = null // optional output for final energy , List <Vector> optOutForces = null // optional output for final force vectors , HPack <double> optOutForcesNorm1 = null // optional output for norm of final force vectors , HPack <double> optOutForcesNorm2 = null // optional output for norm of final force vectors , HPack <double> optOutForcesNormInf = null // optional output for norm of final force vectors ) { if (doSteepDeescent == null) { doSteepDeescent = true; } if (k == null) { k = double.MaxValue; foreach (ForceField.IForceField frcfld in frcflds) { double?kk = frcfld.GetDefaultMinimizeStep(); if (kk.HasValue) { k = Math.Min(k.Value, kk.Value); } } } int iter = 0; // 0. Initial configuration of atoms Vector[] coords = GetCoords(); if (atomsMovable == null) { atomsMovable = new bool[size]; for (int i = 0; i < size; i++) { atomsMovable[i] = true; } } Vectors h = GetVectorsZero(); Vectors forces = Vector.NewVectors(size, new double[3]); Vectors moves = Vector.NewVectors(size, new double[3]); Nonbondeds_v1 nonbondeds = null; // Dictionary<string,object> cache = new Dictionary<string, object>(); double energy = GetPotentialUpdated(frcflds, null, null, null, coords, forces, ref nonbondeds); double forces_NormInf = NormInf(forces, atomsMovable); double forces_Norm1 = Norm(1, forces, atomsMovable); double forces_Norm2 = Norm(2, forces, atomsMovable); Vector[] forces0 = forces; double energy0 = energy; Vectors moves0 = moves; double leastMove = 0.000001; while (true) { if (forces.IsComputable == false) { System.Console.Error.WriteLine("non-computable components while doing steepest-descent"); HEnvironment.Exit(0); } if (logger != null) { logger.log(iter, coords, energy, forces, atomsMovable); logger.logTrajectory(this, iter, coords); } // 1. Save the position of atoms // 2. Calculate the potential energy of system and the net forces on atoms // 3. Check if every force reaches to zero, // , and END if yes bool stopIteration = false; if (forces_NormInf < threshold) { stopIteration = true; } if ((max_iteration != null) && (iter >= max_iteration.Value)) { stopIteration = true; } if (stopIteration) { // double check //cache = new Dictionary<string, object>(); // reset cache //energy = GetPotential(frcflds, coords, out forces, cache); nonbondeds = null; energy = GetPotentialUpdated(frcflds, null, null, null, coords, forces, ref nonbondeds); forces_NormInf = NormInf(forces, atomsMovable); forces_Norm1 = Norm(1, forces, atomsMovable); forces_Norm2 = Norm(2, forces, atomsMovable); if (forces_NormInf < threshold) { if (iter != 1) { SetCoords(coords); } { if (optOutEnergy != null) { optOutEnergy.value = energy; } if (optOutForces != null) { optOutForces.Clear(); optOutForces.AddRange(forces.ToArray()); } if (optOutForcesNorm1 != null) { optOutForcesNorm1.value = forces_Norm1; } if (optOutForcesNorm2 != null) { optOutForcesNorm2.value = forces_Norm2; } if (optOutForcesNormInf != null) { optOutForcesNormInf.value = forces_NormInf; } } return(iter); } } // 4. Move atoms with conjugated gradient Vectors coords_prd; double kk; { if ((iter > 0) && (iter % 100 == 0)) { //cache = new Dictionary<string, object>(); // reset cache nonbondeds = null; } if (iter > 1) { HDebug.Assert(forces0 != null); double r = Vectors.VtV(forces, forces).Sum() / Vectors.VtV(forces0, forces0).Sum(); h = forces + r * h; kk = k.Value; double hNormInf = NormInf(h, atomsMovable); if (kk * hNormInf > max_atom_movement) { // make the maximum movement as atomsMovable kk = max_atom_movement / (hNormInf); } moves = moves0.Clone(); coords_prd = AddConditional(coords, atomsMovable, moves, kk * h, leastMove); } else { // same to the steepest descent for the first iteration h = forces; kk = k.Value; double hNormInf = NormInf(h, atomsMovable); if (kk * hNormInf > max_atom_movement) { // make the maximum movement as atomsMovable kk = max_atom_movement / (hNormInf); } //double kk = (k*h.NormsInf().NormInf() < max_atom_movement) ? k : (max_atom_movement/h.NormsInf().NormInf()); //double kk = (k.Value*NormInf(h,atomsMovable) < max_atom_movement)? k.Value : (max_atom_movement/NormInf(h, atomsMovable)); moves = moves0.Clone(); coords_prd = AddConditional(coords, atomsMovable, moves, kk * h, leastMove); } } // 5. Predict energy or forces on atoms Vectors forces_prd = forces.Clone(); double energy_prd = GetPotentialUpdated(frcflds, energy, coords, forces, coords_prd, forces_prd, ref nonbondeds); iter++; //double energy_prd = GetPotential(frcflds, coords_prd, out forces_prd, cache); iter++; double forces_prd_NormInf = NormInf(forces_prd, atomsMovable); double forces_prd_Norm1 = Norm(1, forces_prd, atomsMovable); double forces_prd_Norm2 = Norm(2, forces_prd, atomsMovable); // 6. Check if the predicted forces or energy will exceed over the limit // , and goto 1 if no doSteepDeescent = true; //if((doSteepDeescent == false) || ((energy_prd <= energy) && (forces_prd_NormInf < forces_NormInf+1.0)) if ((energy_prd < energy + 0.1) && (forces_prd_NormInf < forces_NormInf + 0.0001)) { energy0 = energy; forces0 = forces; moves0 = moves; coords = coords_prd; forces = forces_prd; energy = energy_prd; forces_NormInf = forces_prd_NormInf; forces_Norm1 = forces_prd_Norm1; forces_Norm2 = forces_prd_Norm2; continue; } if (logger != null) { logger.log(iter, coords_prd, energy_prd, forces_prd, atomsMovable, "will do steepest"); } // 7. Back to saved configuration // 8. Move atoms with simple gradient { // same to the steepest descent h = forces; kk = k.Value; double hNormInf = NormInf(h, atomsMovable); if (kk * hNormInf > max_atom_movement) { // make the maximum movement as atomsMovable kk = max_atom_movement / (hNormInf); } moves = moves0.Clone(); coords_prd = AddConditional(coords, atomsMovable, moves, kk * h, leastMove); } //energy_prd = GetPotential(frcflds, coords_prd, out forces_prd, cache); energy_prd = GetPotentialUpdated(frcflds, energy, coords, forces, coords_prd, forces_prd, ref nonbondeds); forces_prd_NormInf = NormInf(forces_prd, atomsMovable); forces_prd_Norm1 = Norm(1, forces_prd, atomsMovable); forces_prd_Norm2 = Norm(2, forces_prd, atomsMovable); energy0 = energy; forces0 = forces; moves0 = moves; coords = coords_prd; forces = forces_prd; energy = energy_prd; forces_NormInf = forces_prd_NormInf; forces_Norm1 = forces_prd_Norm1; forces_Norm2 = forces_prd_Norm2; // 9. goto 1 } }
public double GetPotentialNonbondeds(List <ForceField.IForceField> frcflds, Vector[] coords, ref Vector[] forces, ref MatrixByArr[,] hessian, Dictionary <string, object> cache, PwForceDecomposer forceij, double[,] pwfrc = null, double[,] pwspr = null) { List <ForceField.INonbonded> frcfld_nonbondeds = SelectInFrcflds(frcflds, new List <ForceField.INonbonded>()); double energy = 0; if (frcfld_nonbondeds.Count == 0) { return(energy); } Vector[] lcoords = new Vector[2]; Vector[] lforces = (forces == null) ? null : new Vector[2]; Nonbondeds_v1 nonbondeds = null; if (cache == null) { cache = new Dictionary <string, object>(); } if (cache.ContainsKey("all nonbondeds")) { // compute all non-bondeds double nonbondeds_maxdist = double.PositiveInfinity; nonbondeds = new Nonbondeds_v1(atoms, size, nonbondeds_maxdist); nonbondeds.UpdateNonbondeds(coords, 0); cache.Add("nonbondeds", nonbondeds); } else if (cache.ContainsKey("nonbondeds")) { // use existing cached nonbondeds, but update it as well nonbondeds = (Nonbondeds_v1)cache["nonbondeds"]; nonbondeds.UpdateNonbondeds(coords, 0.01); } else { // create default nonbondeds, and add it into cache nonbondeds = new Nonbondeds_v1(atoms, size, 12); nonbondeds.UpdateNonbondeds(coords, 0); cache.Add("nonbondeds", nonbondeds); } double stat_min = double.MaxValue; double stat_max = double.MinValue; double netstat_min = double.MaxValue; double netstat_max = double.MinValue; foreach (Nonbonded nonbond in nonbondeds) { ///{ // this removes interactions in-between rigid atoms. /// Atom atom0 = nonbond.atoms[0]; /// Atom atom1 = nonbond.atoms[1]; /// HashSet<Atom> atomsInRigid0 = GetAtomsInRigid(atom0); /// if(atomsInRigid0.Contains(atom1)) /// continue; ///} int id0 = nonbond.atoms[0].ID; lcoords[0] = coords[id0]; int id1 = nonbond.atoms[1].ID; lcoords[1] = coords[id1]; foreach (ForceField.INonbonded frcfld in frcfld_nonbondeds) { if (forces != null) { lforces[0] = new double[3]; lforces[1] = new double[3]; } MatrixByArr[,] lhess = (hessian == null) ? null : LinAlg.CreateMatrixArray(2, 2, new double[3, 3]); double[,] lpwfrc = new double[2, 2]; double[,] lpwspr = new double[2, 2]; frcfld.Compute(nonbond, lcoords, ref energy, ref lforces, ref lhess, lpwfrc, lpwspr); HDebug.Assert(double.IsNaN(energy) == false, double.IsInfinity(energy) == false); if (forces != null) { forces[id0] += lforces[0]; forces[id1] += lforces[1]; if (forceij != null) { forceij.AddNonbonded(id0, id1, lcoords, lforces); } HDebug.AssertTolerance(0.00000001, lforces[0].Dist2 - lforces[1].Dist2); double netstat = lforces[0].Dist2 + lforces[1].Dist2; netstat_min = Math.Min(netstat_min, netstat); netstat_max = Math.Max(netstat_max, netstat); stat_min = Math.Min(stat_min, lforces[0].Dist); stat_max = Math.Max(stat_max, lforces[0].Dist); stat_min = Math.Min(stat_min, lforces[1].Dist); stat_max = Math.Max(stat_max, lforces[1].Dist); } if (hessian != null) { hessian[id0, id0] += lhess[0, 0]; hessian[id0, id1] += lhess[0, 1]; hessian[id1, id0] += lhess[1, 0]; hessian[id1, id1] += lhess[1, 1]; } if (pwfrc != null) { pwfrc[id0, id0] += lpwfrc[0, 0]; pwfrc[id0, id1] += lpwfrc[0, 1]; pwfrc[id1, id0] += lpwfrc[1, 0]; pwfrc[id1, id1] += lpwfrc[1, 1]; } if (pwspr != null) { pwspr[id0, id0] += lpwspr[0, 0]; pwspr[id0, id1] += lpwspr[0, 1]; pwspr[id1, id0] += lpwspr[1, 0]; pwspr[id1, id1] += lpwspr[1, 1]; } } } double stat14_min = double.MaxValue; double stat14_max = double.MinValue; double netstat14_min = double.MaxValue; double netstat14_max = double.MinValue; foreach (Nonbonded14 nonbond in nonbonded14s) { int id0 = nonbond.atoms[0].ID; lcoords[0] = coords[id0]; int id1 = nonbond.atoms[1].ID; lcoords[1] = coords[id1]; foreach (ForceField.INonbonded frcfld in frcfld_nonbondeds) { if (forces != null) { lforces[0] = new double[3]; lforces[1] = new double[3]; } MatrixByArr[,] lhess = (hessian == null) ? null : LinAlg.CreateMatrixArray(2, 2, new double[3, 3]); double[,] lpwfrc = new double[2, 2]; double[,] lpwspr = new double[2, 2]; frcfld.Compute(nonbond, lcoords, ref energy, ref lforces, ref lhess, pwfrc, pwspr); HDebug.Assert(double.IsNaN(energy) == false, double.IsInfinity(energy) == false); if (forces != null) { forces[id0] += lforces[0]; forces[id1] += lforces[1]; if (forceij != null) { forceij.AddNonbonded14(id0, id1, lcoords, lforces); } HDebug.AssertTolerance(0.00000001, lforces[0].Dist2 - lforces[1].Dist2); double netstat = lforces[0].Dist2 + lforces[1].Dist2; netstat14_min = Math.Min(netstat14_min, netstat); netstat14_max = Math.Max(netstat14_max, netstat); stat14_min = Math.Min(stat14_min, lforces[0].Dist); stat14_max = Math.Max(stat14_max, lforces[0].Dist); stat14_min = Math.Min(stat14_min, lforces[1].Dist); stat14_max = Math.Max(stat14_max, lforces[1].Dist); } if (hessian != null) { hessian[id0, id0] += lhess[0, 0]; hessian[id0, id1] += lhess[0, 1]; hessian[id1, id0] += lhess[1, 0]; hessian[id1, id1] += lhess[1, 1]; } if (pwfrc != null) { pwfrc[id0, id0] += lpwfrc[0, 0]; pwfrc[id0, id1] += lpwfrc[0, 1]; pwfrc[id1, id0] += lpwfrc[1, 0]; pwfrc[id1, id1] += lpwfrc[1, 1]; } if (pwspr != null) { pwspr[id0, id0] += lpwspr[0, 0]; pwspr[id0, id1] += lpwspr[0, 1]; pwspr[id1, id0] += lpwspr[1, 0]; pwspr[id1, id1] += lpwspr[1, 1]; } } } return(energy); }