private double calculateMonthlyCost(cluster clust)
        {
            int monthHours = 4 * (int)weekly_load_days * (int)daily_load_hours;
            double costPerHour = electricity_cost * (clust.getClusterTDP() / 1000);

            return costPerHour * monthHours * (average_load_percentage / 100);
        }
        private void generateViableClusters()
        {
            doneGeneratingCluster = false;
            readyToGenerateClusters = false;
            int zeroResultCount = 0;
            bool ended = false;

            int step = (int)(prg_1.Maximum / (int)max_racks) - 1;

            int clustersSoFar = 0;
            long start = CurrentTimeSeconds();

            for (int k = (int)max_racks; k >= 1; k--)
            {
                    Parallel.ForEach(allPossibleRacks, currentRack =>
                    {

                        cluster tmpCluster = new cluster(k, currentRack);

                        if (
                            //performance needs
                            cpu_gflops >= tmpCluster.getClusterCPUGFLOPS() ||
                            gpu_sp_tflops >= tmpCluster.getClusterGPUTFLOPS_sp() ||
                            gpu_dp_gflops >= tmpCluster.getClusterGPUTFLOPS_dp() ||
                            min_ram >= tmpCluster.getClusterRAM() ||
                            min_vram >= tmpCluster.getClusterVRAM() ||

                            //budget constraint
                            monthly_power_budget <= calculateMonthlyCost(tmpCluster) ||
                            total_budget <= calculateInitialClusterCost(tmpCluster) ||

                            //power constraints
                            max_cluster_power <= tmpCluster.getClusterTDP() ||
                            max_rack_power <= tmpCluster.getRackUsed().getRackTDP() ||

                            // memory per Core rule
                            tmpCluster.getRAMperCore() < min_ram_per_core)
                        {
                            //exclude cluster
                        }
                        else //include cluster
                            viableClusters.Add(tmpCluster);

                    });

                    prg_1.Value = Math.Abs(prg_1.Maximum - (k * step));
                    int clustersOfThisSize = viableClusters.Count - clustersSoFar;

                    txt_log.AppendText(Environment.NewLine + "Viable Clusters of size " + k + ":\t" + clustersOfThisSize);
                    clustersSoFar = viableClusters.Count;
                }
                prg_1.Value = prg_1.Maximum;
                if (viableClusters.Count == 1)
                {
                    bestCluster = viableClusters.ElementAt(0);
                    txt_log.Text = bestCluster.getDetails() + Environment.NewLine + "TOTAL MONTHLY COST:\t\t" + string.Format("{0:0.00}", calculateMonthlyCost(bestCluster)) + "\t USD";
                    bestClusterMsg = txt_log.Lines.ToList();
                }
                else if (viableClusters.Count > 1)
                {
                    setPriorities();

                    int beforeFilter1 = 0;
                    int beforeFilter2 = 0;
                    int beforeFilter3 = 0;

                    ConcurrentBag<cluster> tmpList = viableClusters;

                    int cnt = 0;

                    bool cont = true;
                    while (cont)
                    {
                        //filter 1st priority
                        int tmp1 = tmpList.Count;
                        tmpList = binaryFilter(tmpList, p1); txt_log.AppendText(Environment.NewLine + "Finding optimal solution step " + ++cnt + " : " + +tmpList.Count);
                        if (tmpList.Count > 1) { cont = false; }

                        beforeFilter1 += Math.Abs(tmpList.Count - tmp1);
                        tmp1 = tmpList.Count;

                        tmpList = binaryFilter(tmpList, p1); txt_log.AppendText(Environment.NewLine + "Finding optimal solution step " + ++cnt + " : " + +tmpList.Count);
                        if (tmpList.Count > 1) { cont = false; }

                        beforeFilter1 += Math.Abs(tmpList.Count - tmp1);
                        tmp1 = tmpList.Count;

                        tmpList = binaryFilter(tmpList, p1); txt_log.AppendText(Environment.NewLine + "Finding optimal solution step " + ++cnt + " : " + +tmpList.Count);
                        if (tmpList.Count > 1) { cont = false;};

                        beforeFilter1 += Math.Abs(tmpList.Count - tmp1);
                        tmp1 = tmpList.Count;

                        //filter 2st priority

                        int tmp2 = tmpList.Count;
                        tmpList = binaryFilter(tmpList, p2); txt_log.AppendText(Environment.NewLine + "Finding optimal solution step " + ++cnt + " : " + +tmpList.Count);
                        if (tmpList.Count > 1) { cont = false;}

                        beforeFilter2 += Math.Abs(tmpList.Count - tmp2);
                        tmp2 = tmpList.Count;

                        tmpList = binaryFilter(tmpList, p2); txt_log.AppendText(Environment.NewLine + "Finding optimal solution step " + ++cnt + " : " + +tmpList.Count);
                        if (tmpList.Count > 1) { cont = false; }

                        beforeFilter2 += Math.Abs(tmpList.Count - tmp2);
                        tmp2 = tmpList.Count;

                        //filter 3st priority

                        int tmp3 = tmpList.Count;
                        tmpList = binaryFilter(tmpList, p3); txt_log.AppendText(Environment.NewLine + "Finding optimal solution step " + ++cnt + " : " + +tmpList.Count);
                        if (tmpList.Count > 1) { cont = false; }

                        beforeFilter3 += Math.Abs(tmpList.Count - tmp3);
                        tmp3 = tmpList.Count;

                        while((beforeFilter1 + beforeFilter2 + beforeFilter3 + 1) < viableClusters.Count){if (beforeFilter2 > beforeFilter3) beforeFilter3++;else beforeFilter2++;
                        }
                    }

                    bestCluster = tmpList.ElementAt(0);
                    txt_log.Text = bestCluster.getDetails() + Environment.NewLine + "TOTAL MONTHLY COST:\t\t" + string.Format("{0:0.00}", calculateMonthlyCost(bestCluster)) + "\t USD";
                    txt_log.Text += Environment.NewLine + Environment.NewLine + "Priorities:" +
                                                                         Environment.NewLine + "1st:\t" + getPriorityString(p1) + "\tFiltered out\t" + beforeFilter1 + "/"+ viableClusters.Count +
                                                                         Environment.NewLine + "2nd:\t" + getPriorityString(p2) + "\tFiltered out\t" + beforeFilter2 + "/" + viableClusters.Count +
                                                                         Environment.NewLine + "3rd:\t" + getPriorityString(p3) + "\tFiltered out\t" + beforeFilter3 + "/" + viableClusters.Count;

                    bestClusterMsg = txt_log.Lines.ToList();

                }
                else
                {
                    txt_log.Text = Environment.NewLine + Environment.NewLine + "No cluster configurations satisfy needs within constraints. Adjust either and try again.";
                }
                readyToGenerateClusters = true;

                if (ended)
                {
                    txt_log.Clear();
                    txt_log.AppendText(Environment.NewLine + Environment.NewLine + "No viable clusters were found within 3 size configurations in a row, so the generation process was halted. Adjust needs/constraints.");

                }
        }
        private double calculateInitialClusterCost(cluster clust)
        {
            double constructionCost = clust.getClusterCost() * (1 + (cost_construct / 100));

            return clust.getClusterCost() + constructionCost;
        }