Beispiel #1
0
        public static float[,] SingleCriterionED(
            MGInput m,
            float[] p_target,
            int[,] u_thr)
        {
            var p_thr       = new float[m.tCount, m.genCount];
            var indexToCost = new Dictionary <int, float>(m.genCount);

            for (int i = 0; i < m.genCount; i++)
            {
                // EUR for 1 hour of functioning
                float cost = MGHelper.ThermalGenerator.GetCost(
                    m.p_thr_max[i],
                    m.thr_c_a[i],
                    m.thr_c_b[i],
                    m.thr_c_c[i]);

                // EUR/MWh
                float alpha = cost / m.p_thr_max[i];
                indexToCost.Add(i, alpha);
            }

            var orderedByCost = indexToCost.OrderBy(x => x.Value).ToDictionary(x => x.Key, y => y.Value);

            return(SingleCriterionED(m, p_target, u_thr, p_thr, orderedByCost, 0, m.tCount));
        }
Beispiel #2
0
        private async Task <int[, ]> UCPSearch(MGInput input, float[] p_target)
        {
#if !UNITY_WEBGL || (UNITY_WEBGL && UNITY_SSM_WEBGL_THREADING_CAPABLE)
            var r = await PSOSearch.UCPSearch(input, optionsPSO, p_target, OnProgress);
#else
            var r = PSOSearch.UCPSearch(input, optionsPSO, p_target, OnProgress).Result;
#endif
            executionID++;
            return(r);
        }
Beispiel #3
0
        public async Task <MGOutput> Calculate(MGInput input)
        {
#if !UNITY_WEBGL || (UNITY_WEBGL && UNITY_SSM_WEBGL_THREADING_CAPABLE)
            var r = await Calculate(input,
                                    ucEnumToMethod[ucAlgorithm],
                                    edEnumToMethod[edAlgorithm]);
#else
            var r = Calculate(input,
                              ucEnumToMethod[ucAlgorithm],
                              edEnumToMethod[edAlgorithm]).Result;
#endif
            return(r);
        }
Beispiel #4
0
        public static float[,] SingleCriterionED(
            MGInput m,
            float[] p_target,
            int[,] u_thr,
            float[,] p_thr,
            Dictionary <int, float> orderedByCost,
            int t1,
            int t2)
        {
            for (int t = t1; t < t2; t++)
            {
                float p_thr_remaining = p_target[t];

                foreach (KeyValuePair <int, float> kvp in orderedByCost)
                {
                    int   i     = kvp.Key;
                    float alpha = kvp.Value;

                    if (u_thr[t, i] == 1)
                    {
                        if (m.canSell)
                        {
                            if (alpha < m.price[t])
                            {
                                p_thr[t, i]      = m.p_thr_max[i];
                                p_thr_remaining -= p_thr[t, i];
                                continue;
                            }
                        }

                        if (m.canBuy)
                        {
                            if (alpha > m.price[t])
                            {
                                p_thr[t, i] = 0.0f;
                                continue;
                            }
                        }

                        p_thr[t, i]      = Mathf.Clamp(m.p_thr_max[i], 0.0f, p_thr_remaining);
                        p_thr_remaining -= p_thr[t, i];
                    }
                    else
                    {
                        p_thr[t, i] = 0.0f;
                    }
                }
            }

            return(p_thr);
        }
Beispiel #5
0
        private async Task <MGOutput> Calculate(MGInput m, UCMethod uc, EDMethod ed)
        {
            var p_res = new float[m.tCount];

            var p_res_excess = new float[m.tCount];
            var p_excess     = new float[m.tCount];

            for (int t = 0; t < m.tCount; t++)
            {
                p_res[t] = m.p_w[t] + m.p_pv[t];
            }

            float[] c_bat    = new float[m.tCount];
            float[] p_target = new float[m.tCount];
            float[] p_bat    = new float[m.tCount];
            float[] e_bat    = new float[m.tCount];
            float[] soc      = new float[m.tCount];

            soc[0]   = m.soc_ini;
            e_bat[0] = m.e_bat_max * soc[0];

            for (int t = 0; t < m.tCount; t++)
            {
                // Renewables aren't enough to meet demand.
                if (m.p_load[t] > p_res[t])
                {
                    p_res_excess[t] = 0.0f;

                    // Battery is usable.
                    if (soc[t] > m.soc_min)
                    {
                        c_bat[t]    = -1.0f;
                        p_target[t] = Mathf.Max(0.0f, m.p_load[t] - p_res[t] - m.p_bat_max);
                    }
                    // Battery is not usable, demand isn't met.
                    else
                    {
                        c_bat[t]    = 0.0f;
                        p_target[t] = Mathf.Max(0.0f, m.p_load[t] - p_res[t]);
                    }
                }
                // Renewables are enough to meet demand.
                else
                {
                    p_target[t]     = 0.0f;
                    p_res_excess[t] = p_res[t] - m.p_load[t];

                    // Battery is chargeable.
                    if (soc[t] < m.soc_max)
                    {
                        c_bat[t] = 1.0f;
                    }
                    else
                    {
                        c_bat[t] = 0.0f;
                    }
                }

                if (c_bat[t] == 1.0f)
                {
                    // Charge the battery wiwth whichever is smallest between
                    // the battery's maximum power and the available surplus.
                    p_bat[t] = Mathf.Max(-m.p_bat_max, m.p_load[t] - p_res[t]);
                }
                else if (c_bat[t] == -1.0f)
                {
                    // Draw whichever is smallest between the battery's
                    // maximum power and the unmet demand.
                    p_bat[t] = Mathf.Min(m.p_bat_max, m.p_load[t] - p_res[t]);
                }
                else
                {
                    p_bat[t] = 0.0f;
                }

                if (t < m.tCount - 1)
                {
                    e_bat[t + 1] = e_bat[t] - (p_bat[t] / 60.0f);
                    soc[t + 1]   = e_bat[t + 1] / m.e_bat_max;
                }
            }

            // Unit Commitment
            var stopWatch = new Stopwatch();

            QueueForMainThread(UCStatusChanged, this,
                               new RunStatusEventArgs(RunStatus.Started));
            stopWatch.Start();

#if !UNITY_WEBGL || (UNITY_WEBGL && UNITY_SSM_WEBGL_THREADING_CAPABLE)
            int[,] u_thr = await uc(m, p_target);
#else
            int[,] u_thr = uc(m, p_target).Result;
#endif

            stopWatch.Stop();
            QueueForMainThread(UCStatusChanged, this,
                               new RunStatusEventArgs(RunStatus.FinishedRunning));

            UCStopwatchStopped?.Invoke(this, new StopwatchStoppedEventArgs(stopWatch.ElapsedMilliseconds));

            // Economic Dispatch
            float[,] p_thr = ed(m, p_target, u_thr);

            // Derive misc. variables
            float[] p_sum     = new float[m.tCount];
            float[] e_sys     = new float[m.tCount];
            float[] e_thr_sum = new float[m.tCount];
            float[] p_thr_sum = new float[m.tCount];
            float[] p_sys     = new float[m.tCount];
            float[] c_sys     = new float[m.tCount];
            float[,] c_thr = new float[m.tCount, m.genCount];
            float[] c_thr_sum     = new float[m.tCount];
            float[] p_thr_max_sum = new float[m.tCount];
            float   c_thr_total   = 0.0f;
            float   c_sys_total   = 0.0f;
            float   e_thr_total   = 0.0f;
            float   e_sys_total   = 0.0f;

            for (int t = 0; t < m.tCount; t++)
            {
                for (int i = 0; i < m.genCount; i++)
                {
                    p_thr_max_sum[t] += m.p_thr_max[i] * u_thr[t, i];
                    p_thr_sum[t]     += p_thr[t, i];
                    e_thr_sum[t]     += p_thr[t, i] / 60.0f;
                    //EUR for 1 hour of functioning
                    c_thr[t, i] = u_thr[t, i] * MGHelper.ThermalGenerator.GetCost(
                        p_thr[t, i],
                        m.thr_c_a[i],
                        m.thr_c_b[i],
                        m.thr_c_c[i]) / 60.0f;
                    c_thr_sum[t] += c_thr[t, i];
                }

                p_sum[t] = p_res[t] + p_bat[t] + p_thr_sum[t];

                if (m.p_load[t] - p_sum[t] < 0)
                {
                    if (m.canSell)
                    {
                        p_sys[t] = m.p_load[t] - p_sum[t];
                    }
                    else
                    {
                        p_sys[t]    = 0.0f;
                        p_excess[t] = p_sum[t] - m.p_load[t];
                    }
                }
                else
                {
                    if (m.canBuy)
                    {
                        p_sys[t] = m.p_load[t] - p_sum[t];
                    }
                    else
                    {
                        p_sys[t]    = 0.0f;
                        p_excess[t] = p_sum[t] - m.p_load[t];
                    }
                }

                e_sys[t]     = p_sys[t] / 60.0f;
                c_sys[t]     = e_sys[t] * m.price[t];
                e_sys_total += e_sys[t];
                c_thr_total += c_thr_sum[t];
                c_sys_total += c_sys[t];
                e_thr_total += e_thr_sum[t];
            }

            return(new MGOutput
            {
                u_thr = u_thr,
                p_sum = p_sum,
                p_res = p_res,
                p_thr = p_thr,
                e_thr_sum = e_thr_sum,
                p_thr_sum = p_thr_sum,
                p_thr_max_sum = p_thr_max_sum,
                p_bat = p_bat,
                p_sys = p_sys,
                p_target = p_target,
                soc = soc,
                c_bat = c_bat,
                e_sys_total = e_sys_total,
                e_thr_total = e_thr_total,
                c_sys = c_sys,
                c_thr = c_thr,
                c_thr_sum = c_thr_sum,
                c_sys_total = c_sys_total,
                c_thr_total = c_thr_total
            });
        }
Beispiel #6
0
        /// <summary>
        /// Precomputes the cost of each possible set of generator states at
        /// every time step.
        /// </summary>
        /// <param name="m">Microgrid input data.</param>
        /// <param name="genCount">Number of generators.</param>
        /// <param name="stepCount">The number of time steps.</param>
        /// <param name="stepSize">The size of each time step.</param>
        /// <param name="p_target">The amount of power the system needs to supply at a given time step.</param>
        /// <returns>A dictionary mapping a generator state and time step pair
        /// to the cost of purchasing the amount of power necessary to fulfill
        /// remaining demand for that specific pair.</returns>
        public static Dictionary <StateStep, float> ConstructCostDictionary(
            MGInput m,
            int stepCount,
            int stepSize,
            float penalty,
            float[] p_target)
        {
            // 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.

            // 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] = new Tuple <int, int>(
                    iStep * stepSize,
                    (iStep + 1) * stepSize - 1);
            }

            int nSqr             = 1 << m.genCount; //Bitwise squaring.
            int nPurchaseCombs   = nSqr * stepCount;
            var purchaseCostDict = new Dictionary <StateStep, float>(nPurchaseCombs);
            var indexToCost      = new Dictionary <int, float>(m.genCount);

            float[] p_thr = new float[m.genCount];

            for (int i = 0; i < m.genCount; i++)
            {
                // EUR for 1 hour of functioning
                float cost = ThermalGenerator.GetCost(
                    m.p_thr_max[i],
                    m.thr_c_a[i],
                    m.thr_c_b[i],
                    m.thr_c_c[i]);

                // EUR/MWh
                float alpha = cost / m.p_thr_max[i];
                indexToCost.Add(i, alpha);
            }

            float[] e_thr_remaining = new float[stepSize];
            float[] p_remaining     = new float[stepSize];
            var     orderedByCost   = indexToCost.OrderBy(x => x.Value).ToDictionary(x => x.Key, y => y.Value);

            for (int iState = 0; iState < nSqr; iState++)
            {
                for (int iStep = 0; iStep < stepCount; iStep++)
                {
                    float c_total = 0.0f;
                    int   t1      = stepInterval[iStep].Item1;
                    int   t2      = stepInterval[iStep].Item2;

                    for (int t = t1; t < t2; t++)
                    {
                        e_thr_remaining[t - t1] = p_target[t] / 60.0f;
                        p_remaining[t - t1]     = p_target[t];

                        foreach (KeyValuePair <int, float> kvp in orderedByCost)
                        {
                            int   iGen     = kvp.Key;
                            float alpha    = kvp.Value;
                            var   bitValue = iState & (1 << m.genCount - iGen - 1);
                            var   state    = ((bitValue | (~bitValue + 1)) >> 31) & 1;

                            if (state == 1)
                            {
                                if (alpha < m.price[t])
                                {
                                    if (m.canSell)
                                    {
                                        // Since we can sell and our generator
                                        // makes cheaper energy than the market price,
                                        // just produce at max power.
                                        p_thr[iGen] = m.p_thr_max[iGen];
                                    }
                                    else
                                    {
                                        // Since we can't sell but our generator
                                        // makes cheaper energy than market price,
                                        // we'll produce enough to cover local demand.
                                        p_thr[iGen] = Mathf.Clamp(m.p_thr_max[iGen], 0.0f, p_remaining[t - t1]);
                                    }
                                }
                                else
                                {
                                    if (m.canBuy)
                                    {
                                        // Since we can buy and our generator
                                        // makes more expensive energy than
                                        // the market price, produce no power
                                        // and buy.
                                        p_thr[iGen] = 0.0f;
                                    }
                                    else
                                    {
                                        // Since we can't buy, produce enough
                                        // power to cover local demand, regardless
                                        // of market price.
                                        p_thr[iGen] = Mathf.Clamp(m.p_thr_max[iGen], 0.0f, p_remaining[t - t1]);
                                    }
                                }

                                c_total += ThermalGenerator.GetCost(
                                    p_thr[iGen],
                                    m.thr_c_a[iGen],
                                    m.thr_c_b[iGen],
                                    m.thr_c_c[iGen]) / 60.0f;
                                p_remaining[t - t1]     -= p_thr[iGen];
                                e_thr_remaining[t - t1] -= p_thr[iGen] / 60.0f;
                            }
                            else
                            {
                                p_thr[iGen] = 0.0f;
                            }
                        }

                        if (e_thr_remaining[t - t1] < 0.0f)
                        {
                            if (m.canSell)
                            {
                                c_total += e_thr_remaining[t - t1] * m.price[t];
                            }
                        }
                        else
                        {
                            if (m.canBuy)
                            {
                                c_total += e_thr_remaining[t - t1] * m.price[t];
                            }
                            else
                            {
                                c_total += e_thr_remaining[t - t1] * penalty;
                            }
                        }
                    }

                    var id = new StateStep(iState, iStep);

#if UNITY_EDITOR || DEVELOPMENT_BUILD
                    if (purchaseCostDict.ContainsKey(id) &&
                        purchaseCostDict[id] != c_total)
                    {
                        throw new InvalidProgramException(
                                  $@"IDs and purchase costs need to have a 1 to 1
                            mapping. There can't be an ID with a different
                            purchase cost. If that happens, the code is wrong
                            somewhere.
                            UID: {id}.
                            Existing Value: {purchaseCostDict[id]}.
                            New Value: {c_total}.");
                    }
#endif

                    purchaseCostDict[id] = c_total;
                }
            }

            return(purchaseCostDict);
        }