/// <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 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)
                //{
                //}
            }
        }