// calculate angle forces
    void calcAngleForces(AngleTerm angle)
    {
        if (LogLevel >= 1000)
        {
            FFlog.WriteLine("calcAngleForces for {0} - {1} - {2}", angle.Atom1, angle.Atom2, angle.Atom3);
        }
        Vector3 rb1 = position[angle.Atom1] - position[angle.Atom2];
        Vector3 rb2 = position[angle.Atom3] - position[angle.Atom2];

        float cosAlpha = (Vector3.Dot(rb1, rb2)) / (Vector3.Magnitude(rb1) * Vector3.Magnitude(rb2));
        //float angleAlpha = Mathf.Acos(cosAlpha) * (180 / Mathf.PI);
        float mAlpha = angle.kAngle * (Mathf.Acos(cosAlpha) * (180.0f / Mathf.PI) - angle.Aeq);

        Vector3 fI = (mAlpha / (Vector3.Magnitude(rb1) * Mathf.Sqrt(1.0f - cosAlpha * cosAlpha))) * ((rb2 / Vector3.Magnitude(rb2)) - cosAlpha * (rb1 / Vector3.Magnitude(rb1)));
        Vector3 fK = (mAlpha / (Vector3.Magnitude(rb2) * Mathf.Sqrt(1.0f - cosAlpha * cosAlpha))) * ((rb1 / Vector3.Magnitude(rb1)) - cosAlpha * (rb2 / Vector3.Magnitude(rb2)));
        Vector3 fJ = -fI - fK;

        if (LogLevel >= 1000)
        {
            FFlog.WriteLine("angle: {0,12:f3}  angle0: {1,12:f3}  --  moment = {2,14:f5} ", Mathf.Acos(cosAlpha) * (180.0f / Mathf.PI), angle.Aeq, mAlpha);
        }

        if (LogLevel >= 10000)
        {
            FFlog.WriteLine(string.Format("force for atom {0,3}:  ( {1,14:f6} ; {2,14:f6} ; {3,14:f6} )", angle.Atom1, fI.x, fI.y, fI.z));
            FFlog.WriteLine(string.Format("force for atom {0,3}:  ( {1,14:f6} ; {2,14:f6} ; {3,14:f6} )", angle.Atom2, fJ.x, fJ.y, fJ.z));
            FFlog.WriteLine(string.Format("force for atom {0,3}:  ( {1,14:f6} ; {2,14:f6} ; {3,14:f6} )", angle.Atom3, fK.x, fK.y, fK.z));
        }

        forces[angle.Atom1] += fI;
        forces[angle.Atom2] += fJ;
        forces[angle.Atom3] += fK;

        if (LogLevel >= 10000)
        {
            FFlog.WriteLine("Updated forces:");
            for (int iAtom = 0; iAtom < nAtoms; iAtom++)
            {
                FFlog.WriteLine(string.Format(" {0,4:d}  -  {1,5:d}   {2,14:f6} {3,14:f6}  {4,14:f6}",
                                              iAtom, atomList[iAtom],
                                              forces[iAtom].x, forces[iAtom].y, forces[iAtom].z));
            }
        }
    }
    void generateFF()
    {
        bondList.Clear();
        angleList.Clear();
        // set topology array
        bool[,] topo = new bool[nAtoms, nAtoms];
        for (int iAtom = 0; iAtom < nAtoms; iAtom++)
        {
            for (int jAtom = 0; jAtom < nAtoms; jAtom++)
            {
                topo[iAtom, jAtom] = false;
            }
        }

        {
            int iAtom = 0;
            foreach (Atom At1 in GetComponent <GlobalCtrl>().list_curAtoms)
            {
                // cycle through connection points
                foreach (ConnectionStatus conPoint in At1.getAllConPoints())
                {
                    // get current atom index by comparison to entries in atomList
                    int jAtom = -1;
                    for (int kAtom = 0; kAtom < nAtoms; kAtom++)
                    {
                        if (atomList[kAtom] == conPoint.otherAtomID)
                        {
                            jAtom = kAtom;
                            break;
                        }
                    }
                    if (jAtom >= 0)
                    {
                        topo[iAtom, jAtom] = true;
                        topo[jAtom, iAtom] = true;
                    }
                }
                iAtom++;
            }
        }

        // now set all FF terms
        // pairwise terms, run over unique atom pairs
        for (int iAtom = 0; iAtom < nAtoms; iAtom++)
        {
            for (int jAtom = 0; jAtom < iAtom; jAtom++)
            {
                if (topo[iAtom, jAtom])
                {
                    BondTerm newBond = new BondTerm();
                    newBond.Atom1 = jAtom;
                    newBond.Atom2 = iAtom;
                    if (atomType[iAtom] == "C" && atomType[jAtom] == "C")
                    {
                        newBond.kBond = kbCC;
                        newBond.Req   = reqCC;
                    }
                    else if (atomType[iAtom] == "C" && atomType[jAtom] == "H" ||
                             atomType[iAtom] == "H" && atomType[jAtom] == "C")
                    {
                        newBond.kBond = kbCH;
                        newBond.Req   = reqCH;
                    }
                    // RENEW THIS LATER
                    else if (atomType[iAtom] == "C" && atomType[jAtom] == "DUMMY" ||
                             atomType[iAtom] == "DUMMY" && atomType[jAtom] == "C")
                    {
                        newBond.kBond = kbCX;
                        newBond.Req   = reqCX;
                        //newBond.kBond = kbCH;
                        //newBond.Req = reqCH;
                    }
                    else if (atomType[iAtom] == "H" && atomType[jAtom] == "H")
                    {
                        newBond.kBond = kb;
                        newBond.Req   = reqHH;
                    }
                    else if (atomType[iAtom] == "H" && atomType[jAtom] == "DUMMY" ||
                             atomType[iAtom] == "DUMMY" && atomType[jAtom] == "H")
                    {
                        newBond.kBond = kbCX;
                        newBond.Req   = reqHX;
                        //newBond.kBond = kb;
                        //newBond.Req = reqHH;
                    }
                    else // take defaults for the time being
                    {
                        newBond.kBond = kb;
                        newBond.Req   = reqStd;
                    }
                    bondList.Add(newBond);
                }
                // else ... set here non-bonded interactions
            }
        }
        if (LogLevel >= 1000)
        {
            FFlog.WriteLine("Bond terms:");
            FFlog.WriteLine(" Atom1  Atom2      kBond           Req");
            foreach (BondTerm bond in bondList)
            {
                FFlog.WriteLine(string.Format(" {0,4} - {1,4}   {2,12:f3}  {3,12:f3}",
                                              bond.Atom1, bond.Atom2, bond.kBond, bond.Req));
            }
        }

        // angle terms
        // run over unique bond pairs
        foreach (BondTerm bond1 in bondList)
        {
            foreach (BondTerm bond2 in bondList)
            {
                // if we reached the same atom pair, we can skip
                if (bond1.Atom1 == bond2.Atom1 && bond1.Atom2 == bond2.Atom2)
                {
                    break;
                }

                int idx = -1, jdx = -1, kdx = -1;
                if (bond1.Atom1 == bond2.Atom1)
                {
                    idx = bond1.Atom2; jdx = bond1.Atom1; kdx = bond2.Atom2;
                }
                else if (bond1.Atom1 == bond2.Atom2)
                {
                    idx = bond1.Atom2; jdx = bond1.Atom1; kdx = bond2.Atom1;
                }
                else if (bond1.Atom2 == bond2.Atom1)
                {
                    idx = bond1.Atom1; jdx = bond1.Atom2; kdx = bond2.Atom2;
                }
                else if (bond1.Atom2 == bond2.Atom2)
                {
                    idx = bond1.Atom1; jdx = bond1.Atom2; kdx = bond2.Atom1;
                }
                if (idx > -1) // if anything was found: set term
                {
                    AngleTerm newAngle = new AngleTerm();
                    newAngle.Atom1 = kdx;  // I put kdx->Atom1 and idx->Atom3 just for aesthetical reasons ;)
                    newAngle.Atom2 = jdx;
                    newAngle.Atom3 = idx;
                    // currently only this angle type:
                    newAngle.kAngle = ka;
                    newAngle.Aeq    = alphaNull;
                    angleList.Add(newAngle);
                }
            }
        }
        if (LogLevel >= 1000)
        {
            FFlog.WriteLine("Angle terms:");
            FFlog.WriteLine(" Atom1  Atom2  Atom3    kAngle           Aeq");
            foreach (AngleTerm angle in angleList)
            {
                FFlog.WriteLine(string.Format(" {0,4} - {1,4} - {2,4}  {3,12:f3}  {4,12:f3}",
                                              angle.Atom1, angle.Atom2, angle.Atom3, angle.kAngle, angle.Aeq));
            }
        }
    }