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];
                    }
                }
            }
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        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
            }
        }
Esempio n. 5
0
        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);
        }