Exemplo n.º 1
0
        private void TestBucketSortArrayMatrixRow()
        {
            try {
                ILArray <string> A = new ILArray <string>(3, 4);
                A[0, 0] = "abc";
                A[0, 1] = "rtu";
                A[0, 2] = "sfkw";
                A[0, 3] = "lsdkfi";
                A[1, 0] = "iowejkc";
                A[1, 1] = "cjks";
                A[1, 2] = "wokys";
                A[1, 3] = "suem,";
                A[2, 0] = "fgj";
                A[2, 1] = "JKSF";
                A[2, 2] = "SEs";
                A[2, 3] = "SEFsr";
                ILArray <double> ind;
                ILArray <string> res = ILMath.sort(A, out ind, 0, false);
                if (!res.Equals(A[ind]))
                {
                    throw new Exception("invalid indices/values detected");
                }
                ILArray <Int16> indI = ILMath.toint16(ILMath.counter(0.0, 1.0, A.Dimensions.ToIntArray()));
                res = ILMath.sort(A, ref indI, 0, true, new ILASCIIKeyMapper());
                if (!res.Equals(A[indI]))
                {
                    throw new Exception("invalid indices/values detected");
                }

                Success(" elapsed: " + m_stopwatch.ElapsedMilliseconds + " ms");
            } catch (Exception e) {
                Error(0, e.Message);
            }
        }
Exemplo n.º 2
0
        private void TestQuickSortDesc()
        {
            try {
                ILArray <double> A = ILMath.counter(5, 4, 3);
                System.Diagnostics.Debug.Assert(!A.IsReference);
                ILArray <double> result = ILMath.sort(A, 1, true);
                ILArray <double> expect = A[":;3,2,1,0;:"];
                if (!result.Equals(expect))
                {
                    throw new Exception("invalid values");
                }
                // test scalar
                A      = 3.0;
                result = ILMath.sort(A, 0, true);
                if (result != 3.0)
                {
                    throw new Exception("invalid values: scalar");
                }
                // test empty
                A = ILArray <double> .empty();

                if (!ILMath.sort(A, 0, true).IsEmpty)
                {
                    throw new Exception("invalid values: empty");
                }
                Success();
            } catch (Exception e) {
                Error(0, e.Message);
            }
        }
Exemplo n.º 3
0
 /// <summary>
 /// create composite shape
 /// </summary>
 /// <param name="panel">scene hosting the scene</param>
 /// <param name="numVertices">number of overall vertices for the shape</param>
 /// <param name="verticesPerShape">Number of vertices per shape</param>
 public ILCompositeShape(ILPanel panel, int numVertices, int verticesPerShape)
     : base(panel, numVertices, verticesPerShape)
 {
     Opacity        = 255;
     m_shapeIndices = ILMath.toint32(
         ILMath.counter(0.0, 1.0, VerticesPerShape, numVertices / VerticesPerShape));
 }
Exemplo n.º 4
0
 /// <summary>
 /// create composite shape
 /// </summary>
 /// <param name="panel">hosting panel</param>
 /// <param name="verticesPerShape">number of vertices per shape</param>
 /// <param name="X">x coordinates vector </param>
 /// <param name="Y">y coordinates vector </param>
 /// <param name="Z">z coordinates vector </param>
 /// <remarks>The constructor creates a new composite shape out of all vertices specified in X,Y and Z.
 /// Every vertex is only used once. Every shape uses
 /// <see cref="ILNumerics.Drawing.Shapes.ILShape&lt;T>.VerticesPerShape"/> vertices one after another.</remarks>
 public ILCompositeShape(ILPanel panel, int verticesPerShape, ILBaseArray X, ILBaseArray Y, ILBaseArray Z)
     : base(panel, X.Length, verticesPerShape)
 {
     Update(X, Y, Z);
     m_shapeIndices = ILMath.toint32(
         ILMath.counter(0.0, 1.0, VerticesPerShape, m_vertCount / VerticesPerShape));
     Opacity   = 255;
     m_shading = ShadingStyles.Flat;
 }
Exemplo n.º 5
0
        public Bars AddBars(ILArray <double> barLength)
        {
            if (!barLength.IsVector && !barLength.IsScalar)
            {
                throw new ILArgumentException("Argument must be a vector or scalar");
            }
            int n = barLength.Dimensions[0];

            return(AddBars(ILMath.zeros(n), barLength, ILMath.counter(n) - 1.0, 0.8, BarType.Vertical));
        }
Exemplo n.º 6
0
 protected static ILArray <double> _c(double start, double incrementation, double limit)
 {
     return(ILMath.counter(start, incrementation, 1, (limit - start) / incrementation + 1));
 }
Exemplo n.º 7
0
 protected static ILArray <double> _c(decimal start, decimal incrementation, decimal limit)
 {
     return(ILMath.counter((double)start, (double)incrementation, 1, (int)_csize(start, incrementation, limit)));
 }
Exemplo n.º 8
0
 protected static ILArray <int> _c_(int start, int incrementation, int limit)
 {
     return(ILMath.counter <int>(start, incrementation, 1, (limit - start) / incrementation + 1));
 }
Exemplo n.º 9
0
 /// <summary>
 /// construct new filled graph
 /// </summary>
 /// <param name="panel">panel hosting the graph</param>
 /// <param name="X">X coords, if null, range 0..[cols of Z] will be created</param>
 /// <param name="Y">Y coords, if null, range 0..[rows of Z] will be created</param>
 /// <param name="Z">Z coords (heights)</param>
 /// <param name="C">Colors for Z</param>
 /// <param name="clippingContainer">gloabal limits of panel</param>
 public ILFilledGraph(ILPanel panel, ILBaseArray X, ILBaseArray Y,
                      ILBaseArray Z, ILBaseArray C, ILClippingData clippingContainer)
     : base(panel, clippingContainer)
 {
     #region argument checking
     m_localClipping.EventingSuspend();
     if (Z == null || !Z.IsMatrix)
     {
         throw new ILArgumentException("ILFilledGraph: Z must be matrix!");
     }
     if (!Z.IsNumeric)
     {
         throw new ILArgumentException("ILFilledGraph: Z must be numeric!");
     }
     m_sourceArray = ILMath.tosingle(Z);
     m_rows        = m_sourceArray.Dimensions[0];
     m_cols        = m_sourceArray.Dimensions[1];
     ILArray <float> tmp;
     if (!object.Equals(X, null) && !X.IsEmpty)
     {
         if (!X.IsMatrix || !X.IsNumeric)
         {
             throw new ILArgumentException("ILFilledGraph: X must be numeric matrix!");
         }
         if (X.Dimensions.IsSameSize(Z.Dimensions))
         {
             tmp = ILMath.tosingle(X);
             tmp.ExportValues(ref m_xCoords);
             m_localClipping.XMax = tmp.MaxValue;
             m_localClipping.XMin = tmp.MinValue;
         }
         else
         {
             throw new ILArgumentException("ILFilledGraph: X must be of same size than Z!");
         }
     }
     else
     {
         ILMath.tosingle(ILMath.repmat(ILMath.counter(0.0, 1.0, 1, m_cols), m_rows, 1)).ExportValues(ref m_xCoords);
         m_localClipping.XMin = 0;
         m_localClipping.XMax = m_cols - 1;
     }
     if (!object.Equals(Y, null) && !Y.IsEmpty)
     {
         if (!Y.IsMatrix || !Y.IsNumeric)
         {
             throw new ILArgumentException("ILFilledGraph: Y must be numeric matrix!");
         }
         if (Y.Dimensions.IsSameSize(Z.Dimensions))
         {
             tmp = ILMath.tosingle(Y);
             tmp.ExportValues(ref m_yCoords);
             m_localClipping.YMax = tmp.MaxValue;
             m_localClipping.YMin = tmp.MinValue;
         }
         else
         {
             throw new ILArgumentException("ILFilledGraph: Y must be same size than Z!");
         }
     }
     else
     {
         ILMath.tosingle(ILMath.repmat(ILMath.counter(0.0, 1.0, m_rows, 1), 1, m_cols)).ExportValues(ref m_yCoords);
         m_localClipping.YMax = m_rows - 1;
         m_localClipping.YMin = 0;
     }
     if (object.Equals(C, null) || C.IsEmpty)
     {
         m_colors = null;
     }
     else
     {
         m_colors = ILMath.tosingle(C);
     }
     m_localClipping.ZMax = m_sourceArray.MaxValue;
     m_localClipping.ZMin = m_sourceArray.MinValue;
     #endregion
     m_Vertcount   = m_rows * m_cols;
     m_vertexReady = false;
     m_indexReady  = false;
     // default view properties
     m_opacity            = 1.0f;
     m_wireLines          = new ILLineProperties();
     m_wireLines.Changed += new EventHandler(m_wireLines_Changed);
     m_filled             = true;
     m_localClipping.EventingResume();
 }
Exemplo n.º 10
0
        private void TestQuickSortAsc()
        {
            try {
                ILArray <double> A = ILMath.counter(5, 4, 3);
                System.Diagnostics.Debug.Assert(!A.IsReference);
                ILArray <double> result = ILMath.sort(A, 1, false);
                ILArray <double> expect = A[":;:;:"];
                if (!result.Equals(expect))
                {
                    throw new Exception("invalid values");
                }
                // test real sortable values
                A      = ILMath.counter(60.0, -1.0, 5, 4, 3);
                result = ILMath.sort(A, 1, false);
                expect = A[":;3,2,1,0;:"];
                if (!result.Equals(expect))
                {
                    throw new Exception("invalid values");
                }
                // test ascending values to sort ascending
                A      = ILMath.counter(1.0, 1.0, 11, 2);
                result = ILMath.sort(A, 0, false);
                if (!result.Equals(A))
                {
                    throw new Exception("invalid values");
                }
                // test descending values to sort ascending
                A      = ILMath.counter(22.0, -1, 11, 2);
                result = ILMath.sort(A, 0, false);
                expect = ILMath.counter(1.0, 1.0, 11, 2)[":;1,0"];
                if (!result.Equals(expect))
                {
                    throw new Exception("invalid values");
                }
                // test scalar
                A      = 3.0;
                result = ILMath.sort(A, 0, false);
                if (result != 3.0)
                {
                    throw new Exception("invalid values: scalar");
                }
                // test empty
                A = ILArray <double> .empty();

                if (!ILMath.sort(A, 0, false).IsEmpty)
                {
                    throw new Exception("invalid values: empty");
                }
                // test nan
                A             = ILMath.counter(1.0, 1.0, 20, 2);
                A[2]          = double.NaN;
                A[4]          = double.PositiveInfinity;
                A[8]          = double.NegativeInfinity;
                A[18]         = double.NegativeInfinity;
                A[14]         = double.NaN;
                result        = ILMath.sort(A, 0, false);
                expect        = ILMath.counter(1.0, 1.0, 20, 2);
                expect[":;0"] = new double[] {
                    double.NegativeInfinity,
                    double.NegativeInfinity,
                    1, 2, 4, 6, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 20,
                    double.PositiveInfinity,
                    double.NaN,
                    double.NaN
                };
                if (!result.Equals(expect))
                {
                    throw new Exception("invalid values");
                }
                Success();
            } catch (Exception e) {
                Error(0, e.Message);
            }
        }
Exemplo n.º 11
0
        private void TestQuickSortDescIDX(int dim, int len)
        {
            try {
                // asc along dimension (already ordered values)
                int[] dims = new int[4] {
                    5, 4, 3, 2
                };
                dims[dim] = len;
                ILArray <double> A = ILMath.counter(dims);
                ILArray <double> ind;
                ILArray <double> result = ILMath.sort(A, out ind, dim, true);
                ILArray <double> expect = null;
                ILArray <double> expectInd;
                expectInd = ILMath.counter(A.Dimensions[dim] - 1, -1.0, 1, A.Dimensions[dim]);
                ILBaseArray[] revDims = new ILBaseArray[dims.Length];
                revDims[dim] = expectInd;
                expect       = A[revDims];
                if (!result.Equals(expect))
                {
                    throw new Exception("invalid values");
                }

                int [] dimsEx = new int[dims.Length];
                expectInd = ILMath.repmat(expectInd, A.Dimensions.SequentialIndexDistance(dim), 1);
                sortIDXTestHelper001(dim, dims, ref expectInd, dimsEx);
                expectInd = ILMath.repmat(expectInd, dimsEx);
                if (!ind.Equals(expectInd))
                {
                    throw new Exception("invalid indices");
                }
                // reverse values ...
                A      = ILMath.counter(A.Dimensions.NumberOfElements, -1.0, dims);
                result = ILMath.sort(A, out ind, dim, true);
                if (!result.Equals(A.C))
                {
                    throw new Exception("invalid values");
                }

                expectInd = ILMath.counter(0.0, 1.0, 1, A.Dimensions[dim]);
                expectInd = ILMath.repmat(expectInd, A.Dimensions.SequentialIndexDistance(dim), 1);
                sortIDXTestHelper001(dim, dims, ref expectInd, dimsEx);
                expectInd = ILMath.repmat(expectInd, dimsEx);
                if (!ind.Equals(expectInd))
                {
                    throw new Exception("invalid indices");
                }
                // test scalar
                A      = 3.0;
                result = ILMath.sort(A, out ind, 0, true);
                if (result != 3.0)
                {
                    throw new Exception("invalid values: scalar");
                }
                if (ind != 0.0)
                {
                    throw new Exception("invalid indices");
                }
                // test empty
                A = ILArray <double> .empty();

                if (!ILMath.sort(A, out ind, 0, true).IsEmpty)
                {
                    throw new Exception("invalid values: empty");
                }
                if (!ind.IsEmpty)
                {
                    throw new Exception("invalid indices");
                }
                Success();
            } catch (Exception e) {
                Error(0, e.Message);
            }
        }
Exemplo n.º 12
0
        //% The main file for running the wind farm controll and wake simulation.
        // It is not completely done yet. Further updates will come
        // Currently there are only 4 turbines, for test purposes. But is should be
        // easily updated to a larger number of turbines.
        // Similarly there is a lot of room for speed optimizations, even though it
        // now runs slowly with only 4 turbines
        // 19/07-13 MS

        public static double[][] Simulation(WakeFarmControlConfig config)
        {
            var parm = new WindTurbineParameters();

            ILMatFile env;
            ILMatFile wt;

            ILArray <int>    idx;
            ILArray <double> ee;

            double           Ki;
            double           Kp;
            int              PC_MaxPit;
            int              PC_MinPit;
            double           VS_CtInSp;
            double           VS_RtGnSp;
            double           VS_Rgn2K;
            double           omega0;
            double           beta0;
            double           power0;
            ILArray <double> x;
            ILArray <double> u0;
            ILArray <double> u;
            ILArray <double> Mg_old;
            ILArray <double> P_ref;
            ILArray <double> Pa;
            ILArray <double> Power;
            ILArray <double> Ct;
            ILArray <double> P_ref_new;
            ILArray <double> v_nac;
            double           alpha;
            double           Mg_max_rate;
            ILArray <double> e;
            ILArray <double> Mg;
            ILArray <double> beta;
            ILArray <double> Cp;
            ILArray <double> Omega;
            ILArray <double> out_;

            if (config.NTurbines == 0)
            {
                return(null);
            }

            // Wind farm properties
            //turbine properties
            env             = wt = new ILMatFile(config.NREL5MW_MatFile);                                             //Load parameters from the NREL 5MW turbine
            parm.N          = config.NTurbines;                                                                       // number of turbines in farm
            parm.rho        = (double)env.GetArray <double>("env_rho");                                               //air density
            parm.radius     = ((double)(wt.GetArray <double>("wt_rotor_radius"))) * ILMath.ones(1, config.NTurbines); // rotor radius (NREL5MW)
            parm.rated      = 5e6 * ILMath.ones(1, config.NTurbines);                                                 //rated power (NREL5MW)
            parm.ratedSpeed = (double)wt.GetArray <double>("wt_rotor_ratedspeed");                                    //rated rotor speed

            idx = ILMath.empty <int>();
            ILMath.max(wt.GetArray <double>("wt_cp_table")[ILMath.full], idx);                                        //Find index for max Cp;
            parm.Cp = ILMath.ones(1, config.NTurbines) * wt.GetArray <double>("wt_cp_table").GetValue(idx.ToArray()); //Set power coefficent to maximum value in the cp table
            parm.Ct = ILMath.ones(1, config.NTurbines) * wt.GetArray <double>("wt_ct_table").GetValue(idx.ToArray()); //Set power coefficent to maximum value in the ct table

            // NOTE: controller parameters should be imported from the wt....struct in
            //Pitch control

            ee = 0;                                 //blade pitch integrator
            Ki = 0.008068634 * 360 / 2 / ILMath.pi; // integral gain (NREL5MW)
            Kp = 0.01882681 * 360 / 2 / ILMath.pi;  // proportional gain (NREL5MW)

            PC_MaxPit = 90;
            PC_MinPit = 0;

            //region control NREL
            VS_CtInSp = 70.16224;
            VS_RtGnSp = 121.6805;
            VS_Rgn2K  = 2.332287;


            // load initial wind data
            var wind = new ILMatFile(config.Wind_MatFile);

            //% Set initial conditions
            omega0 = 1.267; //Rotation speed
            beta0  = 0;     //Pitch

            var timeLine = (int)config.TimeLine();

            power0 = parm.rated.GetValue(0); //Power production
            x      = (omega0 * ILMath.ones(parm.N, 1)).Concat((wind.GetArray <double>("wind").GetValue(0, 1) * ILMath.ones(parm.N, 1)), 1);
            u0     = (beta0 * ILMath.ones(parm.N, 1)).Concat((power0 * ILMath.ones(parm.N, 1)), 1);
            u      = u0.C;
            Mg_old = u[ILMath.full, 1];
            P_ref  = ILMath.zeros(parm.N, (int)config.TimeLine()); //Initialize matrix to save the power production history for each turbine
            Pa     = P_ref.C;                                      //Initialize available power matrix
            Power  = P_ref.C;
            Ct     = parm.Ct.C;                                    //Initialize Ct - is this correct?
            Ct[timeLine - 1, ILMath.full] = Ct[0, ILMath.full];
            P_ref_new = power0 * ILMath.ones(config.NTurbines, 1);

            v_nac = ILMath.zeros(Ct.Size[1], timeLine);
            Mg    = ILMath.zeros(u.Size[0], timeLine);
            beta  = ILMath.zeros(u.Size[0], timeLine);
            Omega = ILMath.zeros(Ct.Size[1], timeLine);
            Cp    = ILMath.zeros(timeLine, parm.Cp.Size[1]);

            var turbineModel = new TurbineDrivetrainModel();

            //% Simulate wind farm operation
            //var timeLine = (int) config.TimeLine();
            for (var i = 2; i <= timeLine; i++) //At each sample time(DT) from Tstart to Tend
            {
                //Calculate the wake using the current Ct values
                {
                    ILArray <double> out_v_nac;
                    WakeCalculation.Calculate((Ct[i - 1 - 1, ILMath.full]), i, wind, out out_v_nac);
                    v_nac[ILMath.full, i - 1] = out_v_nac;
                }
                x[ILMath.full, 1] = v_nac[ILMath.full, i - 1];


                //Farm control
                //Calculate the power distribution references for each turbine
                if (config.EnablePowerDistribution)
                {
                    ILArray <double> out_Pa;
                    PowerDistributionControl.DistributePower(v_nac[ILMath.full, i - 1], config.Pdemand, Power[ILMath.full, i - 1 - 1], parm, out P_ref_new, out out_Pa);
                    Pa[ILMath.full, i - 1] = out_Pa;
                }

                //Hold  the demand for some seconds
                if (ILMath.mod(i, ILMath.round(config.PRefSampleTime / config.DT)) == 2) //???
                {
                    P_ref[ILMath.full, i - 1] = P_ref_new;
                }
                else
                {
                    if (config.PowerRefInterpolation)
                    {
                        alpha = 0.01;
                        P_ref[ILMath.full, i - 1] = (1 - alpha) * P_ref[ILMath.full, i - 1 - 1] + (alpha) * P_ref_new;
                    }
                    else
                    {
                        P_ref[ILMath.full, i - 1] = P_ref_new;
                    }
                }


                //Calculate control for each individual turbine - should be moved to the
                //turbine (drivetrain) model.

                //Torque controller
                for (var j = 1; j <= parm.N; j++)
                {
                    if ((x.GetValue(j - 1, 0) * 97 >= VS_RtGnSp) || (u.GetValue(j - 1, 0) >= 1))   // We are in region 3 - power is constant
                    {
                        u.SetValue(P_ref.GetValue(j - 1, i - 1) / x.GetValue(j - 1, 0), j - 1, 1);
                    }
                    else if (x.GetValue(j - 1, 0) * 97 <= VS_CtInSp)                            //! We are in region 1 - torque is zero
                    {
                        u.SetValue(0.0, j - 1, 1);
                    }
                    else                                                         //! We are in region 2 - optimal torque is proportional to the square of the generator speed
                    {
                        u.SetValue(97 * VS_Rgn2K * x.GetValue(j - 1, 0) * x.GetValue(j - 1, 0) * Math.Pow(97, 2), j - 1, 1);
                    }
                }

                //Rate limit torque change
                //  u(:,2) - Mg_old;
                Mg_max_rate       = 1e6 * config.DT;
                u[ILMath.full, 1] = ILMath.sign(u[ILMath.full, 1] - Mg_old) * ILMath.min(ILMath.abs(u[ILMath.full, 1] - Mg_old), Mg_max_rate) + Mg_old;

                //Pitch controller
                e  = 97 * (omega0 * ILMath.ones(parm.N, 1) - x[ILMath.full, 0]);
                ee = ee - config.DT * e;
                ee = ILMath.min(ILMath.max(ee, PC_MinPit / Ki), PC_MaxPit / Ki);

                u[ILMath.full, 0] = -Kp * config.DT * e + Ki * ee;
                for (var j = 1; j <= parm.N; j++)
                {
                    u.SetValue(Math.Min(Math.Max(u.GetValue(j - 1, 0), PC_MinPit), PC_MaxPit), j - 1, 0);
                }

                if (!config.EnableTurbineDynamics)
                {
                    u = u0;
                }

                Mg[ILMath.full, i - 1] = u[ILMath.full, 1];
                Mg_old = Mg[ILMath.full, i - 1];
                beta[ILMath.full, i - 1] = u[ILMath.full, 0]; //Set pitch


                //Turbine dynamics - can be simplified
                if (config.EnableTurbineDynamics)
                {
                    for (var j = 1; j <= parm.N; j++)
                    {
                        double out_x;
                        double out_Ct;
                        double out_Cp;
                        turbineModel.Model(x[j - 1, ILMath.full], u[j - 1, ILMath.full], wt, env, config.DT, out out_x, out out_Ct, out out_Cp);
                        x.SetValue(out_x, j - 1, 0);
                        Ct.SetValue(out_Ct, i - 1, j - 1);
                        Cp.SetValue(out_Cp, i - 1, j - 1);
                    }
                }
                else
                {
                    Ct[i - 1, ILMath.full] = parm.Ct;
                    Cp[i - 1, ILMath.full] = parm.Cp;
                    x[ILMath.full, 0]      = parm.ratedSpeed;//Rotational speed
                }

                Omega[ILMath.full, i - 1] = x[ILMath.full, 0];
                Power[ILMath.full, i - 1] = Omega[ILMath.full, i - 1] * Mg[ILMath.full, i - 1];
            }

            //% Save output data
            out_ = (config.DT * (ILMath.counter(0, 1, config.TimeLine())));
            out_ = out_.Concat(v_nac.T, 1);
            out_ = out_.Concat(Omega.T, 1);
            out_ = out_.Concat(beta.T, 1);
            out_ = out_.Concat(P_ref.T, 1);
            out_ = out_.Concat(Ct, 1);
            out_ = out_.Concat(Cp, 1);
            out_ = out_.Concat(Pa.T, 1);
            out_ = out_.Concat(Mg.T, 1);
            out_ = out_.Concat(Power.T, 1);

            //Ttotal power demand
            var l = config.NTurbines * 3 + 1;
            var r = l + config.NTurbines - 1;

            out_ = out_.Concat(ILMath.sum(out_[ILMath.full, ILMath.r(l, r)], 1) / 1e6, 1);    // P_ref sum

            l = config.NTurbines * 6 + 1;
            r = l + config.NTurbines - 1;

            out_ = out_.Concat(ILMath.sum(out_[ILMath.full, ILMath.r(l, r)], 1) / 1e6, 1);    // Pa sum. 'Power Demand'
            out_ = out_.Concat(ILMath.sum(Power).T / 1e6, 1);                                 // 'Actual Production'

            //Ttotal power demand
            out_ = out_.Concat(ILMath.sum(P_ref.T, 1), 1);              // 'Demand'
            out_ = out_.Concat(ILMath.sum(Pa.T, 1), 1);                 // 'Available'
            out_ = out_.Concat(ILMath.sum(Mg * Omega).T, 1);            // 'Actual'

            //Total power produced
            out_ = out_.Concat((Mg * Omega).T, 1);

            var out_doubleArray = new double[out_.Size[0]][];

            for (int i = 0; i <= out_doubleArray.GetLength(0) - 1; i++)
            {
                out_doubleArray[i] = new double[out_.Size[1]];
                for (int j = 0; j <= out_doubleArray[i].GetLength(0) - 1; j++)
                {
                    out_doubleArray[i][j] = out_.GetValue(i, j);
                }
            }
            return(out_doubleArray);
        }