// RENORM COORDS TO 0-1 range before running ?
  private void runKamadaOn(ArrayList componentNodes) {
    int nNodes = componentNodes.size();
    // sets up the matrix of path distances
    DenseDoubleMatrix2D distMatrix = NetUtilities.getAllShortPathMatrix(componentNodes);
    // sets up kmatrix of forces
    DenseDoubleMatrix2D kMatrix = calcKMatrix(distMatrix, springConst);
    // calc desired distance between nodes
    double optDist = Math.min(width, height) / Math.max(getDiam(distMatrix), 1);
    // sets up lMatrix of distance between nodes pairs
    DenseDoubleMatrix2D lMatrix = calcLMatrix(distMatrix, optDist);
    // arrays for quick acess to node coords
    double[] xPos = new double[nNodes];
    double[] yPos = new double[nNodes];

    int numEdges = 0;

    for (int i = 0; i < nNodes; i++) {
      DrawableNonGridNode workNode = (DrawableNonGridNode) componentNodes.get(i);
      xPos[i] = workNode.getX();
      yPos[i] = workNode.getY();
      numEdges += ((ArrayList) workNode.getOutEdges()).size();
    }

    // calc value to start minimization from (should be based on previous?)
    // epsilon = (nNodes * numEdges)/2;
    // figure out the initial stat to compare to at the end
    double initialEnergy = getEnergy(lMatrix, kMatrix, xPos, yPos);
    double epsilon = initialEnergy / nNodes;
    // figure out which node to start moving first
    double deltaM;
    int maxDeltaMIndex = 0;
    double maxDeltaM = getDeltaM(0, lMatrix, kMatrix, xPos, yPos);
    for (int i = 1; i < nNodes; i++) {
      deltaM = getDeltaM(i, lMatrix, kMatrix, xPos, yPos);
      if (deltaM > maxDeltaM) {
        maxDeltaM = deltaM;
        maxDeltaMIndex = i;
      }
    }

    int passes = 0;
    int subPasses = 0;
    // epsilon minimizing loop
    while ((epsilon > minEpsilon) && !stop) {
      double previousMaxDeltaM = maxDeltaM + 1;
      // KAMADA-KAWAI LOOP: while the deltaM of the node with
      // the largest deltaM  > epsilon..
      while ((maxDeltaM > epsilon) && ((previousMaxDeltaM - maxDeltaM) > 0.1) && !stop) {

        double[] deltas;
        double moveNodeDeltaM = maxDeltaM;
        // double previousDeltaM = moveNodeDeltaM + 1;

        // KK INNER LOOP while the node with the largest energy > epsilon...
        while ((moveNodeDeltaM > epsilon) && !stop) {

          // get the deltas which will move node towards the local minima
          deltas = getDeltas(maxDeltaMIndex, lMatrix, kMatrix, xPos, yPos);
          // set coords of node to old coords + changes
          xPos[maxDeltaMIndex] += deltas[0];
          yPos[maxDeltaMIndex] += deltas[1];
          // previousDeltaM = moveNodeDeltaM;
          // recalculate the deltaM of the node w/ new vals
          moveNodeDeltaM = getDeltaM(maxDeltaMIndex, lMatrix, kMatrix, xPos, yPos);
          subPasses++;
          if (subPasses > maxPasses) stop = true;
        }
        // previousDeltaM = maxDeltaM;
        // recalculate deltaMs and find node with max
        maxDeltaMIndex = 0;
        maxDeltaM = getDeltaM(0, lMatrix, kMatrix, xPos, yPos);
        for (int i = 1; i < nNodes; i++) {
          deltaM = getDeltaM(i, lMatrix, kMatrix, xPos, yPos);
          if (deltaM > maxDeltaM) {
            maxDeltaM = deltaM;
            maxDeltaMIndex = i;
          }
        }

        // if set to update display, update on every nth pass
        if (updates > 0) {
          if ((passes % updates) == 0) {
            for (int i = 0; i < nNodes; i++) {
              DrawableNonGridNode node = (DrawableNonGridNode) componentNodes.get(i);
              node.setX(xPos[i]);
              node.setY(yPos[i]);
            }
            updateDisplay();
          }
        }

        passes++;
      }

      epsilon -= epsilon / 4;
    }

    if (animate) animateTransition(8, componentNodes, xPos, yPos);
    else {
      // set positions of nodes to coord array vals
      for (int i = 0; i < nNodes; i++) {
        DrawableNonGridNode node = (DrawableNonGridNode) componentNodes.get(i);
        node.setX(xPos[i]);
        node.setY(yPos[i]);
      }
    }
  }