/// <summary>
        /// Dado un supernodo, recorre todas sus ramas para hallar la corriente en una de ellas
        /// </summary>
        /// <param name="nodo"></param>
        /// <param name="W"></param>
        /// <returns></returns>
        private static double CalculateSupernodeCurrent(Node nodo, Dipole comp, double t)
        {
            if (nodo.IsReference)
            {
                nodo = comp.OtherNode(nodo);
            }

            double i = 0;

            foreach (var comp2 in nodo.Components)
            {
                if (comp2 == comp)
                {
                    continue;
                }
                if (comp2 is VoltageGenerator)
                {
                    Node nodo1 = comp2.OtherNode(nodo);
                    i += CalculateSupernodeCurrent(nodo1, comp2, t);
                }
                else
                {
                    i += comp2.Current(nodo, t);
                }
            }
            return(i);
        }
 /// <summary>
 /// Valida una rama y la agrega al circuito si corresponde
 /// En caso contrario solo agrega el componente indicado
 /// </summary>
 /// <param name="yaanalizados"></param>
 /// <param name="nodosnormales"></param>
 /// <param name="ramas"></param>
 /// <param name="nodo"></param>
 /// <param name="compo"></param>
 /// <param name="br"></param>
 protected static void ValidateBranch(List <Dipole> yaanalizados, List <Node> nodosnormales,
                                      List <Branch> ramas, Node nodo, Dipole compo, Branch br)
 {
     if (br.Components.Count <= 1)
     {
         if (compo is PasiveComponent)
         {
             Node other = compo.OtherNode(nodo);
             other.TypeOfNode = Node.NodeType.MultibranchCurrentNode;
             if (!nodosnormales.Contains(other) && !other.IsReference)
             {
                 nodosnormales.Add(other);
             }
         }
         yaanalizados.Add(compo);
     }
     else
     {
         //rama valida
         ramas.Add(br);
         Node other = br.OtherNode(nodo);
         if (!nodosnormales.Contains(other) && !other.IsReference)
         {
             nodosnormales.Add(other);
         }
         yaanalizados.AddRange(br.Components);
         foreach (var comp in br.Components)
         {
             comp.Owner = br;
         }
     }
 }
        /// <summary>
        /// barre una rama desde un nodo interno hacia la izquierda o derecha
        /// calculando la suma de las tensiones de generadores V1
        /// y la suma de impedancias Z1
        /// </summary>
        /// <param name="nodo"></param>
        /// <param name="compo1"></param>
        /// <param name="t"></param>
        /// <param name="v1"></param>
        /// <param name="z1"></param>
        private static void NavigateBranch(Node nodo, Dipole compo1, double t, ref double v1, ref double z1)
        {
            Node nodo1 = nodo;

            while (!(nodo1.TypeOfNode == Node.NodeType.MultibranchCurrentNode || nodo1.IsReference))
            {
                if (compo1 is Resistor)
                {
                    z1 += compo1.Impedance().Real;
                }
                else if (compo1 is VoltageGenerator || compo1 is Capacitor)
                {
                    v1 += compo1.voltage(nodo1, t);
                }
                else
                {
                    throw new NotImplementedException();
                }
                nodo1  = compo1.OtherNode(nodo1);
                compo1 = nodo1.OtherComponent(compo1);
            }
            if (nodo1.TypeOfNode == Node.NodeType.MultibranchCurrentNode)
            {
                v1 += nodo1.Voltage.Real;
            }
        }
        /// <summary>
        /// barre una rama desde un nodo interno hacia la izquierda o derecha
        /// calculando la suma de las tensiones de generadores V1
        /// y la suma de impedancias Z1
        /// </summary>
        /// <param name="nodo"></param>
        /// <param name="compo1"></param>
        /// <param name="v1"></param>
        /// <param name="z1"></param>
        private static void NavigateBranch(Node nodo, Dipole compo1, ref Complex32 v1, ref Complex32 z1)
        {
            Node nodo1 = nodo;

            while (!(nodo1.TypeOfNode == Node.NodeType.MultibranchCurrentNode || nodo1.IsReference))
            {
                if (compo1 is PasiveComponent)
                {
                    z1 += compo1.Impedance();
                }
                else if (compo1 is VoltageGenerator)
                {
                    v1 += compo1.voltage(nodo1, null);
                }
                else
                {
                    throw new NotImplementedException();
                }
                nodo1  = compo1.OtherNode(nodo1);
                compo1 = nodo1.OtherComponent(compo1);
            }
            if (nodo1.TypeOfNode == Node.NodeType.MultibranchCurrentNode)
            {
                v1 += nodo1.Voltage;
            }
        }
 protected static void AddComponentNodes(Circuit ciroptimizado, Dipole rama)
 {
     if (!ciroptimizado.Nodes.ContainsValue(rama.Nodes[0]))
     {
         ciroptimizado.Nodes.Add(rama.Nodes[0].Name, rama.Nodes[0]);
     }
     if (!ciroptimizado.Nodes.ContainsValue(rama.Nodes[1]))
     {
         ciroptimizado.Nodes.Add(rama.Nodes[1].Name, rama.Nodes[1]);
     }
 }
        /// <summary>
        /// Dado un supernodo, recorre todas sus ramas para hallar la corriente en una de ellas
        /// </summary>
        /// <param name="nodo"></param>
        /// <param name="W"></param>
        /// <returns></returns>
        private static Complex32 CalculateSupernodeCurrent(Node nodo, Complex32 W, Dipole comp)
        {
            Complex32 i = Complex32.Zero;

            foreach (var comp2 in nodo.Components)
            {
                if (comp2 == comp)
                {
                    continue;
                }
                if (comp2 is VoltageGenerator)
                {
                    Node nodo1 = comp2.OtherNode(nodo);
                    i += CalculateSupernodeCurrent(nodo1, W, comp2);
                }
                else
                {
                    i += comp2.Current(nodo, W);
                }
            }
            return(i);
        }
        protected static void Calculate(List <Node> nodosnorton)
        {
            if (nodosnorton.Count == 0)
            {
                return;
            }

            //existen nodos donde la tension se puede calcular directamente
            List <Node> nodosCalculables = new List <Node>();

            foreach (var nodo in nodosnorton)
            {
                if (nodo.TypeOfNode == Node.NodeType.VoltageDivideNode)
                {
                    nodosCalculables.Add(nodo);
                }
            }
            foreach (var nodo in nodosCalculables)
            {
                nodosnorton.Remove(nodo);
            }

            //remuevo esos nodos de los que deben calcularse matricialmente

            if (nodosnorton.Count > 0)
            {
                int fila = 0, columna = 0;
                var v = Vector <Complex32> .Build.Dense(nodosnorton.Count);

                var A = Matrix <Complex32> .Build.DenseOfArray(new Complex32[nodosnorton.Count, nodosnorton.Count]);

                foreach (var nodo in nodosnorton)
                {
                    columna = fila = nodosnorton.IndexOf(nodo);
                    Complex32 Z, V;
                    if (nodo.TypeOfNode == Node.NodeType.MultibranchCurrentNode ||
                        nodo.TypeOfNode == Node.NodeType.InternalBranchNode)
                    {
                        foreach (var rama in nodo.Components)
                        {
                            if (rama is Branch || rama is PasiveComponent)
                            {
                                columna = fila = nodosnorton.IndexOf(nodo);
                                if (rama is Branch)
                                {
                                    V = ((Branch)rama).NortonCurrent(nodo);
                                }
                                else
                                {
                                    V = rama.Current(nodo);
                                }
                                v[fila]          += V;
                                Z                 = rama.Impedance();
                                A[fila, columna] += 1 / Z;
                                Node nodo2 = rama.OtherNode(nodo);
                                if (!nodo2.IsReference)
                                {
                                    columna           = nodosnorton.IndexOf(nodo2);
                                    A[fila, columna] -= 1 / Z;
                                }
                            }
                            else if (rama is CurrentGenerator)
                            {
                                V        = rama.Current(nodo);
                                v[fila] += V;
                            }
                        }
                    }
                    else if (nodo.TypeOfNode == Node.NodeType.VoltageLinkedNode)
                    {
                        Dipole compo = nodo.Components[0];
                        if (!(compo is VoltageGenerator))
                        {
                            compo = nodo.Components[1];
                        }
                        v[fila]          = compo.Voltage.Real;
                        A[fila, columna] = 1;
                        columna          = nodosnorton.IndexOf(compo.OtherNode(nodo));
                        A[fila, columna] = -1;
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }
                }
                var x = A.Solve(v);

                foreach (var nodo in nodosnorton)
                {
                    fila         = nodosnorton.IndexOf(nodo);
                    nodo.Voltage = x[fila];
                }
            }

            foreach (var nodo in nodosCalculables)
            {
                if (nodo.TypeOfNode == Node.NodeType.VoltageDivideNode)
                {
                    Node   nodo1  = nodo;
                    Dipole compo1 = nodo.Components[0];
                    Branch br     = compo1.Owner as Branch;
                    if (br == null)
                    {
                        throw new Exception();
                    }
                    Complex32 v1, v2, z1, z2;
                    v1 = v2 = z1 = z2 = Complex32.Zero;
                    //el nodo es interno en una rama, deberian los 2 componentes conectados
                    //al nodo,
                    Dipole compo2 = nodo.Components[1];
                    //hacia la izq (o derec)
                    NavigateBranch(nodo1, compo1, ref v1, ref z1);
                    //hacia el otro lado
                    NavigateBranch(nodo1, compo2, ref v2, ref z2);
                    nodo.Voltage = (z2 * v1 + v2 * z1) / (z1 + z2);
                    //nodosCalculables.Add(nodo);
                }
            }

            //return x;
        }
        protected static Branch FindBranch(Circuit cir, Node initialNode, Dipole Component)
        {
            Branch br    = new Branch(cir);
            Dipole compo = Component;
            Node   nodo  = Component.OtherNode(initialNode);

            br.Nodes.Clear();
            //solo es valido si el circuito fue optimizado, y los paralelos
            //se reemplazaron por bloques paralelo
            while (nodo.Components.Count == 2 && cir.Reference != nodo)
            {
                br.Components.Add(compo);
                br.InternalNodes.Add(nodo);
                compo = nodo.OtherComponent(compo);
                nodo  = compo.OtherNode(nodo);
            }
            br.Components.Add(compo);
            if (br.Components.Count > 1)
            {
                initialNode.Components.Remove(Component);
                initialNode.Components.Add(br);
                nodo.Components.Remove(compo);
                nodo.Components.Add(br);
                nodo.TypeOfNode = Node.NodeType.MultibranchCurrentNode;
            }
            br.Nodes.Add(initialNode);
            br.Nodes.Add(nodo);

            //hay que recorrer la rama para buscar los nodos intermedios flotantes
            //y aquellos dependientes de los flotantes
            nodo = compo.OtherNode(nodo);
            while (nodo != initialNode)
            {
                if (nodo.TypeOfNode == Node.NodeType.VoltageFixedNode)
                {
                    // nothing, node was calculated
                }
                else if (compo is VoltageGenerator)
                {
                    if (nodo.TypeOfNode == Node.NodeType.Unknow)
                    {
                        nodo.TypeOfNode = Node.NodeType.VoltageLinkedNode;
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }
                }
                else if (compo is PasiveComponent)
                {
                    if (nodo.TypeOfNode == Node.NodeType.Unknow)
                    {
                        nodo.TypeOfNode = Node.NodeType.VoltageDivideNode;
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }
                }
                else
                {
                    if (nodo.TypeOfNode == Node.NodeType.Unknow)
                    {
                        nodo.TypeOfNode = Node.NodeType.InternalBranchNode;
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }
                }

                compo = nodo.OtherComponent(compo);
                nodo  = compo.OtherNode(nodo);
            }


            return(br);
        }
        /// <summary>
        /// optimize a recent loaded circuit leaving ready for simulation
        /// </summary>
        /// <param name="cir"></param>
        /// <returns></returns>
        public static bool Optimize(Circuit cir)
        {
            List <Dipole>        yaanalizados  = new List <Dipole>();
            List <ParallelBlock> paralelos     = new List <ParallelBlock>();
            List <Node>          nodosnormales = new List <Node>();
            List <Branch>        ramas         = new List <Branch>();
            ParallelBlock        para          = null;

            #region Chequeo de nodos sueltos o componentes colgantes
            foreach (var nodo in cir.Nodes.Values)
            {
                if (nodo.Components.Count == 0)
                {
                    throw new NotImplementedException();
                }
                //componente con borne suelto
                if (nodo.Components.Count == 1)
                {
                    throw new NotImplementedException();
                }
            }
            #endregion

            #region busco componentes en paralelo

            if (false)
            {
                for (int i = 0; i < cir.Components.Count - 1; i++)
                {
                    if (yaanalizados.Contains(cir.Components[i]))
                    {
                        continue;
                    }
                    Dipole comp1 = cir.Components[i];

                    for (int j = i + 1; j < cir.Components.Count; j++)
                    {
                        if (yaanalizados.Contains(cir.Components[j]))
                        {
                            continue;
                        }
                        Dipole comp2 = cir.Components[j];
                        if ((comp1.Nodes[0] == comp2.Nodes[0] && comp1.Nodes[1] == comp2.Nodes[1]) ||
                            (comp1.Nodes[0] == comp2.Nodes[1] && comp1.Nodes[1] == comp2.Nodes[0]))
                        {
                            if (para == null)
                            {
                                para = new ParallelBlock(cir, comp1, comp2);
                                paralelos.Add(para);
                                yaanalizados.Add(comp1);
                                yaanalizados.Add(comp2);
                            }
                            else
                            {
                                para.Components.Add(comp2);
                                yaanalizados.Add(comp2);
                            }
                        }
                    }
                }
            }

            #endregion

            #region reemplazo los componentes paralelos separados por
            //el correspondiente block paralelo
            foreach (var para1 in paralelos)
            {
                foreach (var compo in para1.Components)
                {
                    cir.Components.Remove(compo);
                }

                cir.Components.Add(para1);
            }
            #endregion

            #region identifico la tierra
            Node tierra = cir.Reference;

            if (tierra == null)
            {
                foreach (var item in cir.Nodes.Values)
                {
                    if (item.IsReference)
                    {
                        tierra        = item;
                        cir.Reference = tierra;
                        break;
                    }
                }
            }
            #endregion

            #region arranco desde tierra he identifico los nodos de tension fija,
            //posibles nodos flotantes de corriente y ramas conectadas a tierra

            List <Dipole> componenttoearh = new List <Dipole>();
            componenttoearh.AddRange(tierra.Components);
            foreach (var compo in componenttoearh)
            {
                foreach (var rama in ramas)
                {
                    if (rama.Components.Contains(compo))
                    {
                        goto end;
                    }
                }
                //los nodos de tension fija
                if (compo is VoltageGenerator)
                {
                    Node other = compo.OtherNode(tierra);
                    other.TypeOfNode = Node.NodeType.VoltageFixedNode;
                    other.Voltage    = compo.Voltage;
                }
                //desde tierra los nodos son:
                //a: pertenecen a una rama. hay que levantar dicha rama...
                //b: son nodos normales flotantes (se aplica teorema de nodo)
                Branch br = FindBranch(cir, tierra, compo);
                //si no forma parte de una rama, la rama de 1 elemento se desecha
                ValidateBranch(yaanalizados, nodosnormales, ramas, tierra, compo, br);
            }
            end :;
            #endregion

            #region Analizo las ramas faltantes desde los nodos normales encontrados

            foreach (var nodo in nodosnormales)
            {
                foreach (var compo in nodo.Components)
                {
                    if (ramas.Contains(compo) || yaanalizados.Contains(compo))
                    {
                        continue;
                    }

                    Branch br = FindBranch(cir, nodo, compo);
                    ValidateBranch(yaanalizados, nodosnormales, ramas, nodo, compo, br);
                }
            }

            #endregion

            //reemplazo los componentes que arman una rama por la propia rama
            foreach (var rama in ramas)
            {
                foreach (var compo in rama.Components)
                {
                    cir.Components.Remove(compo);
                }
            }


            cir.Components.AddRange(ramas);

            //foreach (var rama in ramas)
            //{
            //    AddComponentNodes(cir, rama);
            //}
            cir.State            = Circuit.CircuitState.Optimized;
            cir.OptimizedCircuit = cir;
            return(true);
        }
        protected static void Calculate(SolveInfo solveinfo, Complex32 W)
        {
            if (solveinfo.nortonnodes.Count == 0 && solveinfo.calculablenodes.Count == 0)
            {
                return;
            }

            //existen nodos donde la tension se puede calcular directamente
            foreach (var nodo in solveinfo.calculablenodes)
            {
                if (nodo.TypeOfNode == Node.NodeType.VoltageFixedNode)
                {
                    foreach (var compo in nodo.Components)
                    {
                        if (compo.IsConnectedToEarth && (compo is ACVoltageGenerator))
                        {
                            nodo.Voltage = compo.voltage(nodo, W);   //el componente conectado a tierra debe ser Vdc o Vsin o capacitor
                            break;
                        }
                    }
                    continue;
                }
            }

            #region Calculo de tensions mediante matrices

            if (solveinfo.nortonnodes.Count > 0)
            {
                int fila = 0, columna = 0, max;
                //cada componente especial agrega 0, 1 o 2 variable mas, dependiendo del tipo
                max = solveinfo.MatrixDimension;
                var v = Vector <Complex32> .Build.Dense(max);

                var A = Matrix <Complex32> .Build.DenseOfArray(new Complex32[max, max]);

                //primero la ecuacion de transferencia del VcV
                foreach (var info in solveinfo.specialcomponents)
                {
                    //foreach (var item in info.Component)
                    //{

                    //}
                    //int entrada = especialcomponents.IndexOf(info);
                    //fila = nodosnorton.Count - 1 + entrada;
                    columna          = 1;
                    A[fila, columna] = 1;
                }

                foreach (var nodo in solveinfo.nortonnodes)
                {
                    columna = fila = solveinfo.nortonnodes.IndexOf(nodo);
                    Complex32 Z, V;
                    if (
                        nodo.TypeOfNode == Node.NodeType.MultibranchCurrentNode ||
                        nodo.TypeOfNode == Node.NodeType.VoltageFixedNode ||
                        nodo.TypeOfNode == Node.NodeType.InternalBranchNode)
                    {
                        foreach (var rama in nodo.Components)
                        {
                            if (rama is Branch || rama is PasiveComponent)
                            {
                                columna = fila = solveinfo.nortonnodes.IndexOf(nodo);
                                if (rama is Branch)
                                {
                                    V = ((Branch)rama).NortonCurrent(nodo, W);
                                }
                                else
                                {
                                    V = rama.Current(nodo, W);
                                }

                                v[fila]          += V;
                                Z                 = rama.Impedance(W);
                                A[fila, columna] += 1 / Z;
                                Node nodo2 = rama.OtherNode(nodo);
                                if (!nodo2.IsReference)
                                {
                                    columna           = solveinfo.nortonnodes.IndexOf(nodo2);
                                    A[fila, columna] -= 1 / Z;
                                }
                            }
                            else if (rama is CurrentGenerator)
                            {
                                V        = rama.Current(nodo, W);
                                v[fila] += V;
                            }
                            else if (rama is VoltageControlledGenerator)
                            {
                                //int entrada = especialcomponents.Values.ToList().IndexOf(rama);
                                //columna = nodosnorton.Count -1 + entrada;

                                ////un nodo es positva la corriente, en el otro es negativa
                                //if (entrada % 2 == 0)
                                //    A[fila, columna] = 1;
                                //else
                                //    A[fila, columna] = -1;
                            }
                        }
                    }
                    else if (nodo.TypeOfNode == Node.NodeType.VoltageLinkedNode)
                    {
                        Dipole compo = nodo.Components[0];
                        if (!(compo is VoltageGenerator))
                        {
                            compo = nodo.Components[1];
                        }
                        v[fila]          = compo.Voltage.Real;
                        A[fila, columna] = 1;
                        columna          = solveinfo.nortonnodes.IndexOf(compo.OtherNode(nodo));
                        A[fila, columna] = -1;
                    }
                    //else if (nodo.TypeOfNode == Node.NodeType.VoltageFixedNode)
                    //{
                    //    foreach (var rama in nodo.Components)
                    //    {
                    //        if (rama is VoltageControlledGenerator)
                    //        {

                    //        }
                    //    }
                    //}
                    else
                    {
                        throw new NotImplementedException();
                    }
                }
                var x = A.Solve(v);

                foreach (var nodo in solveinfo.nortonnodes)
                {
                    fila         = solveinfo.nortonnodes.IndexOf(nodo);
                    nodo.Voltage = x[fila];
                }
            }

            #endregion

            //existen nodos donde la tension se puede calcular indirectamente
            foreach (var nodo in solveinfo.calculablenodes)
            {
                if (nodo.TypeOfNode == Node.NodeType.VoltageDivideNode)
                {
                    Node   nodo1  = nodo;
                    Dipole compo1 = nodo.Components[0];
                    Branch br     = compo1.Owner as Branch;
                    if (br == null)
                    {
                        throw new Exception();
                    }
                    Complex32 v1, v2, z1, z2;
                    v1 = v2 = z1 = z2 = Complex32.Zero;
                    //el nodo es interno en una rama, deberian los 2 componentes conectados
                    //al nodo,
                    Dipole compo2 = nodo.Components[1];
                    //hacia la izq (o derec)
                    NavigateBranch(nodo1, compo1, W, ref v1, ref z1);
                    //hacia el otro lado
                    NavigateBranch(nodo1, compo2, W, ref v2, ref z2);
                    nodo.Voltage = (z2 * v1 + v2 * z1) / (z1 + z2);
                }
            }
        }
 public SpecialComponentInfo(Dipole comp)
 {
     Component            = comp;
     ImportantInputNodes  = new List <Node>();
     ImportantOutputNodes = new List <Node>();
 }
Example #12
0
    private static void dipole_sample_test()

//****************************************************************************80
//
//  Purpose:
//
//    DIPOLE_SAMPLE_TEST tests DIPOLE_SAMPLE;
//
//  Licensing:
//
//    This code is distributed under the GNU LGPL license.
//
//  Modified:
//
//    24 January 2007
//
//  Author:
//
//    John Burkardt
//
    {
        const int SAMPLE_NUM = 1000;
        const int TEST_NUM   = 3;

        int seed = 123456789;

        double[] test_a =
        {
            0.0, Math.PI / 4.0, Math.PI / 2.0
        }

        ;
        double[] test_b =
        {
            1.0, 0.5, 0.0
        }

        ;
        int test_i;

        double[] x = new double[SAMPLE_NUM];

        Console.WriteLine("");
        Console.WriteLine("DIPOLE_SAMPLE_TEST");
        Console.WriteLine("  DIPOLE_SAMPLE samples the Dipole distribution;");

        for (test_i = 0; test_i < TEST_NUM; test_i++)
        {
            double a = test_a[test_i];
            double b = test_b[test_i];

            Console.WriteLine("");
            Console.WriteLine("  PDF parameter A =      " + a + "");
            Console.WriteLine("  PDF parameter B =      " + b + "");

            if (!Dipole.dipole_check(a, b))
            {
                Console.WriteLine("");
                Console.WriteLine("DIPOLE_SAMPLE_TEST - Fatal error!");
                Console.WriteLine("  The parameters are not legal.");
                return;
            }

            int i;
            for (i = 0; i < SAMPLE_NUM; i++)
            {
                x[i] = Dipole.dipole_sample(a, b, ref seed);
            }

            double mean     = typeMethods.r8vec_mean(SAMPLE_NUM, x);
            double variance = typeMethods.r8vec_variance(SAMPLE_NUM, x);
            double xmax     = typeMethods.r8vec_max(SAMPLE_NUM, x);
            double xmin     = typeMethods.r8vec_min(SAMPLE_NUM, x);

            Console.WriteLine("");
            Console.WriteLine("  Sample size =     " + SAMPLE_NUM + "");
            Console.WriteLine("  Sample mean =     " + mean + "");
            Console.WriteLine("  Sample variance = " + variance + "");
            Console.WriteLine("  Sample maximum =  " + xmax + "");
            Console.WriteLine("  Sample minimum =  " + xmin + "");
        }
    }
Example #13
0
    private static void dipole_cdf_test()

//****************************************************************************80
//
//  Purpose:
//
//    DIPOLE_CDF_TEST tests DIPOLE_CDF.
//
//  Licensing:
//
//    This code is distributed under the GNU LGPL license.
//
//  Modified:
//
//    24 January 2007
//
//  Author:
//
//    John Burkardt
//
    {
        const int TEST_NUM = 3;

        int seed = 123456789;
        int test_i;

        double[] test_a =
        {
            0.0, Math.PI / 4.0, Math.PI / 2.0
        }

        ;
        double[] test_b =
        {
            1.0, 0.5, 0.0
        }

        ;

        Console.WriteLine("");
        Console.WriteLine("DIPOLE_CDF_TEST");
        Console.WriteLine("  DIPOLE_CDF evaluates the Dipole CDF;");
        Console.WriteLine("  DIPOLE_CDF_INV inverts the Dipole CDF.");
        Console.WriteLine("  DIPOLE_PDF evaluates the Dipole PDF;");

        for (test_i = 0; test_i < TEST_NUM; test_i++)
        {
            double a = test_a[test_i];
            double b = test_b[test_i];

            Console.WriteLine("");
            Console.WriteLine("  PDF parameter A =      " + a + "");
            Console.WriteLine("  PDF parameter B =      " + b + "");

            if (!Dipole.dipole_check(a, b))
            {
                Console.WriteLine("");
                Console.WriteLine("DIPOLE_CDF_TEST - Fatal error!");
                Console.WriteLine("  The parameters are not legal.");
                return;
            }

            Console.WriteLine("");
            Console.WriteLine("       X            PDF           CDF            CDF_INV");
            Console.WriteLine("");

            int i;
            for (i = 1; i <= 10; i++)
            {
                double x   = Dipole.dipole_sample(a, b, ref seed);
                double pdf = Dipole.dipole_pdf(x, a, b);
                double cdf = Dipole.dipole_cdf(x, a, b);
                double x2  = Dipole.dipole_cdf_inv(cdf, a, b);

                Console.WriteLine("  "
                                  + x.ToString(CultureInfo.InvariantCulture).PadLeft(12) + "  "
                                  + pdf.ToString(CultureInfo.InvariantCulture).PadLeft(12) + "  "
                                  + cdf.ToString(CultureInfo.InvariantCulture).PadLeft(12) + "  "
                                  + x2.ToString(CultureInfo.InvariantCulture).PadLeft(12) + "");
            }
        }
    }
        protected static void CalculateCurrents(ComponentContainer container, double t)
        {
            foreach (var comp in container.Components)
            {
                //la corriente en las resistencias se calcula directamente en ellas: es ley de Ohm:V/R
                if (comp is CurrentGenerator || comp is Inductor || comp is Resistor)
                {
                    Node nodo = comp.Nodes[0];
                    //comp.current = new Complex32((float)comp.Current(nodo, t), 0);
                    if (container is Branch)
                    {
                        ((Branch)container).current = new Complex32((float)comp.Current(nodo, t), 0);
                    }
                    continue;
                }


                //en los Generadores de tension hay que calcular la corriente en 1 u ambos nodos
                if (comp is VoltageGenerator || comp is Capacitor)
                {
                    foreach (var nodo in comp.Nodes)
                    {
                        if (nodo.IsReference)
                        {
                            continue;
                        }
                        Dipole comp2 = nodo.OtherComponent(comp);
                        //si tiene solo un resistor en serie es automatico el valor de corriente
                        if (nodo.Components.Count == 2 && (comp2 is Resistor || comp2 is CurrentGenerator || comp2 is Inductor))
                        {
                            if (nodo == comp.Nodes[0])
                            {
                                comp.current = new Complex32((float)comp2.Current(nodo, t), 0);
                            }
                            else
                            {
                                comp.current = new Complex32((float)-comp2.Current(nodo, t), 0);
                            }
                            if (container is Branch)
                            {
                                ((Branch)container).current = comp.current;
                            }
                            goto out1;
                        }
                    }
                    Node node = comp.Nodes[0];
                    //si no tiene solo una resistencias en serie, es decir, un nodo de multiples ramas
                    //se aplica 2da de Kirchoff para el supernodo
                    comp.current = new Complex32((float)CalculateSupernodeCurrent(node, comp, t), 0);
                }
                else if (comp is Branch)
                {
                    CalculateCurrents((Branch)comp, t);
                    continue;
                }

                else if (comp is ParallelBlock)
                {
                    CalculateCurrents((ParallelBlock)comp, t);
                    continue;
                }

                out1 :;
            }
        }
        protected static void CalculateCurrents(ComponentContainer container, Complex32 W)
        {
            foreach (var comp in container.Components)
            {
                //la corriente en las resistencias se calcula directamente en ellas: es ley de Ohm:V/R
                if (comp is PasiveComponent || comp is CurrentGenerator)
                {
                    Node nodo = comp.Nodes[0];
                    comp.current = comp.Current(nodo, W);
                    if (container is Branch)
                    {
                        ((Branch)container).current = comp.current;
                    }
                    continue;
                }


                //en los Generadores de tension hay que calcular la corriente en 1 u ambos nodos
                if (comp is VoltageGenerator)
                {
                    foreach (var nodo in comp.Nodes)
                    {
                        Dipole comp2 = nodo.OtherComponent(comp);
                        //si tiene solo un resistor en serie es automatico el valor de corriente
                        if (nodo.Components.Count == 2 && (comp2 is PasiveComponent || comp2 is CurrentGenerator))
                        {
                            comp.current = comp2.Current(nodo, W);

                            if (container is Branch)
                            {
                                ((Branch)container).current = comp.current;
                            }
                            goto out1;
                        }
                    }
                    //si no tiene solo una resistencias en serie, es decir, un nodo de multiples ramas
                    //se aplica 2da de Kirchoff para el supernodo
                    // throw new NotImplementedException();
                    foreach (var nodo in comp.Nodes)
                    {
                        if (nodo.IsReference)
                        {
                            continue;
                        }
                        Complex32 i = Complex32.Zero;
                        i            = CalculateSupernodeCurrent(nodo, W, comp);
                        comp.current = i;
                        break;
                    }
                }
                else if (comp is Branch)
                {
                    CalculateCurrents((Branch)comp, W);
                    continue;
                }

                else if (comp is ParallelBlock)
                {
                    CalculateCurrents((ParallelBlock)comp, W);
                    continue;
                }

                out1 :;
            }
        }
        /// <summary>
        /// Calculate Statics components currents
        /// </summary>
        /// <param name="container"></param>
        private static void CalculateCurrents(ComponentContainer container)
        {
            foreach (var comp in container.Components)
            {
                //la corriente de DC de un capacitor es 0
                if (comp is Capacitor)
                {
                    continue;
                }

                //la corriente en las resistencias se calcula directamente en ellas: es ley de Ohm:V/R
                if (comp is Resistor || comp is CurrentGenerator)
                {
                    if (container is Branch)
                    {
                        Node nodo = comp.Nodes[0];
                        ((Branch)container).current = comp.Current(nodo);
                    }
                    continue;
                }


                //en los Generadores de tension hay que calcular la corriente en 1 u ambos nodos
                if (comp is VoltageGenerator || comp is Inductor)
                {
                    foreach (var nodo in comp.Nodes)
                    {
                        Dipole comp2 = nodo.OtherComponent(comp);
                        //si tiene solo un resistor en serie es automatico el valor de corriente
                        if (nodo.Components.Count == 2 && (comp2 is Resistor || comp2 is CurrentGenerator))
                        {
                            //Node nodo2 = com
                            comp.current = comp2.Current(nodo);

                            if (container is Branch)
                            {
                                ((Branch)container).current = comp.Current(nodo);
                            }
                            goto out1;
                        }
                    }
                    //si no tiene solo una resistencias en serie, es decir, un nodo de multiples ramas
                    //se aplica 2da de Kirchoff para el supernodo
                    throw new NotImplementedException();
                    foreach (var nodo in comp.Nodes)
                    {
                        Complex32 i;
                        foreach (var comp2 in nodo.Components)
                        {
                        }
                    }
                }
                else if (comp is Branch)
                {
                    CalculateCurrents((Branch)comp);
                    continue;
                }

                else if (comp is ParallelBlock)
                {
                    CalculateCurrents((ParallelBlock)comp);
                    continue;
                }

                out1 :;
            }
        }
        protected static void Calculate(SolveInfo solveinfo, double t)
        {
            if (solveinfo.nortonnodes.Count == 0 && solveinfo.calculablenodes.Count == 0)
            {
                return;
            }

            //tensiones que se calculan directamente
            foreach (var nodo in solveinfo.calculablenodes)
            {
                if (nodo.TypeOfNode == Node.NodeType.VoltageFixedNode)
                {
                    foreach (var compo in nodo.Components)
                    {
                        if (compo.IsConnectedToEarth && (compo is VoltageGenerator || compo is Capacitor))
                        {
                            nodo.Voltage = new Complex32((float)compo.voltage(nodo, t), 0);   //el componente conectado a tierra debe ser Vdc o Vsin o capacitor
                            break;
                        }
                    }
                    continue;
                }
            }

            #region Tensiones de nodos que se calculan mediante matriz

            if (solveinfo.nortonnodes.Count > 0)
            {
                int fila = 0, columna = 0;
                var Currs = Vector <double> .Build.Dense(solveinfo.MatrixDimension);

                var A = Matrix <double> .Build.DenseOfArray(new double[solveinfo.MatrixDimension, solveinfo.MatrixDimension]);

                foreach (var nodo in solveinfo.nortonnodes)
                {
                    columna = fila = solveinfo.nortonnodes.IndexOf(nodo);
                    double Z, I;
                    if (nodo.TypeOfNode == Node.NodeType.MultibranchCurrentNode ||
                        nodo.TypeOfNode == Node.NodeType.InternalBranchNode)
                    {
                        foreach (var rama in nodo.Components)
                        {
                            if (rama is Branch || rama is Resistor)
                            {
                                columna = fila = solveinfo.nortonnodes.IndexOf(nodo);
                                if (rama is Branch)
                                {
                                    I = ((Branch)rama).NortonCurrent(nodo, t);
                                }
                                else
                                {
                                    I = rama.Current(nodo, t);
                                }

                                Currs[fila]      += I;
                                Z                 = rama.Impedance().Real;
                                A[fila, columna] += 1 / Z;
                                Node nodo2 = rama.OtherNode(nodo);
                                if (!nodo2.IsReference && solveinfo.nortonnodes.Contains(nodo2))
                                {
                                    columna           = solveinfo.nortonnodes.IndexOf(nodo2);
                                    A[fila, columna] -= 1 / Z;
                                }
                            }
                            else if (rama is CurrentGenerator || rama is Inductor)
                            {
                                I            = rama.Current(nodo, t);
                                Currs[fila] += I;
                            }
                        }
                    }
                    else if (nodo.TypeOfNode == Node.NodeType.VoltageLinkedNode)
                    {
                        Dipole compo = nodo.Components[0];
                        if (!(compo is VoltageGenerator || compo is Capacitor))
                        {
                            compo = nodo.Components[1];
                        }
                        Currs[fila]      = compo.voltage(nodo, t);
                        A[fila, columna] = 1;
                        columna          = solveinfo.nortonnodes.IndexOf(compo.OtherNode(nodo));
                        A[fila, columna] = -1;
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }
                }
                var x = A.Solve(Currs);

                foreach (var nodo in solveinfo.nortonnodes)
                {
                    fila         = solveinfo.nortonnodes.IndexOf(nodo);
                    nodo.Voltage = new Complex32((float)x[fila], 0);
                }
            }
            #endregion

            //existen nodos donde la tension se puede calcular casi directamente
            foreach (var nodo in solveinfo.calculablenodes)
            {
                if (nodo.TypeOfNode == Node.NodeType.VoltageDivideNode)
                {
                    Node   nodo1  = nodo;
                    Dipole compo1 = nodo.Components[0];
                    Branch br     = compo1.Owner as Branch;
                    if (br == null)
                    {
                        throw new Exception();
                    }
                    double v1, v2, z1, z2;
                    v1 = v2 = z1 = z2 = 0;
                    //el nodo es interno en una rama, deberian los 2 componentes conectados
                    //al nodo,
                    Dipole compo2 = nodo.Components[1];
                    //hacia la izq (o derec)
                    NavigateBranch(nodo1, compo1, t, ref v1, ref z1);
                    //hacia el otro lado
                    NavigateBranch(nodo1, compo2, t, ref v2, ref z2);
                    nodo.Voltage = new Complex32((float)((z2 * v1 + v2 * z1) / (z1 + z2)), 0);
                }
            }

            //parto del extremo de la rama
            foreach (var rama in solveinfo.ramas)
            {
                Node nodo1 = null;
                //busco nodos ya calculados en la rama
                foreach (var nodo in rama.InternalNodes)
                {
                    if (!solveinfo.calculablenodes.Contains(nodo) && !solveinfo.nortonnodes.Contains(nodo))
                    {
                        nodo1 = nodo;
                        break;
                    }
                }
                if (nodo1 == null)
                {
                    continue;
                }

                double i = 0;
                //encuentro la corriente impuesta de la rama si es que la hay
                //nodo1 = rama.Nodes[0];

                i = rama.Current(nodo1, t);
                Dipole compo1 = null;
                foreach (var compo in rama.Components)
                {
                    //busco el componente hubicado en un extremo de la rama
                    if (compo.Nodes[0] == nodo1 || compo.Nodes[1] == nodo1)
                    {
                        compo1 = compo;
                        break;
                    }
                }
                Node nodo2 = compo1.OtherNode(nodo1);
                if (compo1 is VoltageGenerator)
                {
                    //nodo de tension vinculada
                    nodo1.Voltage = nodo2.Voltage + new Complex32((float)compo1.voltage(nodo2, t), 0);
                }
                else if (compo1 is Resistor)
                {
                    //nodo interno, pero conocemos la corriente
                    nodo1.Voltage = nodo2.Voltage - new Complex32((float)i * compo1.Impedance().Real, 0);
                }
                else
                {
                    throw new NotImplementedException();
                }
                //if (nodo.TypeOfNode == Node.NodeType.InternalBranchNode)
                //{
                //}
            }
        }