Esempio n. 1
0
        public int[,] UCPSearch(
            MGInput m,
            float[] p_target,
            Action <float> progressCallback)
        {
            // Exhaustive Search is very expensive so we use a coarser step.
            // But we'll need to translate from the coarse step to the
            // orginal step so we'll store the translation coefficient
            // in stepSize.
            int stepCount = options.stepCount;
            int stepSize  = m.tCount / stepCount;
            int taskCount = options.taskCount;

            // Get the total number of possible combinations.
            long nCombinations = (long)1 << (m.genCount * stepCount);

            // Out fitness variable.
            float lowestCost = Mathf.Infinity;

            // Pre-calculate fuel costs at max power because we'll use them
            // later to calculate a presumptive total cost.
            float[] cost_thr_at_max = ThermalGenerator.GetCostAtMaxPower(
                m.genCount, m.p_thr_max, m.thr_c_a, m.thr_c_b, m.thr_c_c, 60.0f);

            // We only need to verify min uptime/downtime constraints if our
            // step size is smaller than the the biggest min u/dtime. Otherwise
            // our step is large enough that the algorithm will never be in a
            // situation where it's trying to switch a generator that can't be
            // switched due to min downtime/uptime constraints.
            bool[] isValidationNeeded = IsMinTimeVerificationNeeded(
                m.genCount, stepSize, m.thr_min_dtime, m.thr_min_utime);

            // t1 and t2 define the interval of time this step occupies.
            var stepInterval = new Tuple <int, int> [stepCount];

            for (int iStep = 0; iStep < stepCount; iStep++)
            {
                stepInterval[iStep] = Tuple.Create(
                    iStep * stepSize,
                    (iStep + 1) * stepSize - 1);
            }

            // It's expensive to compute the cost of the amount of power the
            // microgrid needs to purchase inside the main loop. There are only
            // 2^n * stepCount combinations possible which end up being
            // redundantly recalculated a lot if done in the main loop.
            // So we compute all of them ahead of time and store them in a
            // dictionary.
            Dictionary <StateStep, float> purchaseCostDict
                = ConstructCostDictionary(m, stepCount, stepSize, 400, p_target);

            // Running the search in threads makes pruning high cost
            // combinations happen earlier and more often because a low cost
            // variant is discovered earlier on.
            long bestComb        = -1;
            var  tasks           = new Task[taskCount];
            long combSegmentSize = nCombinations / taskCount;

            var taskParams = new TaskParams(
                p_target,
                stepCount,
                stepSize,
                stepInterval,
                isValidationNeeded,
                cost_thr_at_max,
                purchaseCostDict);

            var taskProgress = new float[taskCount];

            void progressCallbackInner(int id, float completion)
            {
                taskProgress[id] = completion;
                float totalProgress = 0;

                for (int i = 0; i < taskProgress.Length; i++)
                {
                    totalProgress += taskProgress[i];
                }
                progressCallback(totalProgress / taskCount);
            }

            for (int iTask = 0; iTask < taskCount; iTask++)
            {
                taskProgress[iTask] = 0.0f;
                long searchStart = iTask * combSegmentSize;
                long searchEnd   = (iTask + 1) * combSegmentSize;
                int  taskID      = iTask;
                var  task        = Task.Run(() => SearchTask(
                                                m,
                                                searchStart,
                                                searchEnd,
                                                ref bestComb,
                                                ref lowestCost,
                                                taskParams,
                                                progressCallbackInner,
                                                taskID));
                tasks[iTask] = task;
            }

            var waiter = Task.WhenAll(tasks.ToArray());

            waiter.Wait();

            // Write out the step based state array
            int[,] u_thr_best_step = new int[m.genCount, m.tCount];
            for (int iStep = 0; iStep < stepCount; iStep++)
            {
                for (int iGen = m.genCount - 1; iGen >= 0; iGen--)
                {
                    u_thr_best_step[iGen, iStep] = (int)(bestComb % 2);
                    bestComb /= 2;
                }
            }

            // Translate step-based state array to original time based
            // state array.
            int[,] u_thr_best = new int[m.genCount, m.tCount];
            for (int t = 0; t < m.tCount; t++)
            {
                int currStep = t / stepSize;
                for (int iGen = 0; iGen < m.genCount; iGen++)
                {
                    u_thr_best[iGen, t] = u_thr_best_step[iGen, currStep];
                }
            }

            return(u_thr_best);
        }