simulación de transitorios electromagnéticos de sistemas
Post on 29-Oct-2021
3 Views
Preview:
TRANSCRIPT
Simulación de transitorios electromagnéticos de sistemas
eléctricos de potencia empleando programación de unidades de
procesamiento gráfico
Juan Gonzalo Cuartas Bouhot
Universidad Nacional de Colombia
Facultad de Minas
Departamento de Energía Eléctrica y Automática
Medellín, Colombia
2020
Simulación de transitorios electromagnéticos de sistemas
eléctricos de potencia empleando programación de unidades de
procesamiento gráfico
Juan Gonzalo Cuartas Bouhot
Tesis o trabajo de investigación presentada(o) como requisito parcial para optar al título
de:
Magíster en Ingeniería – Ingeniería Eléctrica
Director (a):
Ing. Javier Gustavo Herrera Murcia, PhD
Línea de Investigación:
Sistemas Eléctricos de Potencia
Universidad Nacional de Colombia
Facultad de Minas
Departamento de Energía Eléctrica y Automática
Medellín, Colombia
2020
Dedicatoria
Dedico esta tesis a mi familia, a mi amada
novia y a todos aquellos que contribuyeron a
su elaboración.
“¡Actúa en vez de suplicar! ¡Sacrifícate sin
esperanza de gloria ni recompensa! Si quieres
conocer los milagros, hazlos tú antes. Sólo así
podrá cumplirse tu peculiar destino.”
Ludwig van Beethoven
Agradecimientos
Doy un agradecimiento especial a mi tutor de tesis el profesor Javier Herrera Murcia por
su dedicación y su guía, a través de la cual con paciencia y esmero se llegaron a grandes
resultados.
Por otra parte, me permito agradecer a las siguientes instituciones o personas:
A la Facultad de Minas de la Universidad Nacional de Colombia sede Medellín y a
sus profesores quienes contribuyeron a mi formación como magister.
A HMV Ingenieros Ltda. por brindar los espacios de formación que el curso de una
maestría requiere.
A mi familia, amigos y novia por su especial apoyo, impulsándome a continuar hasta
culminar esta investigación.
Resumen y Abstract IX
Resumen
Los sistemas eléctricos de potencia están evolucionando de manera acelerada; nuevos
elementos como las redes inteligentes, las microredes, los compensadores de potencia
reactiva (SVC) y los sistemas de transmisión flexibles (FACTS), obligan a que los sistemas
eléctricos de potencia deban concebirse como sistemas variables de múltiples
dimensiones. En consecuencia, ya no solo es importante satisfacer los requerimientos de
eficiencia, confiabilidad y compatibilidad sino también contar con herramientas capaces de
hacer frente a la complejidad de los sistemas durante las etapas de diseño y operación.
Entre las herramientas utilizadas, se destaca la simulación digital, la cual ha sido
ampliamente usada en el diseño, optimización y predicción del comportamiento de los
sistemas eléctricos de potencia. En esta área, esta tesis propone una metodología para la
simulación de transitorios electromagnéticos en sistemas eléctricos de potencia
monofásicos empleando Unidades de Procesamiento Gráfico (GPU por sus siglas en
inglés). Metodología que se plantea como una alternativa competente en la simulación de
sistemas de gran tamaño, usando herramientas de fácil acceso como las tarjetas gráficas
convencionales o comunes.
La metodología considera un particionamiento de una red monofásica mediante el uso del
Equivalente de Thévenin Multi Área (MATE por sus siglas en inglés), define la utilización
de los modelos a partir de la regla trapezoidal de integración para emular el
comportamiento de los equipos eléctricos en régimen transitorio y plantea la solución de
estos a través de computación paralela con arquitectura de cálculo CUDA.
La metodología es puesta a prueba en sistemas eléctricos de diferentes tamaños y se
obtiene que bajo ciertas condiciones los métodos propuestos representan una mejora en
tiempo respecto a otras metodologías de solución de transitorios en la GPU propuestas en
la literatura.
Palabras clave: Computación paralela, MATE, Dommel, CUDA, Sistemas eléctricos
de potencia, Transitorios electromagnéticos.
X Simulación de transitorios electromagnéticos mediante programación de GPUs
Abstract
Simulation of electromagnetic transients in electric power systems using graphics processing units.
Electrical power systems are evolving in an accelerated way. New technologies as smart
grids, micro grids, Static Var Compensators (SVC) and Flexible AC Transmission Systems
(FACTS) demand to consider electrical power systems as variable and multidimensional
systems. As consequence, it is not only necessary to satisfy efficiency, reliability and
compatibility requirements but also it is required the use of tools and techniques to deal
with the complexity during the design and operation stages of electrical power systems.
Among the tools used, the digital simulation is highlighted because it has been widely used
in the design, optimization and prediction of the behavior of electrical power systems. In
this field, this Thesis proposes a methodology to simulate single-phase electromagnetic
transients using Graphic Processing Units (GPU). Methodology that as seen in the
following. is a proficient alternative in the simulation of high size electrical systems
transients.
The proposed methodology considers a single-phase network partitioning through the use
of Multi Area Thevenin Equivalents (MATE), defines the use of trapezoidal rule based
equivalent models for transients calculation and proposes the solution of the electrical
power systems by techniques of parallel computing with CUDA GPU programming
architecture.
The methodology is tested in electrical power systems of different sizes and it is obtained
that under some given conditions, the proposed techniques represent a calculation time
improvement in comparison with other GPU parallelizing techniques which are normally
proposed in academic literature.
Keywords: Parallel computing, MATE, Dommel, CUDA, Electrical Power Systems,
electromagnetic transients
Tabla de contenido XI
Contenido
Pág.
Resumen ........................................................................................................................ IX
Lista de figuras ............................................................................................................ XIII
Lista de tablas .............................................................................................................. XV
Lista de Símbolos y abreviaturas ............................................................................... XVI
Introducción .................................................................................................................... 1
1. Generalidades de las metodologías de simulación de transitorios electromagnéticos ........................................................................................................... 5
1.1 Simulación tradicional de transitorios electromagnéticos .................................... 7 1.2 Simulación de transitorios electromagnéticos en tiempo real .............................. 8 1.3 Simulación de transitorios electromagnéticos en Unidades de Procesamiento
Gráfico – GPU. ................................................................................................. 10
2. Equivalente de Thévenin Multi Área - MATE ........................................................ 13
3. Regla trapezoidal de integración y Modelos Equivalentes de Dommel .............. 21
4. Implementación de modelos equivalentes de Dommel y particionamiento de red MATE ....................................................................................................................... 31
5. CUDA y programación de unidades de procesamiento gráfico .......................... 41 5.1 Metodología CPU-GPU-1 .................................................................................. 46 5.2 Metodología base con mayor paralelismo CPU-GPU-2 ..................................... 49 5.3 Metodología GPU completa GPU-O .................................................................. 49
6. Simulación a gran escala de transitorios electromagnéticos ............................. 55 6.1 Generación aleatoria de sistemas eléctricos de potencia .................................. 55
6.1.1 Subsistemas empleados ..................................................................... 55 6.1.2 Línea de transmisión empleada .......................................................... 57 6.1.3 Fuente de corriente tipo rampa ........................................................... 57 6.1.4 Conexión de los subsistemas .............................................................. 57
6.2 Comparación en el tiempo de ejecución GPU vs CPU ...................................... 62
7. Conclusiones y trabajos futuros ........................................................................... 69 7.1 Conclusiones .................................................................................................... 69 7.2 Trabajos futuros ................................................................................................ 71
XII Simulación de transitorios electromagnéticos mediante programación de GPUs
A. Anexo 1: Código validación uso modelos equivalentes de Dommel ................. 73
B. Anexo 2: Código implementación MATE + Dommel ............................................ 75
C. Anexo 3: Código computación paralela metodología CPU-GPU-1 ..................... 78
D. Anexo 4: Código computación paralela metodología CPU-GPU 2. .................... 89
E. Anexo 5: Código computación paralela metodología GPU-GPU O .................. 101
F. Anexo 6: Código CUDA para la solución de transitorios de sistema eléctrico aleatorio en la GPU ..................................................................................................... 113
G. Anexo 7: Código en MATLAB para la solución de transitorios de sistema eléctrico aleatorio en la CPU ...................................................................................... 127
H. Anexo 8: Código en MATLAB para la generación de sistemas eléctricos aleatorios ..................................................................................................................... 131
Bibliografía .................................................................................................................. 137
Lista de figuras XIII
Lista de figuras
Figura 1-1. Simulación Hardware In Loop. A partir de [14] ............................................... 6
Figura 1-2. Ejemplo de corriente de cortocircuito, periodos subtransitorio, transitorio y
estable. A partir de [16] .................................................................................................... 7
Figura 1-3. Velocidad de simulación y poder de computación requeridas para algunos
fenómenos y sistemas típicos. A partir de [4] ................................................................... 9
Figura 2-1. Sistema eléctrico de ejemplo empleado para explicar MATE. ...................... 13
Figura 2-2. Proceso de solución metodología MATE ..................................................... 18
Figura 3-1. Diagrama unifilar sistema de estudio. ......................................................... 23
Figura 3-2. Esquema equivalente para el cálculo de transitorios. .................................. 24
Figura 3-3. Diagrama de flujo algoritmo de solución de transitorios con equivalentes de
Dommel. A partir de [21] ................................................................................................. 26
Figura 3-4. Tensión al extremo de la línea – modelos equivalente de Dommel. ............. 28
Figura 3-5. División sistema eléctrico Figura 3-2 ........................................................... 29
Figura 4-1. Topología sistema de estudio, combinación MATE y Dommel ..................... 32
Figura 4-2. Fuente de corriente tipo rampa sistema de estudio. .................................... 32
Figura 4-3. Circuito equivalente a partir de modelos equivalentes de Dommel .............. 33
Figura 4-4. Circuitos equivalentes línea de transmisión del sistema de prueba ............. 34
Figura 4-6. Diagrama de flujo del algoritmo de solución de transitorios con modelos
equivalentes de Dommel y MATE. A partir de [8], [21]. ................................................... 37
Figura 4-7. Voltaje vs tiempo Nodo 3 del sistema A. ...................................................... 39
Figura 4-8. Voltaje vs tiempo nodo 1 del sistema B. ...................................................... 39
Figura 5-1. Jerarquía de hilos CUDA. A partir de [26] .................................................... 42
Figura 5-2. Esquema general de un programa en CUDA. .............................................. 42
Figura 5-3. Código ejemplo con lectura de memoria no consecutiva. A partir de [25]. ... 43
Figura 5-4. Código ejemplo con lectura de memoria consecutiva. A partir de [25] ......... 44
Figura 5-5. Sistema de prueba para programación en CUDA ........................................ 45
Figura 5-6. Algoritmo de solución – Metodología CPU-GPU-1 y metodología CPU-GPU-2
de solución de transitorios en la GPU. Acciones en azul son ejecutadas en la CPU,
acciones en verde en la GPU ......................................................................................... 47
Figura 5-7. Algoritmo de solución – Metodología GPU-O para solución de transitorios en
la GPU. Acciones en azul son ejecutadas en la CPU, acciones en verde en la GPU ..... 50
Figura 5-8. Voltaje vs Tiempo Nodo 2 subsistema A ..................................................... 53
Figura 5-9. Voltaje vs Tiempo Nodo 3 subsistema B ..................................................... 53
Figura 5-10. Voltaje vs Tiempo Nodo 2 subsistema C ................................................... 54
Figura 6-1. Subsistema tipo A ........................................................................................ 56
Figura 6-2. Subsistema tipo B ........................................................................................ 56
XIV Simulación de transitorios electromagnéticos mediante programación de GPUs
Figura 6-3. Algoritmo para definición del subsistema del cual sale cada línea ............... 59
Figura 6-4. Algoritmo para definición del subsistema al cual llega cada línea ................ 61
Figura 6-5. Voltaje vs tiempo extremo inicial de la línea 1 .............................................. 63
Figura 6-6. Voltaje vs tiempo extremo final de la línea 1 ................................................ 63
Figura 6-7. Voltaje vs tiempo extremo inicial de la línea 3 .............................................. 64
Figura 6-8. Voltaje vs tiempo extremo final de la línea 3 ................................................ 64
Figura 6-9. Voltaje vs tiempo extremo inicial de la línea 5 .............................................. 65
Figura 6-10. Comparativo tiempos de ejecución GPU vs CPU ....................................... 66
Figura 6-11. Comparativo tiempo de ejecución por sistema GPU vs CPU. ..................... 67
Lista de tablas XV
Lista de tablas
Pág.
Tabla 1-1: Componentes principales del equipo de cómputo empleado en la
investigación. ................................................................................................................... 4
Tabla 3-1:Circuitos equivalentes de los componentes básicos de una red. A partir de [21]
....................................................................................................................................... 22
Tabla 5-1: Comparación tiempos de ejecución metodologías. ....................................... 52
Lista de símbolos y abreviaturas XVI
Lista de Símbolos y abreviaturas
Símbolos con letras latinas Símbolo Término Unidad SI Definición
A Matriz de admitancias subsistema A S ( 2-1) B Matriz de admitancias subsistema B S ( 2-2)
a Matriz inversa de admitancias subsistema A multiplicada por p
Ω ( 2-10)
b Matriz inversa de admitancias subsistema B multiplicada por q
Ω ( 2-11)
C Capacitancia F Tabla 3-1
𝑒𝐴 Tensiones del subsistema A considerando caso desacoplado
V ( 2-10)
𝑒𝐵 Tensiones del subsistema B considerando caso desacoplado
V ( 2-11)
ℎ𝐴 Corrientes de inyección subsistema A A ( 2-1) ℎ𝐵 Corrientes de inyección subsistema B A ( 2-2)
𝐼𝑘 Término de historia corriente saliendo nodo k modelo de línea ideal
A Tabla 3-1
𝐼𝑘𝑚 Término de historia corriente entre nodos k y m
A Tabla 3-1
𝐼𝑚 Término de historia corriente saliendo nodo m modelo de línea ideal
A Tabla 3-1
𝑖𝑘𝑚 Corriente del nodo k al nodo m A Tabla 3-1
𝐼𝛼 Corrientes de los enlaces entre los subsistemas
A ( 2-6)
L Inductancia H Tabla 3-1
p Matrices de conectividad de los enlaces subsistema A
1 ( 2-6)
q Matrices de conectividad de los enlaces subsistema B
1 ( 2-7)
R Resistencia eléctrica Ω Tabla 3-1 𝑢𝑘 Tensión en nodo k V Tabla 3-1 𝑢𝑘𝑚 Tensión entre los nodos k y m V Tabla 3-1
𝑢𝑚 Tensión en nodo m V Tabla 3-1 𝑉𝐴 Tensiones nodales subsistema A V ( 2-1)
𝑉𝐵 Tensiones nodales subsistema B V ( 2-2)
Z Matriz diagonal con impedancias de cada enlace
Ω ( 2-6)
𝑍𝛼 Vector de impedancias equivalentes vista desde los enlaces
Ω ( 2-19)
Lista de símbolos y abreviaturas XVII
Símbolo Término Unidad SI Definición
𝑍𝑐 Impedancia característica línea de transmisión
Ω Figura 3-1
Símbolos con letras griegas Símbolo Término Unidad SI Definición
α Enlaces entre subsistemas 1 Figura 2-1 ∆t Paso de tiempo s ( 3-2), ( 3-4)
Subíndices Subíndice Término
α Referente a los enlaces entre subsistemas
Abreviaturas Abreviatura Término
CPU Unidad de procesamiento central CHIL Controller Hardware In Loop GPU Unidad de procesamiento gráfico HIL Hardware In Loop MATE Equivalente de Thévenin Multi Área PHIL Power Hardware In Loop
RTS Real Time Simulation (Simulación en tiempo real)
Introducción
Los simuladores de sistemas eléctricos han sido ampliamente usados en su planeación,
diseño y mejora por décadas; a pesar de ello, actualmente y frente a la creciente
complejidad de las redes eléctricas, el enfoque de verificar su comportamiento sin
necesidad de afectar sistemas reales o de construir complejas configuraciones, sigue
estando vigente. Actualmente, para garantizar la seguridad y funcionalidad de los diseños
resulta imprescindible la realización de estudios eléctricos que incluyen simulaciones
computacionales de diversos escenarios y fenómenos en múltiples escalas de tiempo. [1]
Entre el conjunto de simulaciones, es importante destacar la simulación digital de
transitorios electromagnéticos, ya que esta requiere la solución de una gran cantidad de
ecuaciones en el dominio del tiempo implicando recursos computacionales significativos.
Tradicionalmente, para la solución de transitorios electromagnéticos se efectúan tres
pasos: (1) La discretización de las ecuaciones diferenciales asociadas al sistema bajo
estudio, (2) la solución iterativa de ecuaciones algebraicas no lineales y (3) la solución de
ecuaciones algebraicas lineales; pasos que normalmente son desarrollados de manera
secuencial ocasionando que en sistemas de gran tamaño deba aumentarse bien sea el
recurso computacional, o el tiempo de simulación [2].
Con el incremento continuo en el acceso a tecnologías de computación cada vez más
eficientes, nuevas metodologías para la solución de transitorios electromagnéticos han
surgido y nuevos métodos como la computación paralela o en la nube se han destacado
como alternativas para lograr simulaciones cada vez más rápidas y precisas [1], [3]. No
obstante, ante el reto de la eficiencia, las soluciones más comunes se han dado a través
de costosos super computadores y elementos de hardware dedicados, o mediante el uso
de herramientas de software que resultan ser inflexibles o aplican reducciones de los
sistemas eléctricos de potencia sacrificando la precisión de los resultados. [1][4]
2 Simulación de transitorios electromagnéticos mediante programación de GPUs
Lo anterior, ha propiciado un vacío en la exploración de nuevas metodologías de
paralelización combinadas con nuevas herramientas como la programación de Unidades
de Procesamiento Gráfico (GPU por sus siglas en inglés), lo cual se estima facilitaría la
implementación de un simulador eficiente y accesible [4], [5]. En consecuencia, esta tesis
plantea la implementación de una metodología para el cálculo de transitorios
electromagnéticos en sistemas eléctricos de potencia a partir de la implementación de
diferentes estrategias modernas de solución de redes eléctricas y computación paralela en
entornos que involucran el uso de unidades de procesamiento gráfico. Esto con el fin de
lograr principalmente una disminución cuantificable de los tiempos de cálculo invertidos en
este tipo de soluciones, especialmente cuando la escala de los sistemas simulados es
considerable.
En este trabajo se plantearon inicialmente como objetivo general y objetivos específicos
los siguientes:
Objetivo general: implementar una metodología que mejore los tiempos de simulación de
transitorios electromagnéticos de potencia basada en técnicas modernas de solución de
redes eléctricas y de computación paralela.
Objetivos específicos:
Definir el esquema de particionamiento de red que será empleado en la simulación
de transitorios electromagnéticos de sistemas eléctricos de potencia.
Evaluar a partir de técnicas de partición, las condiciones de operación de sistemas
eléctricos de potencia.
Solucionar el sistema eléctrico de potencia a partir de técnicas de computación
paralela
Para el cumplimiento de los anteriores objetivos, esta investigación propuso una
metodología en la cual los sistemas eléctricos de potencia de gran tamaño se dividen en
subsistemas a través del uso de Equivalentes de Thévenin Multi Área – MATE [6]–[8]. A
partir de esto, cada subsistema se soluciona considerando la representación de sus
elementos en modelos equivalentes obtenidos a partir de la regla trapezoidal de integración
o también conocidos como “Equivalentes de Dommel”. La metodología propuesta se aplica
Introducción 3
a redes monofásicas pero su implementación en el caso polifásico sería implementable a
través de los conceptos aquí expuestos.
La implementación conjunta de los equivalentes de Thévenin Multi Área y de los modelos
equivalentes obtenidos a partir de la aplicación de la regla trapezoidal constituye un
significativo aporte de esta investigación. Lo anterior, teniendo en cuenta que en la
literatura revisada relacionada con los equivalentes de Thévenin Multi Área no se utilizan
modelos detallados de la línea de transmisión para el cálculo de transitorios, en su lugar
únicamente se incluye una impedancia de enlace [3], [8]–[10]. El modelo de línea empleado
corresponde al modelo ideal de línea de transmisión, pero la metodología propuesta puede
extenderse a otros modelos más detallados.
Otro aporte relevante de la presente investigación corresponde a la solución de las
ecuaciones asociadas al comportamiento dinámico del sistema eléctrico a partir de
técnicas de computación paralela. Para ello se utiliza la plataforma CUDA en la
implementación de la metodología anteriormente mencionada. Esta plataforma de
computación paralela ha sido desarrollada por la compañía NVIDIA y permite a los
programadores usar una extensión del lenguaje C para codificar algoritmos en unidades
de procesamiento gráfico [11], [12]. Basado en esto, la investigación propone una
ejecución completa de los algoritmos propuestos directamente en la GPU, y un
preprocesamiento llevado a cabo en la CPU. A lo largo del presente documento, se logra
demostrar que al aplicar el enfoque de ejecución propuesto se mejoran los tiempos de
simulación de transitorios electromagnéticos en sistemas eléctricos de gran tamaño en
comparación con el enfoque híbrido CPU – GPU y para grandes escalas, el enfoque
tradicional de ejecución en la CPU.[2], [11], [13].
El documento está organizado de la siguiente manera. En el capítulo 1 de este documento
se presentan algunas metodologías actuales de simulación de transitorios
electromagnéticos. Seguidamente, en el capítulo 2 se explica la utilización de Equivalentes
de Thévenin Multi Área (MATE) como esquema de particionamiento de red. En el capítulo
3, se define el uso de los modelos de Dommel para emular el comportamiento transitorio
de los equipos que constituirán los sistemas eléctricos de potencia de prueba. En el
capítulo 4 se combinan los capítulos 2 y 3, en una implementación de MATE combinada
con los modelos equivalentes de Dommel.
4 Simulación de transitorios electromagnéticos mediante programación de GPUs
Con el entendimiento de las metodologías de paralelización normalmente propuestas en
la literatura y las técnicas de solución de sistemas eléctricos de potencia, explicadas en los
capítulos 2, 3 y 4; el capítulo 5 efectúa una comparación del enfoque “clásico” o
metodología base de paralelización, con un enfoque mixto GPU – CPU y un enfoque de
simulación completamente implementado en la GPU. Como aporte de la investigación se
pone a disposición una metodología que resulta competente en la solución de transitorios
de gran tamaño como se evidencia en el capítulo 6.
Los resultados presentados en esta investigación son consecuencia de la ejecución de los
códigos descritos en los capítulos siguientes y presentados en los anexos. El equipo de
cómputo usado tiene las siguientes especificaciones principales:
Tabla 1-1: Componentes principales del equipo de cómputo empleado en la investigación.
COMPONENTE CARACTERÍSTICAS
Procesador Intel Core I5-8300H 2.30 GHz
Memoria RAM 8 GB DDR4
Unidad de procesamiento
gráfico - GPU
NVIDIA GeForce GTX 1050 con 8036 MB de
memoria total
1. Generalidades de las metodologías de simulación de transitorios electromagnéticos
Una simulación consiste en una representación de la operación o de las características de
un sistema a través del uso de otro [1]. En el contexto de la simulación de sistemas
eléctricos de potencia, según la tecnología empleada, existen diferentes clases de
simulaciones entre las cuales se resaltan las siguientes [14]:
Simulación digital: una simulación de este tipo requiere que todo el sistema,
incluyendo las protecciones, el control y otros accesorios, sean modelados en el
simulador, de manera tal que esta no involucra o requiere de interfaces externas ni
de entradas o salidas análogas y digitales.
Hardware In Loop (HIL por sus siglas en inglés): como se ilustra en la Figura
1-1, en una simulación HIL se emplea un computador como la representación virtual
de un sistema eléctrico el cual intercambia señales con la versión real de un
controlador, protección o equipo bajo prueba. Lo anterior, permite el prototipado,
desarrollo y prueba de sistemas de control y protección reales, sin la necesidad de
que estos sean instalados en sistemas eléctricos de potencia existentes o se
requiera la construcción de una red eléctrica de prueba. Esto reduce
significativamente los costos, el riesgo y permite la detección temprana de errores,
contribuyendo así a reducir fallas en la operación de los sistemas eléctricos.
A su vez, la simulación tipo Hardware In Loop se divide en dos metodologías: Power
Hardware In Loop (PHIL) y Controller Hardware In Loop (CHIL), las cuales son
también mostradas en la Figura 1-1. En la división izquierda de la figura se
presenta la simulación CHIL, la cual comprende un simulador en tiempo real del
que se toman señales que son acondicionadas para ser llevadas a un controlador;
nótese que en este caso no hay amplificación de las señales del simulador en
6 Simulación de transitorios electromagnéticos mediante programación de GPUs
tiempo real para emular la transmisión de potencia eléctrica. En la división derecha
de la figura se tiene también un simulador en tiempo real; Sin embargo, en esta
metodología se utiliza un amplificador con el propósito de generar no solo un
intercambio de señales sino una emulación de transferencia de potencia eléctrica
entre los sistemas conectados.
Figura 1-1. Simulación Hardware In Loop. A partir de [14]
En esta investigación las simulaciones realizadas son completamente digitales; Sin
embargo, la metodología propuesta podría mejorarse hasta aplicarse a simulaciones del
tipo Hardware in Loop con los accesorios pertinentes.
Los sistemas eléctricos de potencia se encuentran sometidos a fenómenos caracterizados
por diferentes formas de onda, frecuencias, magnitudes y orígenes. En consecuencia, las
simulaciones tienen como objetivo llevar a cabo análisis según el fenómeno o perturbación
de interés. Por ejemplo, una simulación de sistemas eléctricos de potencia podrá ser,
según la escala de tiempo, una simulación de régimen transitorio o de régimen
permanente; o según el dominio, una simulación con dominio en frecuencia o dominio en
tiempo.[15]
Como se presenta a continuación, la simulación de transitorios electromagnéticos de
sistemas eléctricos de potencia requiere la solución de un gran conjunto de ecuaciones en
el dominio del tiempo implicando el uso de significativos recursos computacionales.
Mencionada condición, define una necesidad continua de aprovechar adecuadamente los
recursos computacionales disponibles y reducir tiempos de simulación la cual se intensifica
en el caso particular de la simulación en tiempo real.[2]
Generalidades de las metodologías de simulación de transitorios
electromagnéticos
7
1.1 Simulación tradicional de transitorios electromagnéticos
Cuando se presenta una perturbación en un sistema eléctrico de potencia, bien sea por el
impacto de una descarga atmosférica, un cortocircuito o una maniobra, se altera el
equilibrio de energía almacenada en este. Durante esta alteración, intercambios de energía
se llevan a cabo entre los campos eléctricos y magnéticos a las frecuencias naturales del
sistema y a las asociadas a la perturbación; como resultado de ello, las corrientes y voltajes
se desvían de sus formas de onda previas a esta y cuando un nuevo equilibrio es
alcanzado después de un intervalo de tiempo, el sistema retorna a un nuevo estado estable
[15].
Un ejemplo de las alteraciones mencionadas es presentado en la Figura 1-2, la cual
corresponde a la corriente de cortocircuito en una máquina síncrona [16]. En la figura se
identifica que tras la ocurrencia del cortocircuito en el instante t=0s, la corriente presenta
comportamientos variantes en el tiempo distinguiéndose de izquierda a derecha los
periodos subtransitorios, transitorios y de estado estable. Esta investigación se enfocará
en la simulación del comportamiento de las variables eléctricas del circuito en estos
periodos de tiempo.
Figura 1-2. Ejemplo de corriente de cortocircuito, periodos subtransitorio, transitorio y estable. A partir de [16]
8 Simulación de transitorios electromagnéticos mediante programación de GPUs
La teoría del análisis de transitorios electromagnéticos aplicada a sistemas eléctricos de
potencia basada en el análisis nodal y propuesta en el siglo XX [13], es todavía el método
más usado por los programas computacionales de simulación de transitorios
electromagnéticos. Generalmente, este tipo de simulación es aplicada a pequeños
sistemas o a porciones de sistemas de gran envergadura, con el fin de verificar por ejemplo
las sobretensiones a las que teóricamente se verán expuestos algunos equipos, o la
simulación de sistemas de control y protección. Sin embargo, con el desarrollo e
implementación de nuevas tecnologías como las líneas de transmisión en corriente
continua y el crecimiento de la generación a partir de fuentes de energía renovables no
convencionales, se da origen a procesos o perturbaciones transitorias no usuales, lo cual
cambia las características tradicionales de las redes eléctricas y trae nuevos retos a las
simulaciones de sistemas eléctricos de potencia de gran tamaño. En estos ya no solo debe
considerarse la porción de la red o el equipo sino gran parte o todo el sistema en
cuestión.[13]
Es un reto considerable realizar la simulación de transitorios electromagnéticos de un
sistema completo debido a la dificultad de asegurar la precisión y estabilidad de la
simulación a medida que el tamaño del sistema crece [13]. Reto que se intensifica si la
simulación pretende ser de tipo real.
1.2 Simulación de transitorios electromagnéticos en tiempo real
La simulación de transitorios electromagnéticos en tiempo real (RTS por sus siglas en
inglés), es también una simulación de transitorios electromagnéticos, pero se caracteriza
por el hecho de que el modelo debe ser siempre solucionado en pasos de tiempo discretos
y coordinados con el proceso de cálculo o computación.
En la simulación de sistemas eléctricos de potencia se presentan dos tipos de
simulaciones, una simulación del tipo fuera de línea u offline y otra en tiempo real. En las
simulaciones de tipo offline el proceso computacional no tiene que estar sincronizado con
la contraparte real del sistema que se está simulando y puede ser más rápida o lenta que
este. En la simulación en tiempo real, considerando que posiblemente al simulador se
encuentra conectado un controlador o un equipo real, se requiere que el tiempo de
Generalidades de las metodologías de simulación de transitorios
electromagnéticos
9
cómputo inicie y finalice de manera sincronizada con los tiempos reales del sistema y el
fenómeno que se está simulando.[14].
A comparación de la simulación del tipo offline, donde el tiempo para resolver las
ecuaciones puede ser mayor o menor y el momento en el que se presentan los resultados
es irrelevante, en las RTS para cada paso de tiempo el simulador debe leer las entradas,
generar salidas, solucionar las ecuaciones e integrar sus resultados con todos los nodos
de tal manera que estos resultados puedan ser convertidos a señales análogas. En
consecuencia, el paso de tiempo debe ser cuidadosamente seleccionado considerando la
necesidad de reproducir y presentar resultados a la misma velocidad que lo haría la
contraparte real del sistema [1], [14]. En esta investigación la simulación será del tipo
offline; sin embargo, con las herramientas necesarias la metodología propuesta puede ser
optimizada para ser empleada en simulaciones de tiempo real.
En la Figura 1-3, se presentan las características del recurso computacional requerido
como función de las velocidades necesarias de simulación en tiempo real para algunos
sistemas mecánicos y eléctricos. Se observa que las velocidades de simulación son
definidas de acuerdo con el sistema y el fenómeno a analizar y que la velocidad de
simulación seleccionada impone un requisito computacional.
Figura 1-3. Velocidad de simulación y poder de computación requeridas para algunos fenómenos y sistemas típicos. A partir de [4]
10 Simulación de transitorios electromagnéticos mediante programación de GPUs
En respuesta a la exigencia de velocidad en simulaciones eléctricas de sistemas de
potencia de gran tamaño y en particular de las simulaciones en tiempo real, se tienen
diversas alternativas y entre ellas se destaca la simulación de transitorios
electromagnéticos en la GPU como una alternativa accesible y competente. Esta
alternativa es descrita a continuación.
1.3 Simulación de transitorios electromagnéticos en Unidades de Procesamiento Gráfico – GPU.
El cálculo acelerado basado en Unidades de Procesamiento Gráfico - GPU puede ser
definido como el uso de estas en combinación con una unidad central de procesamiento
(CPU) para acelerar aplicaciones de análisis e ingeniería. Esta metodología fue introducida
por la empresa NVIDIA en el año 2007 y se fundamenta en el hecho de que las GPU
poseen miles de núcleos que pueden programarse para procesar las cargas de trabajo de
forma paralela y eficiente. [11], [12]
Con base en lo anterior, el objetivo de una aplicación que use GPUs es el de trasladar las
partes de esta con mayor carga computacional a la GPU y dejar el resto del código
ejecutándose en la CPU, teniendo entonces como resultado que las aplicaciones se
ejecutarán en general más rápido. [2], [11]
Dado lo anterior, se tiene que en la simulación basada en unidades de procesamiento
gráfico (GPU) se parte de un esquema de división del problema principal en problemas
independientes, los cuales pueden ser resueltos paralelamente de manera simultánea. En
el particular de los sistemas eléctricos de potencia, los métodos para realizar la división de
los mismos pueden ser clasificados en las siguientes categorías: geométrico, combinatorio,
matemático, espectral y métodos multinivel [3]. En esta investigación, el sistema eléctrico
de potencia se divide gráficamente, considerando la agrupación de elementos en
subsistemas por su pertenencia a la misma infraestructura o red eléctrica real y la conexión
de estos subsistemas a través de líneas de transmisión. Para la solución paralela y unión
de los múltiples resultados en una única solución, se empleará la metodología llamada
Equivalentes de Thévenin Multi Área (MATE), la cual ha demostrado ser precisa y rápida.
[3], [9]
En la programación de unidades de procesamiento gráfico, se identifican principalmente
dos interfaces de programación: CUDA y OpenCL [17]. OpenCL es un estándar que puede
Generalidades de las metodologías de simulación de transitorios
electromagnéticos
11
ser usado para programar CPUs, GPUs y otros dispositivos de diferentes fabricantes. En
su lugar, CUDA es específico para GPUs fabricadas por NVIDIA. Sin embargo, aunque
OpenCL promete un lenguaje portable para la programación de GPUs, esto involucra
sacrificios en rendimiento en comparación con CUDA [17], [18]. De igual manera, es
posible convertir un código generado en CUDA a uno de OpenCL a través de mínimas
modificaciones. [17]. Como resultado de lo anterior en búsqueda de un mayor rendimiento,
esta investigación utilizará la arquitectura de programación de unidades de procesamiento
gráfico (GPU) CUDA.
En la solución de transitorios de sistemas eléctricos de potencia en las GPU, es común
usar un enfoque híbrido CPU-GPU, donde las partes del problema que no pueden ser
paralelizadas son ejecutadas en la CPU y aquellas que pueden ejecutarse en paralelo se
resuelven en la GPU. Este enfoque involucra un costo computacional asociado a la
transferencia continua de memoria entre la GPU y la CPU. [2], [5],[19]
El desempeño de la programación basada en CUDA depende del nivel de paralelización
del problema que se desee resolver. Para definir un enfoque de solución paralelo de
sistemas eléctricos de potencia de gran tamaño, esta investigación define emplear el
particionamiento y solución de red a partir de equivalentes de Thévenin Multi Área los
cuales son explicados a continuación.
2. Equivalente de Thévenin Multi Área - MATE
El equivalente de Thévenin Multi Área (MATE por sus siglas en inglés) parte del hecho que
una red eléctrica de gran tamaño puede ser dividida en pequeñas partes denominadas
subsistemas. Los subsistemas a su vez estarán unidos por algunas ramas o enlaces que
no harán parte de estos[7], [8]. En el análisis de la interacción de los subsistemas, MATE
hace uso del análisis nodal modificado [20] con el fin de combinar en la misma matriz
ecuaciones nodales y ecuaciones de las ramas que conectan los sistemas, tal como se
explica a continuación.
Para explicar la metodología se tomará como base un ejemplo al igual que el reportado en
[8]. Para este, se propone la siguiente topología de red:
Figura 2-1. Sistema eléctrico de ejemplo empleado para explicar MATE.
Esta red puede ser dividida en dos (2) subsistemas de tamaño aproximadamente igual,
llamados subsistemas A y B, conectados a través de enlaces ∝1 𝑦 ∝2. Si cada subsistema
fuera un sistema totalmente independiente se tendrían las siguientes ecuaciones:
[𝐴][𝑣𝐴] = [ℎ𝐴] ( 2-1)
14 Simulación de transitorios electromagnéticos mediante programación de GPUs
[𝐵][𝑣𝐵] = [ℎ𝐵] ( 2-2)
Para los subsistemas A y B respectivamente. Donde A corresponde a la matriz de
admitancia nodal que involucra a los nodos 1 a 4 y B a la matriz de admitancia nodal que
involucra los nodos 1 a 3, y están dadas por:
𝐴 = [
𝐺𝐴12 + 𝐺𝐴14 −𝐺𝐴12 0 −𝐺𝐴14
−𝐺𝐴12 𝐺𝐴12 + 𝐺𝐴23 −𝐺𝐴23 00 −𝐺𝐴23 𝐺𝐴23 + 𝐺𝐴34 −𝐺𝐴34
−𝐺𝐴14 0 −𝐺𝐴34 𝐺𝐴34 + 𝐺𝐴14
] ( 2-3)
𝐵 = [
𝐺𝐵12 + 𝐺𝐵13 −𝐺𝐵12 −𝐺𝐵13
−𝐺𝐵12 𝐺𝐵12 + 𝐺𝐵23 −𝐺𝐵23
−𝐺𝐵13 −𝐺𝐵23 𝐺𝐵13 + 𝐺𝐵23
] ( 2-4)
Además, con ℎ𝐴 y ℎ𝐵 como las respectivas corrientes de inyección, 𝑣𝐴 y 𝑣𝐵 corresponden
a las tensiones nodales de los nodos de los subsistemas A y B respectivamente.
Las ecuaciones ( 2-1) y ( 2-2) pueden ser combinadas en una única matriz como:
[𝐴 00 𝐵
] [𝑣𝐴
𝑣𝐵] = [
ℎ𝐴
ℎ𝐵] ( 2-5)
Haciendo uso de la técnica de análisis nodal modificado (MNA), en la cual se combinan
ecuaciones nodales con ecuaciones de corriente de ramas, se añaden a la ecuación ( 2-5)
las expresiones asociadas a las corrientes de los enlaces ∝1 𝑦 ∝2, obteniendo:
[
𝐴 0 𝑝0 𝐵 𝑞
𝑝′ 𝑞′ −𝑧] [
𝑣𝐴
𝑣𝐵
𝐼𝛼] = [
ℎ𝐴
ℎ𝐵0
] ( 2-6)
Donde 𝐼𝛼 corresponde al vector de corriente de los enlaces 𝛼1 y 𝛼2, 𝐼𝛼 = [𝐼𝛼1, 𝐼𝛼2]′; 𝑝 y 𝑞
corresponden a las matrices de inyección derivadas de los enlaces y asociadas a los
subsistemas A y B respectivamente. Sus elementos tendrán un valor +1 si la corriente sale
del nodo y -1 si entra al mismo. Para la red mostrada en la Figura 2-1, corresponden a las
siguientes matrices:
Equivalentes de Thévenin Multi Área (MATE) 15
𝑝 = [
0 00 0
+1 00 +1
] , 𝑞 = [−1 00 00 −1
] ( 2-7)
𝑝′ y 𝑞′son las matrices transpuestas de las matrices 𝑝 y 𝑞 presentadas anteriormente:
𝑝′ = [0 0 +1 00 0 0 +1
] , 𝑞 = [−1 0 00 0 −1
] ( 2-8)
Nótese que la cantidad de columnas de 𝑝 y 𝑞 corresponde al número de enlaces
involucrados ( 𝛼1 y 𝛼2 en este caso), y la cantidad de filas al número de nodos de los
respectivos subsistemas. Esta es la razón de por qué la matriz 𝑝, asociada al subsistema
A, cuenta con cuatro filas y 𝑞, asociada al subsistema B, con tres filas.
En ( 2-6) 𝑧 corresponde a una matriz diagonal con las impedancias de los enlaces 𝛼1 y 𝛼2:
𝑧 = [𝑧𝛼1
0
0 𝑧𝛼2
]
( 2-9)
En la ecuación ( 2-6) se representa el sistema de forma matricial; Sin embargo, este modelo
implica resolver todos los subsistemas simultáneamente. Con el propósito de encontrar un
conjunto de expresiones que denoten independencia en el proceso de solución, se procede
a operar matemáticamente cada fila de ( 2-6)
En ( 2-6) se multiplica la primera fila por 𝐴−1 y operando:
𝐴−1[𝐴 0 𝑝] [
𝑣𝐴
𝑣𝐵
𝐼𝛼] = 𝐴−1[ℎ𝐴]
[𝐴−1𝐴 0 𝐴−1𝑝] [
𝑣𝐴
𝑣𝐵
𝐼𝛼] = [𝐴−1ℎ𝐴]
[Ι 0 𝑎] [
𝑣𝐴
𝑣𝐵
𝐼𝛼] = [𝑒𝐴] ( 2-10)
De manera análoga, en ( 2-6) se multiplica la fila 2 por 𝐵−1 obteniéndose que:
[0 I 𝑏] [
𝑣𝐴
𝑣𝐵
𝐼𝛼] = [𝑒𝐵] ( 2-11)
16 Simulación de transitorios electromagnéticos mediante programación de GPUs
Finalmente, para la última fila de ( 2-6) que representa los enlaces entre subsistemas se
tiene que
[𝑝′ 𝑞′ −𝑧] [
𝑣𝐴
𝑣𝐵
𝐼𝛼] = [0] ( 2-12)
De ( 2-10) y ( 2-11) es posible obtener expresiones para 𝑣𝐴 y 𝑣𝐵 en términos de 𝐼𝛼, 𝑒𝐴 y
𝑒𝐵:
𝑣𝐴 = 𝑒𝐴 − 𝑎𝐼𝛼 ( 2-13)
𝑣𝐵 = 𝑒𝐵 − 𝑏𝐼𝛼 ( 2-14)
Al sustituirlas en ( 2-12) se obtiene:
[𝑝′ 𝑞′ −𝑧] [
𝑒𝐴 − 𝑎𝐼𝛼𝑒𝐵 − 𝑏𝐼𝛼
𝐼𝛼
] = [0] ( 2-15)
Expandiendo la ecuación ( 2-15), la expresión resultante es agrupada y escrita en forma
matricial considerando como factor común 𝐼𝛼 :
(𝑝′𝑎 + 𝑞′𝑏 + 𝑧)𝐼𝛼 = 𝑝′𝑒𝐴 + 𝑞′𝑒𝐵
[𝑝′𝑎 + 𝑞′𝑏 + 𝑧] [𝐼𝛼] = [𝑝′𝑒𝐴 + 𝑞′𝑒𝐵] ( 2-16)
El vector de incógnitas de la ecuación ( 2-16) es aumentando con 𝑣𝐴 y 𝑣𝐵 para recuperar
las incógnitas planteadas en la ecuación ( 2-6). En consecuencia, la última fila de la
ecuación ( 2-6) puede ser reemplazada por la siguiente:
[0 0 𝑝′𝑎 + 𝑞′𝑏 + 𝑧] [
𝑣𝐴
𝑣𝐵
𝐼𝛼] = [𝑝′𝑒𝐴 + 𝑞′𝑒𝐵] ( 2-17)
Agrupando las ecuaciones ( 2-10), ( 2-11) y ( 2-17) se tiene que:
[1 0 𝑎0 1 𝑏0 0 𝑍𝛼
] [
𝑣𝐴
𝑣𝐵
𝐼𝛼] = [
𝑒𝐴
𝑒𝐵𝑒𝛼
] ( 2-18)
Equivalentes de Thévenin Multi Área (MATE) 17
Con:
𝑎 = 𝐴−1𝑝 𝑒𝐴 = 𝐴−1ℎ𝐴
𝑏 = 𝐵−1𝑞 𝑒𝐵 = 𝐵−1ℎ𝐵
𝑍𝛼 = 𝑝′𝑎 + 𝑞′𝑏 + 𝑧 𝑒𝛼 = 𝑝′𝑒𝐴 + 𝑞′𝑒𝐵
( 2-19)
Nótese que en ( 2-18) en conjunto con las ecuaciones presentadas en ( 2-19), los sistemas
pueden resolverse usando el siguiente proceso de solución[7], [8]:
1. Hallar las tensiones internas de cada subsistema considerando que se encuentran
desacoplados y haciendo uso de las siguientes expresiones, con ℎ𝐴 y ℎ𝐵 siendo las
corrientes de inyección de cada uno de los susbsistemas:
𝑒𝐴 = 𝐴−1ℎ𝐴
𝑒𝐵 = 𝐵−1ℎ𝐵 ( 2-20)
2. Hallar las tensiones vistas desde los enlaces empleando la siguiente expresión:
𝑒𝛼 = 𝑝′𝑒𝐴 + 𝑞′𝑒𝐵 ( 2-21)
3. Hallar las corrientes de los enlaces, usando la inversa de la matriz 𝑍𝛼 definida en
( 2-19):
𝐼𝛼 = 𝑍𝛼−1𝑒𝛼 ( 2-22)
4. Hallar de nuevo los voltajes internos de los subsistemas pero inyectando las
corrientes de enlace calculadas en ( 2-22) y haciendo uso de las siguientes
expresiones, las cuales se derivan de las ecuaciones ( 2-18) y ( 2-19) :
𝑣𝐴 = 𝐴−1(ℎ𝐴 − 𝑝𝐼𝛼)
𝑣𝐵 = 𝐵−1(ℎ𝐵 − 𝑞𝐼𝛼) ( 2-23)
18 Simulación de transitorios electromagnéticos mediante programación de GPUs
En términos generales, la metodología MATE propone el siguiente esquema de solución
Figura 2-2. Proceso de solución metodología MATE
Se ha definido entonces un esquema de particionamiento de red, el cual permite separar
grandes sistemas eléctricos de potencia en subsistemas que pueden ser resueltos de
manera independiente y simultánea.
Para la selección de la estrategia de división de la red en subsistemas se debe tener en
cuenta que un buen esquema de particionamiento debe distribuir a cada unidad de cálculo
o procesador aproximadamente igual número de operaciones y al mismo tiempo debe
minimizar el número de cálculos de enlaces y la comunicación entre unidades de
procesamiento [3].
Teniendo en cuenta que en esta investigación se considera que el sistema eléctrico de
potencia estará conformado por conjuntos o subsistemas que serán de aproximadamente
igual tamaño, se decide realizar la división del sistema eléctrico de potencia a través de un
esquema de particionamiento gráfico, en el cual se establecerán los subsistemas de
acuerdo con la pertenencia de los elementos a la misma infraestructura o red eléctrica real.
De acuerdo con la literatura, los esquemas de particionamiento gráfico pueden ser usados
para relacionar dependencias en la simulación de sistemas de potencia y el
particionamiento a través de los mismos consiste en una buena estrategia para dividir las
operaciones entre las unidades de cálculo o procesadores [3], [8], [9].
De acuerdo con lo anterior, esta investigación propone que los enlaces indicados en la
metodología de los Equivalentes de Thévenin Multi Área correspondan a líneas de
1. Hallar la solución a cada sistema sin
considerar enlaces utilizando (2-20).
2. Con matrices p y q, las tensiones halladas
en 1 y Zα se calculan las corrientes de los
enlaces utilizando (2-21) y (2-22)
3. Con las corrientes de
enlace, se recalculan las
tensiones de los subsistemas y se halla la solución
completa utilizando (2-23)
Equivalentes de Thévenin Multi Área (MATE) 19
transmisión. Enlaces que de acuerdo con la formulación anterior son elementos
concentrados, sin embargo, para solucionar transitorios electromagnéticos de manera
precisa se debe definir el modelo de la línea de transmisión a utilizar, el cual como se indica
en los capítulos siguientes será un modelo de línea con parámetros constantes distribuidos
[21], [22].
Ahora, hemos de preocuparnos por cómo se resolverá cada uno de los subsistemas y
cuáles serán los modelos equivalentes empleados para llegar a una solución rápida y
precisa de los procesos transitorios. Esto es presentado en el capítulo siguiente.
3. Regla trapezoidal de integración y Modelos Equivalentes de Dommel
Las maniobras, fallas, descargas atmosféricas y otras perturbaciones causan sobrevoltajes
o sobrecorrientes temporales en los sistemas eléctricos de potencia. El cálculo riguroso de
estos procesos transitorios resulta ser una tarea difícil debido a la complejidad de los
modelos de los equipos involucrados. Esto ocasiona además, que sea prácticamente
imposible obtener la solución de un proceso transitorio mediante un cálculo manual, incluso
en redes o sistemas bastante simples.[21], [23]
Varias técnicas han sido desarrolladas para simular procesos transitorios mediante
computadora. Estas se pueden dividir en dos categorías principalmente: técnicas en el
dominio de la frecuencia y técnicas en el dominio del tiempo. De los varios métodos
propuestos en el domino del tiempo, el más común es el algoritmo desarrollado por H. W.
Dommel, el cual dio origen al EMTP, la herramienta más empleada en el cálculo de
procesos transitorios.[21]
El método de Dommel permite resolver redes polifásicas con parámetros distribuidos y con
la presencia de elementos lineales y no-lineales. Esta técnica tiene como base la regla
trapezoidal de integración, la cual al ser aplicada a los modelos de los diferentes elementos
permite obtener circuitos equivalentes que facilitan la implementación de una metodología
de cálculo recursiva rápida y precisa.[23]
Con la aplicación de la regla trapezoidal se obtienen los siguientes circuitos equivalentes
de los componentes básicos de una red[21]:
22 Simulación de transitorios electromagnéticos mediante programación de GPUs
Tabla 3-1:Circuitos equivalentes de los componentes básicos de una red. A partir de [21]
Componente Representación
Temporal Circuito equivalente
Resistencia
Inductancia
Capacidad
Línea de
transmisión
ideal
Los anteriores circuitos equivalentes son representados por las siguientes expresiones:
Resistencia:
𝑢𝑘(𝑡) − 𝑢𝑚(𝑡) = 𝑢𝑘𝑚(𝑡) = 𝑅𝑖𝑘𝑚(𝑡) ( 3-1)
Inductancia:
𝑖𝑘𝑚(𝑡) =∆𝑡
2𝐿𝑢𝑘𝑚(𝑡) + 𝐼𝑘𝑚(𝑡)
( 3-2)
𝐼𝑘𝑚(𝑡) = [∆𝑡
2𝐿𝑢𝑘𝑚(𝑡 − ∆𝑡) + 𝑖𝑘𝑚(𝑡 − ∆𝑡)]
( 3-3)
23 Modelos equivalentes de Dommel 23
Capacidad:
𝑖𝑘𝑚(𝑡) =2𝐶
∆𝑡𝑢𝑘𝑚(𝑡) + 𝐼𝑘𝑚(𝑡)
( 3-4)
𝐼𝑘𝑚(𝑡) = − [2𝐶
∆𝑡𝑢𝑘𝑚(𝑡 − ∆𝑡) + 𝑖𝑘𝑚(𝑡 − ∆𝑡)]
( 3-5)
Línea de transmisión ideal:
𝐼𝑘(𝑡) = − [𝑣𝑚(𝑡 − 𝜏)
𝑍𝑐+ 𝑖𝑚𝑘(𝑡 − 𝜏)]
𝐼𝑚(𝑡) = − [𝑣𝑘(𝑡 − 𝜏)
𝑍𝑐+ 𝑖𝑘𝑚(𝑡 − 𝜏)]
( 3-6)
𝑖𝑘𝑚(𝑡) = 𝑢𝑘(𝑡)
𝑍𝑐+ 𝐼𝑘(𝑡)
𝑖𝑚𝑘(𝑡) = 𝑢𝑚(𝑡)
𝑍𝑐+ 𝐼𝑚(𝑡)
( 3-7)
𝜏 =𝑙
𝑣 ( 3-8)
Con:
𝑙:Longitud de la línea de transmisión.
𝑣: velocidad de propagación de ondas, 𝑣 = 300.000 𝑘𝑚/𝑠 .
Para comparar la estrategia de solución tradicional con aquella usando la metodología
MATE y la aplicación de los modelos equivalentes de Dommel, se programa en MATLAB
la solución al siguiente circuito tomado de [21]:
Figura 3-1. Diagrama unifilar sistema de estudio.
Con:
𝑒(𝑡) = 1 𝑉
𝑅0 = 10 Ω
𝑍𝐶 = 350 Ω
𝑣 = 300.000 𝑘𝑚/𝑠
𝐿 = 60 𝑘𝑚
𝐶 = 0.1𝜇𝐹
De acuerdo con los modelos equivalentes presentados en la Tabla 3-1, el circuito anterior
puede ser presentado de la siguiente manera:
Figura 3-2. Esquema equivalente para el cálculo de transitorios.
Aplicando el análisis nodal convencional al circuito de la Figura 3-2 se obtiene el siguiente
sistema de ecuaciones:
[ 1
𝑅0+
1
𝑍𝐶0
01
𝑍𝑐+
2𝐶
Δ𝑡]
[𝑢1(𝑡)
𝑢2(𝑡)] = [
𝑒(𝑡)
𝑅0− 𝐼1(𝑡)
−𝐼2(𝑡) − 𝐼𝐶(𝑡)
] ( 3-9)
De acuerdo con ( 3-6) y ( 3-7) se tiene:
𝐼1(𝑡) = − [𝑢2(𝑡 − 𝜏)
𝑍𝑐+ 𝑖21(𝑡 − 𝜏)] ( 3-10)
𝐼2(𝑡) = − [𝑢1(𝑡 − 𝜏)
𝑍𝑐+ 𝑖12(𝑡 − 𝜏)] ( 3-11)
𝐼𝐶(𝑡) = −[2𝐶
Δ𝑡 𝑢2(𝑡 − Δ𝑡) + 𝑖𝐶(𝑡 − Δ𝑡)] ( 3-12)
A su vez, del sistema original presentado en la Figura 3-1 se obtienen las siguientes
expresiones para las corrientes asociadas a la línea ideal y al capacitor:
𝑖12(𝑡) =1
𝑅0
[𝑒(𝑡) − 𝑢1(𝑡)] ( 3-13)
25 Modelos equivalentes de Dommel 25
𝑖21(𝑡) = −𝑖𝐶(𝑡) ( 3-14)
𝑖𝐶(𝑡) =2𝐶
Δ𝑡𝑢2(𝑡) − [
2𝐶
Δ𝑡𝑢2(𝑡 − Δ𝑡) + 𝑖𝐶(𝑡 − Δ𝑡)] ( 3-15)
Adicional a las ecuaciones anteriores se deben fijar las condiciones iniciales del sistema,
para ello se realizan las siguientes consideraciones:
El sistema de la Figura 3-1 se encuentra inicialmente relajado, por tanto:
𝐼1(0) = 𝐼2(0) = 𝐼𝐶(0) = 0
El interruptor se cierra en 𝑡 = Δ𝑡
Con las ecuaciones y consideraciones anteriores, el algoritmo de la Figura 3-3 es
programado en MATLAB teniendo como resultado el código del anexo 1.
26 Simulación de transitorios electromagnéticos mediante programación de GPUs
Figura 3-3. Diagrama de flujo algoritmo de solución de transitorios con equivalentes de Dommel. A partir de [21]
En resumen, en el código del anexo 1 desarrollado a partir del algoritmo de la Figura 3-3,
se realiza el siguiente procedimiento:
1. Se definen las características de los componentes del sistema: 𝑅0, E, 𝑍𝐶, 𝜏, 𝐶.
2. Se define un paso de tiempo Δ𝑡 = 𝜏/15.
27 Modelos equivalentes de Dommel 27
3. Se definen condiciones iniciales, el sistema se encuentra inicialmente relajado por
tanto todas las corrientes y voltajes en 𝑡 = 0 tienen un valor nulo.
4. Con las variables del paso 1 y de acuerdo con ( 3-9) se construye la siguiente
matriz:
[ 1
𝑅0+
1
𝑍𝐶0
01
𝑍𝑐+
2𝐶
Δ𝑡]
( 3-16)
5. Se invierte la matriz presentada en ( 3-16).
6. Si el paso de tiempo es inferior al paso de tiempo máximo de simulación, se realiza
el siguiente proceso iterativo:
6.1. Con las ecuaciones ( 3-10), ( 3-11) y ( 3-12) se hallan las corrientes 𝐼1, 𝐼2 e 𝐼𝐶.
En el caso de 𝐼1 e 𝐼2 se deben considerar dos escenarios: 𝑡 < 𝜏 y 𝑡 > 𝜏. En el
primer escenario 𝐼1 e 𝐼2 tendrán un valor de 0 A, en el segundo se calculan
con las ecuaciones mencionadas previamente.
6.2. Del paso anterior y con los parámetros del sistema se conoce el vector
presentado en el lado derecho del igual en la ecuación ( 3-9). Se multiplica
entonces la matriz inversa del paso 5 con el vector mencionado anteriormente
y se obtienen las tensiones 𝑢1(𝑡) y 𝑢2(𝑡).
6.3. Con los resultados de los pasos 6.2 y 6.3 se hallan las corrientes 𝑖12, 𝑖21 e 𝑖𝐶
con las ecuaciones ( 3-13), ( 3-14) y ( 3-15).
6.4. Se actualizan el parámetro de tiempo, 𝑡 = 𝑡 + Δ𝑡.
7. Se finaliza la ejecución y se presentan resultados.
Tras la ejecución de este algoritmo con Δ𝑡 = 13,33 𝜇𝑠 y un tiempo máximo de simulación
de 35 𝑚𝑠, se obtiene la forma de onda presentada en la Figura 3-4 en color azul, la cual
corresponde a la tensión al extremo de la línea, es decir medida en el nodo 2 del sistema
de la Figura 3-1. Para validar el procedimiento anterior, el sistema es simulado en ATP
Draw [24] obteniendo el resultado presentado en la Figura 3-4 en color rojo, nótese que
tanto el resultado del procedimiento programado como el de la simulación en ATP Draw
28 Simulación de transitorios electromagnéticos mediante programación de GPUs
tienen la misma forma de onda y presentan una diferencia máxima de 0.59%, lo cual
confirma lo correcto del procedimiento realizado.
Figura 3-4. Tensión al extremo de la línea – modelos equivalentes de Dommel.
De la Tabla 3-1 se tiene que todos los modelos equivalentes de Dommel para el cálculo
de transitorios electromagnéticos emplean elementos resistivos y fuentes de corriente,
elementos que son de fácil cálculo y evitan el uso de números complejos propiciando una
reducción del costo computacional de las operaciones.[3]
Nótese además que, con el uso del modelo equivalente de la línea de transmisión ideal,
se produce un efecto desacoplador ya que la línea es representada por dos circuitos
independientes, los cuales pueden ser asociados a subsistemas o enlaces diferentes. Lo
anterior puede ser aprovechado mediante la metodología MATE descrita en el Capítulo 2.
La combinación de los modelos equivalentes de Dommel y la metodología de
particionamiento de red MATE es presentada en el capítulo siguiente.
El circuito de la Figura 3-2 se podría resolver empleado la metodología de los equivalentes
de Thévenin Multi Área descrita en el capítulo 2 del presente documento. Para ello el
sistema eléctrico de potencia se puede dividir en dos subsistemas considerando a la línea
de transmisión como único enlace como se presenta en la figura Figura 3-5. Tras
realizarse esta división se seguiría el procedimiento de la figura Figura 2-2. Se tiene
29 Modelos equivalentes de Dommel 29
entonces que los modelos equivalentes obtenidos a partir de la aplicación de la regla
trapezoidal y la metodología de los Equivalentes de Thévenin Multi Área pueden
combinarse para calcular los transitorios electromagnéticos de sistemas eléctricos de
potencia. Esta combinación es presentada en el siguiente capítulo.
Figura 3-5. División sistema eléctrico Figura 3-2
4. Implementación de modelos equivalentes de Dommel y particionamiento de red MATE
El objeto de la presente investigación es proponer una metodología para la simulación de
transitorios electromagnéticos en sistemas eléctricos de potencia usando unidades de
procesamiento gráfico (GPUs). La programación en GPUs se fundamenta en la
paralelización del problema, en consecuencia, resulta indispensable la aplicación de un
esquema que permita calcular los transitorios electromagnéticos de un sistema de gran
tamaño dividiendo el mismo en subsistemas, los cuales permitan abordar el problema por
partes para luego consolidar los resultados del sistema completo. Este esquema
corresponde a la combinación de la metodología del equivalente de Thévenin Multi área
descrita en el Capítulo 2, junto con el uso de los modelos equivalentes de Dommel para el
cálculo de transitorios presentados en el capítulo 3. Con el propósito de presentar esta
metodología se parte de un sistema ejemplo.
El sistema objeto de estudio esta dado por dos subsistemas A y B conectados por una
línea de transmisión de longitud conocida y de impedancia característica Zc, tal como se
muestra en la Figura 4-1.
32 Simulación de transitorios electromagnéticos mediante programación de GPUs
Figura 4-1. Topología sistema de estudio, combinación MATE y Dommel
Este sistema cuenta con los siguientes elementos:
𝑰𝑟𝑎𝑚𝑝: fuente de corriente tipo rampa de amplitud máxima 1000 A y tiempo de subida 2 ms,
luego de este tiempo el valor de la fuente será 0 A. La forma de onda de la fuente de
corriente es presentada en la Figura 4-2.
Figura 4-2. Fuente de corriente tipo rampa sistema de estudio.
Además, el resto de los parámetros está dado por:
𝑅𝐴12= 20 Ω
𝑅𝐴23= 10 Ω
𝑅𝐴34= 2,5 Ω
𝑅𝐴14= 5 Ω
Implementación Dommel y MATE 33
𝑅𝐴4= 2 Ω
𝑅𝐵12= 7 Ω
𝑅𝐵23= 5 Ω
𝑅𝐵34= 2 Ω
𝑅𝐵14= 10 Ω
𝑅𝐵4= 8 Ω
𝑍𝑐: 200 Ω , Impedancia característica línea de transmisión de 60 km.
Para definir las condiciones iniciales del sistema, se considera que este se encuentra
desenergizado en t=0 s, es decir todas las corrientes y tensiones tienen un valor nulo.
Es posible observar que el sistema de la Figura 4-1 puede dividirse en dos subsistemas A
y B, unidos por la línea transmisión de impedancia característica Zc. De acuerdo con la
Tabla 3-1 la Figura 4-3 muestra el equivalente del circuito bajo estudio representado en
sus equivalentes circuitales de Dommel.
En la Figura 4-3 se evidencia el efecto desacoplador del modelo equivalente de línea de
transmisión ideal, debido al cual no se tiene un enlace directo de elementos concentrados
entre los sistemas A y B, sino que el modelo de línea permite considerar dos impedancias
y dos corrientes de inyección independientes.
Figura 4-3. Circuito equivalente a partir de modelos equivalentes de Dommel
En primera instancia se hallan las matrices de admitancias de cada uno de los
subsistemas:
34 Simulación de transitorios electromagnéticos mediante programación de GPUs
𝐴 = [
0.25 −0.05 0 −0.20−0.05 0.15 −0.10 0
0 −0.10 0.50 −0.40−0.20 0 −0.40 1.10
] ( 4-1)
𝐵 = [
0.24 −0.14 0 −0.10−0.14 0.34 −0.20 0
0 −0.20 0.70 −0.50−0.10 0 −0.50 0.73
]
( 4-2)
Posterior a ello, se define la matriz de enlace Z:
𝑍 = [𝑍𝛼1 00 𝑍𝛼2
]
( 4-3)
En la Figura 4-3 es posible identificar que, mediante la aplicación de los modelos
equivalentes obtenidos a partir de la aplicación de la regla trapezoidal, la línea de
transmisión es representada como dos circuitos independientes mostrados en la Figura
4-4
Figura 4-4. Circuitos equivalentes línea de transmisión del sistema de prueba
Estos circuitos independientes dan cabida a que en la metodología MATE descrita en el
capítulo 2 una línea de transmisión pueda considerarse como dos enlaces independientes
de impedancias iguales a la impedancia característica de la línea:
𝑍𝛼1 = 𝑍𝛼2 = 𝑍𝑐 ( 4-4)
Implementación Dommel y MATE 35
En consecuencia y como se muestra en las siguientes expresiones, las fuentes de corriente
I1 e I2 de los circuitos equivalentes de la línea de transmisión serán consideradas como
corrientes de inyección de los respectivos subsistemas en los nodos en los cuales se
encuentra conectado cada extremo de la línea.
Por tanto, se definen las siguientes corrientes de inyección para cada subsistema:
𝐼𝐴 = [
𝐼𝑟𝑎𝑚𝑝(𝑡)
0−𝐼1(𝑡)
0
]
( 4-5)
𝐼𝐵 = [
−𝐼2(𝑡)000
]
( 4-6)
A continuación, se determinan las matrices de inyección p y q asociadas a la conexión de
los enlaces, nótese que ambas matrices tienen dos columnas, las cuales corresponden a
cada uno de los enlaces resultantes de la división de la línea de transmisión de acuerdo
con los circuitos equivalentes presentados en la
Figura 4-4. Circuitos equivalentes línea de transmisión del sistema de prueba:
𝑝 = [
0 00 0
+1 00 0
] , 𝑞 = [0 −10 00 0
]
( 4-7)
Se ha de tener en cuenta que 𝐼1(𝑡) e 𝐼2(𝑡) corresponden a las fuentes de corriente del
equivalente de la línea de transmisión mostrado en la Tabla 3-1. Estas corrientes según el
equivalente Dommel, obedecen a las siguientes expresiones:
𝐼1(𝑡) = − [𝑉𝐵1(𝑡 − 𝜏)
𝑍𝑐+ 𝑖1𝐵−3𝐴(𝑡 − 𝜏)]
( 4-8)
𝐼2(𝑡) = − [𝑉𝐴3(𝑡 − 𝜏)
𝑍𝑐+ 𝑖3𝐴−1𝐵(𝑡 − 𝜏)] ( 4-9)
36 Simulación de transitorios electromagnéticos mediante programación de GPUs
Donde:
𝑉𝐵1: Tensión del nodo 1 del sistema B [V].
𝑉𝐴3: Tensión del nodo 3 del sistema A [V].
𝜏: Tiempo de propagación de ondas entre ambos extremos de la línea.
𝜏 =𝑙
𝑣 [𝑠]
( 4-10)
𝑙:longitud de la línea de transmisión, 60 km.
𝑣:velocidad de propagación de la onda, 300.000 km/s. Además,
𝑖12(𝑡) =𝑉𝐴3(𝑡)
𝑍𝑐+ 𝐼1(𝑡)
( 4-11)
𝑖21(𝑡) =𝑉𝐵1(𝑡)
𝑍𝑐+ 𝐼2(𝑡) ( 4-12)
Se destaca que en la solución de la red y considerando el tiempo de propagación de las
ondas en la línea de transmisión, se deben evaluar principalmente dos condiciones: 𝑡 < 𝜏
y 𝑡 ≥ 𝜏.
Con las ecuaciones anteriores, se sigue el proceso de solución de la Figura 4-5 a través
del código generado en MATLAB y presentado en el anexo 2.
Implementación Dommel y MATE 37
Figura 4-5. Diagrama de flujo del algoritmo de solución de transitorios con modelos
equivalentes de Dommel y MATE. A partir de [8], [21].
38 Simulación de transitorios electromagnéticos mediante programación de GPUs
En resumen, este proceso considera las siguientes operaciones:
1. Se definen los parámetros del sistema, las condiciones iniciales, el tiempo máximo
de cálculo y se inicializan los contadores y el parámetro de tiempo.
2. Siempre que el tiempo t sea menor que el tiempo máximo de cálculo se realizan las
siguientes operaciones:
2.1. Se evalúan las corrientes de las líneas de transmisión empleando los
modelos equivalentes obtenidos a partir del uso de la regla trapezoidal, para
ello se consideran dos condiciones:
Si el tiempo t es menor que el tiempo de propagación de las ondas en la
línea de transmisión, las corrientes de la línea 𝐼1(𝑡) e 𝐼2(𝑡) serán 0 A.
Si el tiempo t es mayor o igual que el tiempo de propagación de las ondas
en la línea de transmisión, las corrientes de la línea 𝐼1(𝑡) e 𝐼2(𝑡) deberán
calcularse haciendo uso de las ecuaciones ( 4-8) y ( 4-9).
2.2. Con las corrientes de las líneas calculadas anteriormente se establecen los
vectores de corrientes de inyección de cada subsistema.
2.3. Con las corrientes de inyección y los parámetros de los subsistemas se
sigue la metodología de los equivalentes de Thévenin Multi Área presentada
en el capítulo 2 de la presente investigación para hallar las tensiones y
corrientes de los subsistemas.
2.4. Con las tensiones de los subsistemas se hallan las corrientes 𝑖12(𝑡) e
𝑖21(𝑡) haciendo uso de las ecuaciones ( 4-11) y ( 4-12).
2.5. Se actualiza parámetro de tiempo, 𝑡 = 𝑡 + ∆𝑡.
3. Se repite el proceso del numeral anterior hasta que se alcance el tiempo máximo
de cálculo, cuando esto suceda se detiene el proceso de cálculo y se presentan
resultados.
Tras la ejecución del algoritmo con ∆𝑡 = 20 𝜇𝑠 y un tiempo máximo de simulación de 35 𝑚𝑠,
se obtienen las formas de onda presentadas en la Figura 4-6 en azul y en la Figura 4-7
en azul, las cuales son validadas mediante el uso de ATPDraw obteniendo las curvas
presentadas en rojo en las anteriores figuras.
Implementación Dommel y MATE 39
Figura 4-6. Voltaje vs tiempo Nodo 3 del sistema A.
Figura 4-7. Voltaje vs tiempo nodo 1 del sistema B.
En la Figura 4-6 y en la Figura 4-7 se identifica que tanto la solución programada como la
hallada con ATPDraw siguen la misma forma de onda y son aproximadamente iguales,
adicionalmente se tiene que el porcentaje de error obtenido como una comparación entre
sus valores máximos corresponde al 0.94% y 1.49% respectivamente.
Del ejemplo anterior se destaca que, en el caso de las líneas de transmisión, el valor de la
fuente de corriente asociada al equivalente Dommel de la línea puede ser incluida en la
metodología MATE como una corriente inyectada al subsistema correspondiente. Se
40 Simulación de transitorios electromagnéticos mediante programación de GPUs
resalta además, que con el equivalente de Dommel de la línea de transmisión, esta puede
ser dividida en dos enlaces de igual impedancia característica Zc lo que facilita la aplicación
del equivalente de Thévenin Multi área.
El proceso de solución presentado en la Figura 4-5 puede ser extrapolado a sistemas
eléctricos de potencia de mayor tamaño que el sistema de la Figura 4-1. Para ello bastará
con dividir el sistema eléctrico en subsistemas a través de la definición las líneas de
transmisión como enlaces, estos subsistemas deberán resolverse utilizando los modelos
equivalentes de Dommel y sus expresiones.
En la aplicación de esta metodología a sistemas de gran tamaño se identifica una gran
oportunidad de paralelizar el proceso de solución, paralelización que será lograda a través
del uso de unidades de procesamiento gráfico (GPU) tal como se presenta en los capítulos
5 y 6.
5. CUDA y programación de unidades de procesamiento gráfico
En aplicaciones adecuadas para la paralelización del proceso de solución, las unidades de
procesamiento gráfico (GPU) pueden ofrecer resultados más rápidos en comparación con
las unidades centrales de procesamiento (CPU). Esto es debido principalmente a que las
GPU cuentan con un mayor número de núcleos y su memoria RAM tiene un mayor ancho
de banda que la memoria RAM usada por las CPU. Pese a ello, las GPU no pueden ser
utilizadas por sí solas y requieren que su uso se de en combinación con las CPU, ya que
son estas últimas las encargadas de realizar el preprocesamiento, la gestión de memorias
y de indicar cuando y para que parámetros se deben ejecutar las funciones definidas en la
GPU. [19], [25]
Las funciones que se ejecutan en la GPU se denominan Kernels (“Núcleos” en español).
Estos Kernels se ejecutan de forma paralela dentro de la GPU sobre un conjunto de hilos
llamados threads, los cuales como se muestra en la Figura 5-1 son organizados en una
jerarquía en la que se agrupan en bloques (“blocks”) los que a su vez se pueden distribuir
formando una malla o grid [19], [25].
La cantidad de hilos y los bloques que conforman la malla es especificada por el
programador al invocar un Núcleo. Una vez en la GPU y como se muestra en la Figura
5-1, se asigna a cada hilo y a cada bloque un único número de identificación dentro de la
malla, el cual es usado para indicar a cada hilo cuales son los datos con los que tiene que
trabajar, lo que facilita el direccionamiento de memoria y evita realizar las mismas
operaciones sobre los mismos datos.
42 Simulación de transitorios electromagnéticos mediante programación de GPUs
Figura 5-1. Jerarquía de hilos CUDA. A partir de [26]
En la Figura 5-2 se presenta un esquema general de un programa en la GPU. En este
esquema se destaca que el preprocesamiento que comprende la definición de variables,
la definición de Núcleos y de los parámetros sobre los cuales se ejecutarán los Núcleos,
se ejecutan en la CPU. De igual manera se identifica que debido a que la GPU y la CPU
tienen espacios de memoria diferentes se presentan copias de memoria de la CPU a la
GPU y viceversa.[25]
Figura 5-2. Esquema general de un programa en CUDA.
CUDA y programación de GPUs 43
Para la programación de transitorios en la GPU, esta investigación utiliza el lenguaje
CUDA, el cual corresponde a una extensión de C/C++ para permitir la programación de
tarjetas gráficas fabricadas por NVIDIA [19]. Para la programación se consideran los
siguientes criterios de mejoramiento de la ejecución[25]:
1. Reducir al máximo las operaciones de copia de memoria entre la GPU y la CPU.
2. Considerado que la ejecución de los Núcleos tiene un costo inicial asociado, si la
aplicación no es lo suficientemente grande puede resultar más conveniente
ejecutarla completamente en la CPU. Es decir, la mejora en desempeño de la
programación en la GPU radica en el uso de muchos hilos.
3. Para facilitar los accesos de memoria se recomienda que la cantidad seleccionada
de hilos sea mucho mayor que la cantidad de bloques empleados.
4. Se aprovechará el máximo ancho de banda de la GPU cuando se accede a la
memoria de esta de una manera organizada y secuencial. Esto es llamado “memory
coalescing” y se logra asignando a hilos subsecuentes datos de memoria
subsecuentes [19], [25], [27]. Por ejemplo, considere el siguiente programa:
Figura 5-3. Código ejemplo con lectura de memoria no consecutiva. A partir de [25].
Donde:
blockIdx.x: identificador único de cada bloque de la malla asignada a la
ejecución del Núcleo.
threadIdx.x: identificador único de cada hilo de la malla asignada a la
ejecución del Núcleo.
Output: matriz resultado de la ejecución del programa.
Input: matriz de entrada del programa.
En el código de la Figura 5-3, cuando j=1, el hilo 0 del bloque 0 definirá un valor de
i=0 y en consecuencia, para generar la matriz output deberá consultar el espacio
i = blockIdx.x*blockDim.x + threadIdx.x;
for (j=0; j<N; j++)
output [i] [j] =2 * input [i] [j] ;
44 Simulación de transitorios electromagnéticos mediante programación de GPUs
de memoria correspondiente a input en la posición (0, j=1); el hilo siguiente, es decir
el hilo 1 del bloque 0 definirá un valor de i=1 y consultará el espacio de memoria
correspondiente a input en la posición (1, j=1). Observe entonces que en el código
de la figura Figura 5-3 hilos subsecuentes no consultan espacios de memorias
subsecuentes ya que hay un salto de fila en la matriz input cuando se avanza al
hilo siguiente. Ahora considere el código de la Figura 5-4:
Figura 5-4. Código ejemplo con lectura de memoria consecutiva. A partir de [25]
Observe que cuando i=1, el hilo 0 del bloque 0 definirá un valor de j=0 y leerá el
espacio de memoria correspondiente a input en la posición (i=1, 0); el hilo siguiente,
es decir el hilo 1 del bloque 0 definirá un valor de j=1 y consultará el espacio de
memoria correspondiente a input en la posición (i=1, 1). Nótese que en el código
de la Figura 5-4 hilos subsecuentes sí consultan espacios de memorias
subsecuentes ya que se cambia a la columna siguiente en la matriz input cuando
se avanza al hilo siguiente. Por tanto, se puede afirmar que la lectura de memoria
es secuencial y el resultado práctico se ve reflejado en que se aprovecha a mayor
medida el ancho de banda de la GPU en el código de la Figura 5-4 que en el código
de la Figura 5-3.
En la solución de transitorios de sistemas eléctricos de potencia en las GPU, es común un
enfoque híbrido CPU-GPU, donde las partes del problema que no pueden ser paralelizadas
son ejecutadas en la CPU y aquellas que pueden ejecutarse en paralelo se resuelven en
la GPU asumiendo el costo computacional de la transferencia de memoria entre la GPU y
la CPU [2], [5], [8]. En ese sentido en el proceso de la Figura 4-5, el cálculo de las
corrientes de las líneas es realizado en la CPU, las tensiones de los subsistemas son
halladas con la metodología MATE en la GPU y luego son transferidas a la CPU para ser
utilizadas en el cálculo de los valores históricos de las corrientes de línea de acuerdo con
los modelos equivalentes de Dommel. A este enfoque se le llamará Metodología “CPU-
GPU-1”
j = blockIdx.x*blockDim.x + threadIdx.x;
for (i=0; i<N; i++)
output[i][j] =2*input[i][j];
CUDA y programación de GPUs 45
El enfoque descrito anteriormente se pone a prueba en la solución del sistema de la Figura
5-5 y es comparado con otras dos metodologías: una metodología en la cual se
implementan algunas herramientas de programación con el propósito de incrementar el
nivel de paralelismo del proceso de solución; a este enfoque se le llamará metodología
“CPU-GPU-2” y una metodología GPU completa en la cual todas las operaciones son
realizadas en la GPU a excepción del preprocesamiento y muestra final de resultados; a
esta se le llamará metodología “GPU-O”.
Figura 5-5. Sistema de prueba para programación en CUDA
El Sistema de prueba cuenta con los siguientes elementos:
𝑰𝑟𝑎𝑚𝑝: fuente de corriente tipo rampa de amplitud máxima 1000 A y tiempo de subida
100Δ𝑡, luego de este tiempo el valor de la fuente será 0 A tal como en la Figura 4-2. El
resto de los parámetros están dados por:
Δ𝑡 =1
10∗ (𝜏𝑙í𝑛𝑒𝑎 𝑚á𝑠 𝑐𝑜𝑟𝑡𝑎)
𝑅𝐴12= 20 Ω
𝑅𝐴23= 10 Ω
𝑅𝐴34= 2,5 Ω
𝑅𝐴14= 5 Ω
𝑅𝐴4= 2 Ω
𝑅𝐵12= 7 Ω
𝑅𝐵23= 5 Ω
𝑅𝐵34= 2 Ω
𝑅𝐵14= 10 Ω
𝑅𝐵4= 8 Ω
𝑅𝐶12= 4 Ω
𝑅𝐶23= 8 Ω
𝑅𝐶34= 9 Ω
𝑅𝐶14= 20 Ω
𝑅𝐶4= 5 Ω
Línea 1 de longitud 60 km y 𝑍𝑐𝑙í𝑛𝑒𝑎 1 = 200 Ω
Línea 2 de longitud 40 km y 𝑍𝑐𝑙í𝑛𝑒𝑎 2 = 150 Ω
Línea 3 de longitud 20 km y 𝑍𝑐𝑙í𝑛𝑒𝑎 3 = 180 Ω
5.1 Metodología CPU-GPU-1
En la Figura 5-6 que corresponde al procedimiento de la metodología CPU-GPU-1, se
resaltan en azul los procedimientos llevados a cabo en la CPU y en verde los realizados
en la GPU. Esta metodología es comúnmente usada en la literatura académica; en ella se
implementa la metodología del equivalente de Thévenin Multi Área en la GPU y el resto de
las operaciones son ejecutadas en la CPU. En consecuencia, en cada iteración se presenta
una operación de transferencia de memoria entre la CPU y la GPU y viceversa. El código
en CUDA asociado a la metodología base se presenta en el anexo 3.
CUDA y programación de GPUs 47
Figura 5-6. Algoritmo de solución – Metodología CPU-GPU-1 y metodología CPU-GPU-2 de solución de transitorios en la GPU. Acciones en azul son ejecutadas en la CPU,
acciones en verde en la GPU
48 Simulación de transitorios electromagnéticos mediante programación de GPUs
En resumen, el código presenta la siguiente secuencia de operaciones:
1. Definición de funciones (Núcleos) que se ejecutarán en la GPU.
2. Definición de variables, lectura de matrices inversas y parámetros del sistema. En
este punto se aclara que con el propósito de evitar el cálculo de la inversa dentro
del programa, se decide realizar esta operación previamente en MATLAB como
parte de preprocesamiento y llevarlas a través de un archivo de texto a CUDA.
3. Gestión de memorias. Se asigna espacio en la GPU a las variables que lo requieran
a través de la instrucción CUDA: cudaMalloc.
4. Copia de memoria de la CPU a la GPU de variables que se utilizarán durante la
simulación en la GPU por lo que únicamente se requiere una operación de
transferencia de memoria inicial. Ejemplo: las matrices inversas de los sistemas y
la matriz inversa 𝑍𝛼.
5. Inicio ciclo iterativo hasta cumplirse el tiempo máximo de simulación.
5.1 Cálculo en la CPU de las corrientes de las líneas de acuerdo con el modelo
equivalente de Dommel descrito en el capítulo 3.
5.2 Asignación de las corrientes de inyección de cada subsistema.
5.3 Copia de las corrientes de inyección de cada subsistema de la CPU a la GPU.
5.4 Ejecución en la GPU de la Metodología MATE descrita en el capítulo 2.
5.5 Copia de las tensiones nodales de la GPU a la CPU.
5.6 Actualización en la CPU de las corrientes históricas asociadas al modelo de
la línea.
5.7 Actualización de tiempo t, 𝑡 = 𝑡 + Δ𝑡.
6. Terminar ejecución y presentar resultados.
Al ejecutar el algoritmo de solución de transitorios electromagnéticos para el sistema de la
figura Figura 5-5 siguiendo la metodología CPU-GPU-1 descrita en esta sección con
Δ𝑡 = 6,66 𝜇𝑠 y un tiempo máximo de simulación de 35 𝑚𝑠, se obtiene un tiempo de cálculo
promedio en 10 ejecuciones de 2,51 segundos. El algoritmo de solución es presentado en
el anexo 3.
CUDA y programación de GPUs 49
5.2 Metodología base con mayor paralelismo CPU-GPU-2
El procedimiento de la metodología base con mayor paralelismo CPU-GPU-2 es el mismo
de la metodología CPU-GPU-1 presentada en la Figura 5-6. A diferencia de la metodología
CPU-GPU-1, en esta metodología se implementan las siguientes herramientas que brinda
CUDA para incrementar el paralelismo de la aplicación:
Streams: un stream corresponde a una organización de los hilos en un mismo flujo
o conjunto para permitir concurrencia entre los núcleos. En las operaciones en el
mismo stream se establece el esquema “primeras en entrar primeras en salir” y no
pueden ocurrir simultáneamente; operaciones con streams diferentes asignados no
tienen un orden definido y pueden ocurrir simultáneamente [28]. En el caso del
sistema de la Figura 5-5 se asigna un stream por cada subsistema.
Copia de memoria asíncrona: la instrucción cudamemcpyAsync permite la
transferencia de memoria entre la CPU y la GPU y viceversa de manera asíncrona
según el stream asignado a la operación de copia de memoria. En ese sentido, si
varias operaciones de transferencia de memoria son asignadas al mismo stream
estas serán ejecutadas en el orden del código y no podrá existir concurrencia en
las mismas; en caso contrario, si operaciones de transferencia de memoria se
asignan a diferentes streams, estas operaciones no tendrán un orden y podrán
ejecutarse simultáneamente. Con esta instrucción la copia de memoria se realiza
de manera independiente para cada uno de los subsistemas.
La aplicación de las anteriores herramientas es presentada en el anexo 4. Con la aplicación
de estas con Δ𝑡 = 6,66 𝜇𝑠 y un tiempo máximo de simulación de 35 𝑚𝑠, se obtiene un
tiempo de cálculo promedio en 10 ejecuciones de 1,67 segundos.
5.3 Metodología GPU completa GPU-O
En las metodologías anteriores CPU-GPU-1 y 2 se tiene un alto costo computacional de la
transferencia de memoria entre la CPU y la GPU presentada en cada iteración del proceso
de solución. Como consecuencia de lo anterior se propone el esquema de solución
presentado en la Figura 5-7, en el cual se resaltan en azul las operaciones realizadas en
la CPU y en verde las llevadas a cabo por la GPU. En la metodología GPU-O se utilizan
50 Simulación de transitorios electromagnéticos mediante programación de GPUs
también las herramientas de paralelización presentadas en el numeral 5.2. El código en
CUDA asociado a la metodología GPU-O se presenta en el anexo 5
Figura 5-7. Algoritmo de solución – Metodología GPU-O para solución de transitorios en la GPU. Acciones en azul son ejecutadas en la CPU, acciones en verde en la GPU
En resumen, el código propuesto presenta la siguiente secuencia de operaciones:
1. Definición de funciones (Núcleos) que se ejecutaran en la GPU. Considerando que
en esta metodología todo el proceso de solución será ejecutado en la GPU, se
CUDA y programación de GPUs 51
definen muchos más Núcleos que los empleados en la metodología de la
sección 5.1
2. Definición de variables, lectura de matrices inversas y parámetros del sistema.
3. Gestión de memorias. Se asigna espacio en la GPU a las variables que lo requieran
a través de la instrucción cudaMalloc.
4. Copia de memoria de la CPU a la GPU, se copian a la GPU todas las variables que
se utilizarán en el cálculo
5. Inicio ciclo iterativo hasta cumplirse el tiempo máximo de simulación.
5.1 Cálculo en la GPU de las corrientes de las líneas de acuerdo con el modelo
equivalente de Dommel descrito en el capítulo 3.
5.2 Asignación en la GPU de las corrientes de inyección de cada subsistema.
5.3 Ejecución en la GPU de la Metodología MATE descrita en el capítulo 2.
5.4 Actualización en la GPU de las corrientes históricas asociadas al modelo de
la línea.
5.5 Actualización de tiempo t, 𝑡 = 𝑡 + Δ𝑡.
6. Terminar ejecución, copiar resultados a la CPU y presentarlos
La principal diferencia entre esta metodología y las anteriores CPU-GPU-1 y 2, es que esta
ejecuta muchas más funciones en la GPU sin importar que se trate de funciones serie o
no paralelas. Lo anterior con el propósito de evitar operaciones de transferencia de
memoria en el ciclo iterativo y el alto costo que esto representa.
Al ejecutar el anterior algoritmo de solución de transitorios electromagnéticos para el
sistema de la figura Figura 5-5 con Δ𝑡 = 6,66 𝜇𝑠 y un tiempo máximo de simulación de
35 𝑚𝑠, se obtiene un tiempo de cálculo promedio en 10 ejecuciones de 1,37 segundos.
En resumen, al comparar las metodologías CPU-GPU-1, CPU-GPU-2 y GPU-O, se obtienen
los siguientes tiempos:
52 Simulación de transitorios electromagnéticos mediante programación de GPUs
Tabla 5-1: Comparación tiempos de ejecución metodologías.
Metodología
Metodología CPU-GPU-1
Metodología CPU-GPU-2
Metodología GPU-O
Tiempo de cálculo (s) 2.51 1.67 1.37
Porcentaje de reducción (%)1 0% 34% 45%
Los tiempos reportados en la Tabla 5-1 consideran únicamente el tiempo de cálculo y no
tienen en cuenta el tiempo de preprocesamiento. Los valores presentados corresponden
al tiempo de cálculo promedio de 10 ejecuciones.
Con la aplicación de las tres metodologías descritas en el presente capítulo sobre el
sistema de la Figura 5-5 se obtienen las mismas formas de onda, las cuales como se
muestra en la Figura 5-8, Figura 5-9 y Figura 5-10 son validadas mediante el uso de
ATP/EMTP. En la Figura 5-10 se presentan unas pequeñas diferencias entre la forma de
onda de las metodologías calculadas en CUDA y la simulada en ATP/EMTP. Esta
diferencia se debe a la transferencia de matrices entre MATLAB y CUDA, en la cual se
pierden algunas cifras significativas. Si se incrementan las cifras significativas de los
componentes de las matrices que son transferidos de MATLAB a CUDA y viceversa, los
resultados de los cálculos transitorios y de la simulación en ATP serán aproximadamente
iguales.
1 Los porcentajes de reducción presentados son calculados tomando como base el tiempo de
ejecución de la metodología base señalada en el numeral 5.1.
CUDA y programación de GPUs 53
Figura 5-8. Voltaje vs Tiempo Nodo 2 subsistema A
Figura 5-9. Voltaje vs Tiempo Nodo 3 subsistema B
54 Simulación de transitorios electromagnéticos mediante programación de GPUs
Figura 5-10. Voltaje vs Tiempo Nodo 2 subsistema C
Se obtiene entonces como resultado de la presente investigación, que la metodología
propuesta GPU-O la cual es indicada en la Figura 5-7, representa una significativa
reducción del 45% en el tiempo de ejecución en comparación con la metodología
comúnmente propuesta por la literatura académica.
De acuerdo con lo descrito en el presente capítulo, hasta ahora los sistemas objeto de
estudio han contado con un máximo de tres subsistemas, es por ello que en el próximo
capítulo se define un algoritmo para la creación aleatoria de múltiples sistemas y se efectúa
una comparación del desempeño GPU vs CPU en la solución de transitorios
electromagnéticos de sistemas eléctricos de potencia de gran tamaño.
6. Simulación a gran escala de transitorios electromagnéticos
En este capítulo se realiza una comparación del desempeño en la solución de transitorios
electromagnéticos del uso de unidades de procesamiento gráfico (GPU) versus el uso de
unidades de procesamiento central (CPU). En ambos escenarios se realiza un
particionamiento de la red a través de los equivalentes de Thévenin Multi Área y se
solucionan los transitorios electromagnéticos empleando los modelos equivalentes de
Dommel. En el caso de la solución en la CPU se emplea un programa generado en
MATLAB descrito en el anexo 6 y para la solución en la GPU se utiliza la metodología
“GPU-O” descrita en el capítulo anterior, para ello se desarrolla en CUDA el código
presentado en el anexo 7. Estos programas son utilizados en sistemas de tamaño y
topología variable los cuales son creados aleatoriamente como se describe a continuación.
6.1 Generación aleatoria de sistemas eléctricos de potencia
Para la creación aleatoria de sistemas eléctricos de potencia de prueba con topologías y
tamaños variables se definen las siguientes consideraciones:
6.1.1 Subsistemas empleados
Se utilizarán dos tipos de subsistemas, el subsistema tipo A para el primer subsistema y
subsistema tipo B para el resto de los subsistemas. Estos tendrán las siguientes
características:
Subsistema tipo A: mostrado en la Figura 6-1 es un sistema de cuatro nodos
conformado por elementos resistivos de las siguientes características:
𝑅𝐴12= 20 Ω 𝑅𝐴23
= 10 Ω
56 Simulación de transitorios electromagnéticos mediante programación de GPUs
𝑅𝐴34= 2,5 Ω
𝑅𝐴14= 5 Ω
𝑅𝐴4= 2 Ω
Figura 6-1. Subsistema tipo A
Subsistema tipo B: mostrado en la Figura 6-2 es un sistema de cuatro nodos
conformado por elementos resistivos de las siguientes características:
𝑅𝐵12= 7 Ω
𝑅𝐵23= 5 Ω
𝑅𝐵34= 2 Ω
𝑅𝐵14= 10 Ω
𝑅𝐵4= 8 Ω
Figura 6-2. Subsistema tipo B
Simulación a gran escala de transitorios electromagnéticos 57
6.1.2 Línea de transmisión empleada
Para facilitar la creación de sistemas aleatorios de topologías y tamaños variados, se
empleará únicamente un tipo de línea, la cual tendrá una longitud de 60 km y una
impedancia característica Zc de 200 Ω. Se utilizará igual cantidad de líneas y de
subsistemas.
6.1.3 Fuente de corriente tipo rampa
Para excitar el sistema creado aleatoriamente se define la utilización de una fuente tipo
rampa de amplitud máxima 10.000 A y tiempo de subida 100Δ𝑡, luego de este tiempo el
valor de la fuente será 0 A. Esta fuente se conectará al primer nodo del primer subsistema
que se encuentre disponible luego de asignadas las conexiones de las líneas con la
metodología presentada a continuación.
6.1.4 Conexión de los subsistemas
De acuerdo con la metodología MATE descrita en el capítulo 2, la forma en que los
subsistemas están interconectados se encuentra descrita por las matrices de conectividad
p asociadas a cada subsistema. Considerando el efecto desacoplador del modelo
equivalente de Dommel para las líneas de transmisión, se tiene que cada línea es dividida
en dos enlaces y en consecuencia para cada subsistema la matriz de conectividad p será
una matriz de orden 𝑁 × (𝐿 × 2), siendo N el número de nodos de cada subsistema y L el
número total de líneas del sistema eléctrico de potencia.
En esta matriz p las columnas impares se refieren a la salida de la línea y las columnas
impares a la llegada; cuando la línea sale se asigna un +1 en el nodo correspondiente y
cuando la línea llega se asigna un -1 en el nodo de llegada. Se definen entonces los
siguientes algoritmos para establecer conexión entre los subsistemas.
Algoritmo de definición subsistema de salida de la línea: el algoritmo
presentado en la Figura 6-3 establece como condición que cada subsistema
sea como mínimo el punto de salida de una línea. En ese sentido recorre
secuencialmente los subsistemas seleccionando aleatoriamente el nodo de
58 Simulación de transitorios electromagnéticos mediante programación de GPUs
partida con la restricción de que a un mismo nodo no puede salir o llegar más
de una línea.
En este algoritmo se realiza el siguiente procedimiento:
1. Se asigna un contador i para recorrer todas las líneas. Debido a la
condición de que cada subsistema sea como mínimo el punto de salida
de una línea de transmisión, se define el contador c que servirá para
recorrer todos los subsistemas y como cada línea representa una
columna de las matrices de conectividad p, se define contador h para
recorrer las columnas de p.
2. Se genera aleatoriamente un nodo de conexión; si este nodo se
encuentra disponible se asigna un +1, lo cual indica que en el nodo k
del subsistema c sale la línea i. En caso tal que el primer nodo generado
aleatoriamente no se encuentre disponible, es decir ya tenga una
conexión, se generará aleatoriamente otro nuevo hasta encontrar uno
disponible.
3. Se actualizan contadores i, c y h. Para c se tiene en cuenta que este
recorre M subsistemas. En caso de que sean más enlaces que
subsistemas, se recorrerán los subsistemas de manera cíclica
asignando salidas de línea en los nodos disponibles. El contador h crece
de dos en dos ya que las columnas impares de la matriz de conectividad
p son las que hacen alusión a los nodos de partida de las líneas de
transmisión.
4. Una vez se hayan asignado los nodos y subsistemas de todas las líneas
de transmisión se finaliza la ejecución.
Simulación a gran escala de transitorios electromagnéticos 59
Figura 6-3. Algoritmo para definición del subsistema del cual sale cada línea
60 Simulación de transitorios electromagnéticos mediante programación de GPUs
Algoritmo de definición subsistema de llegada de la línea: el algoritmo
presentado en la Figura 6-4 establece como restricciones que ninguna línea
podrá salir y llegar al mismo sistema, y que de un mismo nodo no puede salir o
llegar más de una línea.
En este algoritmo se realiza el siguiente procedimiento:
1. Se asigna un contador i para recorrer todas las líneas. Aleatoriamente
se preselecciona un subsistema c y como cada línea representa una
columna de las matrices de conectividad p, se define contador h para
recorrer las columnas de p.
2. Se genera aleatoriamente un nodo de conexión y se verifica que el
subsistema de llegada de la línea de transmisión no sea el mismo de
salida, de igual manera se verifica que el nodo seleccionado se
encuentre disponible. En caso de que alguna de las dos condiciones
anteriores no se cumpla, se generará aleatoriamente un nodo y
subsistema de conexión hasta que se satisfagan las restricciones.
3. Una vez se ha encontrado un subsistema y un nodo disponible, se
asigna un -1 en la respectiva posición de la matriz de conectividad. Este
-1 indica que en al nodo k del subsistema c sale la línea i.
4. Se actualizan contadores i y h y se preselecciona aleatoriamente el
sistema c de conexión. El contador h crece de dos en dos ya que las
columnas pares de la matriz de conectividad p son las que hacen alusión
a los nodos de llegada de las líneas de transmisión.
5. Una vez se hayan asignado los nodos y subsistemas de todas las líneas
de transmisión se finaliza la ejecución.
Simulación a gran escala de transitorios electromagnéticos 61
Figura 6-4. Algoritmo para definición del subsistema al cual llega cada línea
62 Simulación de transitorios electromagnéticos mediante programación de GPUs
Con las matrices de conectividad p y los parámetros de los subsistemas y de la línea
descritos anteriormente, se definen las matrices y vectores requeridos para la solución de
los transitorios electromagnéticos del sistema generado aleatoriamente de acuerdo con lo
presentado en la sección 5.3 del presente documento de acuerdo con el procedimiento de
la Figura 5-7. El código de solución desarrollado en lenguaje CUDA es presentado en al
anexo 6.
El proceso de cálculo de transitorios electromagnéticos en la GPU es comparado en
desempeño y precisión con la solución transitoria en la CPU, para ello se sigue la
metodología presentada en el capítulo 4 de la presente investigación de acuerdo con el
procedimiento de la Figura 4-5. El código de solución de transitorios en la CPU es
presentado en el anexo 7.
6.2 Comparación en el tiempo de ejecución GPU vs CPU
Para realizar una comparación del desempeño de la solución de transitorios
electromagnéticos mediante el uso de GPU versus el uso de CPU, se ejecutan los códigos
de los anexos 6 y 7, los cuales corresponden a la solución de transitorios en la CPU y en
la GPU respectivamente. Estos códigos son empleados sobre los sistemas eléctricos de
potencia generados aleatoriamente a partir de las definiciones de la sección 6.1 de este
documento. El código de generación de sistemas aleatorios de potencia es presentado en
el anexo 8.
La solución transitoria del sistema generado aleatoriamente conteniendo hasta 2000
subsistemas es hallada en un equipo que de acuerdo con la Tabla 1-1 posee una unidad
de procesamiento gráfico NVIDIA GeForce GTX 1050 y un procesador Intel Core I5 8500H.
Tras la ejecución en la GPU y en la CPU de los códigos de solución de transitorios
electromagnéticos, anexos 6 y 7 respectivamente, con Δ𝑡 = 20 𝜇𝑠 y con un tiempo máximo
de simulación de 35 𝑚𝑠, se obtienen para un sistema de 5 subsistemas las siguientes
formas de onda:
Simulación a gran escala de transitorios electromagnéticos 63
Figura 6-5. Voltaje vs tiempo extremo inicial de la línea 1
Figura 6-6. Voltaje vs tiempo extremo final de la línea 1
64 Simulación de transitorios electromagnéticos mediante programación de GPUs
Figura 6-7. Voltaje vs tiempo extremo inicial de la línea 3
Figura 6-8. Voltaje vs tiempo extremo final de la línea 3
Simulación a gran escala de transitorios electromagnéticos 65
Figura 6-9. Voltaje vs tiempo extremo inicial de la línea 5
En las formas de onda anteriores se evidencia que se obtienen aproximadamente la misma
solución transitoria del sistema aleatoriamente generado tanto mediante el uso de la GPU
como de la CPU. La diferencia presentada entre las formas de onda es atribuible al
redondeo llevado a cabo cuando se exportan desde MATLAB las matrices a CUDA
mediante ficheros de texto.
Adicionalmente, en la Figura 6-10 se presenta un comparativo en los tiempos de ejecución
de los programas de solución de transitorios electromagnéticos. En esta se evidencia que
cuando el sistema eléctrico de potencia tiene pocos subsistemas resulta más competente
la solución de estos mediante el uso de CPUs. Sin embargo, a medida que el sistema crece
en tamaño y complejidad, la brecha en tiempo de ejecución entre la GPU y la CPU se
reduce progresivamente, alcanzando un punto a partir del cual resulta más competente
implementar estrategias basadas en la programación de unidades de procesamiento
gráfico. A simple vista puede parecer que la diferencia entre los tiempos de ejecución en
la GPU y la CPU no es mucha, sin embargo, los 25 segundos de diferencia presentados
entre el tiempo de simulación en la GPU y la CPU cuando el tamaño del sistema eléctrico
de potencia es de 2000 subsistemas, es una diferencia que puede ser ventajosa cuando
por ejemplo se ejecutan análisis que involucran miles de ejecuciones como los análisis de
confiabilidad o análisis de Montecarlo.
66 Simulación de transitorios electromagnéticos mediante programación de GPUs
Figura 6-10. Comparativo tiempos de ejecución GPU vs CPU
En la Figura 6-11 se presenta la razón de incremento en el tiempo de ejecución al crecer
el número de subsistemas de los sistemas eléctricos de potencia de prueba. La razón de
incremento en tiempo de ejecución es hallada como el cociente entre el tiempo de
ejecución con 𝑀 subsistemas y un tiempo base, el cual corresponde al tiempo de ejecución
para un sistema compuesto por dos subsistemas y dos líneas. En la Figura 6-11 resulta
evidente la paralelización del proceso de solución obtenida en el uso de unidades de
procesamiento gráfico, ya que por ejemplo cuando el tamaño del sistema es de 500
subsistemas, es decir el tamaño se ha multiplicado 250 veces respecto al sistema base,
en la CPU el tiempo de ejecución se ha multiplicado aproximadamente 600 veces y en su
lugar el tiempo de ejecución en la GPU se ha multiplicado únicamente 54 veces.
Se destaca que el tiempo base utilizado para el cálculo de la razón de incremento es
diferente en el caso de la simulación en la CPU y en la GPU, siendo 39635 𝜇𝑠 para la CPU
y 795769 𝜇𝑠 para la GPU. La alta diferencia en los tiempos base de cálculo justifica el
hecho de que aunque en la Figura 6-11 la diferencia entre la GPU y la CPU es considerable
en la Figura 6-10 no sea tan notoria.
0
50
100
150
200
250
300
350
0 500 1000 1500 2000
Tie
mp
o d
e e
jecució
n (
s)
Cantidad de subsistemas
Comparativo tiempos de ejecución
GPU
CPU
Simulación a gran escala de transitorios electromagnéticos 67
Figura 6-11. Comparativo tiempo de ejecución por sistema GPU vs CPU.
Resulta importante identificar que en esta comparación la unidad de procesamiento gráfico
GPU disponible, la cual corresponde a la NVIDIA GeForce GTX 1050, tiene un poder de
cálculo bastante inferior al procesador Intel Core I5 8300H por lo que el tamaño del sistema
en el cual resulta más competente emplear unidades de procesamiento gráfico
corresponde a una cantidad de subsistemas considerable. Esta cantidad de subsistemas
es plausible si se considera la complejidad de los subsistemas empleados, ya que en la
realidad se pueden encontrar sistemas con múltiples elementos y diferentes niveles de
tensión que resultan mucho más complejos que el sistema eléctrico de prueba empleado.
La cantidad de subsistemas a partir de la cual resulta más competente el uso de unidades
de procesamiento gráfico en lugar de CPUs se puede reducir empleando GPUs
especializadas con un mayor desempeño en el cálculo paralelo como la Tesla V100-SXM2.
[29]
0
1,000
2,000
3,000
4,000
5,000
6,000
7,000
8,000
9,000
0 500 1000 1500 2000
Tie
mpo d
e e
jecució
n/ tiem
po d
e e
jecució
n b
ase
Cantidad de subsistemas
Crecimiento en el tiempo de ejecución
GPU
CPU
7. Conclusiones y trabajos futuros
7.1 Conclusiones
De acuerdo con los resultados de los capítulos 5 y 6 del presente documento se puede
afirmar que se ha cumplido el objetivo general de esta investigación, el cual corresponde
a “implementar una metodología que mejore los tiempos de simulación de transitorios
electromagnéticos de potencia basada en técnicas modernas de solución de redes
eléctricas y de computación paralela”. Lo anterior debido a que se ha propuesto una
metodología de solución de transitorios mediante el uso de unidades de procesamiento
gráfico (GPU) que mejora el enfoque tradicional de ejecución hibrida CPU-GPU, puesto
que ofrece la misma precisión y mejora de acuerdo con la Tabla 5-1 los tiempos de cálculo
en aproximadamente un 45%. Además, al implementar un algoritmo de generación
aleatoria de sistemas eléctricos de potencia y solucionar el sistema aleatoriamente
generado con la metodología propuesta, se encuentra que a partir de cierto número de
subsistemas la metodología resulta ser más competente que el enfoque tradicional de
cálculo de transitorios electromagnéticos en la CPU.
Para cumplir el objetivo general, esta investigación satisfizo los objetivos específicos
identificados en la introducción, para ello se definió un esquema de particionamiento
gráfico y se evaluaron las condiciones de operación de sistemas eléctricos de potencia a
través del uso de Equivalentes de Thévenin Multi Área (MATE) tal como se presenta en
los capítulos 2, 3 y 4. Finalmente, mencionados esquemas de particionamiento fueron
utilizados para realizar el cálculo de transitorios de sistemas eléctricos de potencia a partir
de técnicas de computación paralela usando la arquitectura CUDA en los capítulos 5 y 6.
Con la implementación de los modelos equivalentes de Dommel en la metodología de los
Equivalentes de Thévenin Multi Área y en particular con el uso del modelo equivalente de
70 Simulación de transitorios electromagnéticos mediante programación de GPUs
las líneas de transmisión, esta investigación realiza un valioso aporte, ya que esto permite
emular de manera más acertada las características eléctricas de los equipos y elementos
de los sistemas eléctricos de potencia en el cálculo de transitorios electromagnéticos. El
modelo de línea empleado corresponde al modelo ideal de línea de transmisión, sin
embargo, la metodología propuesta es aplicable a modelos más detallados.
La metodología propuesta nombrada GPU-O no solo mejora los tiempos de ejecución en
aproximadamente un 45% y un 18% respecto a las estrategias de simulación CPU-GPU-1
y CPU-GPU-2 respectivamente sino que también a partir de cierto número de subsistemas
demuestra ser más competente que la solución de transitorios electromagnéticos en la
CPU, tal como se muestra en la Figura 6-10.
En resumen, se ha propuesto una metodología en la cual los sistemas eléctricos de
potencia son divididos gráficamente, para ello se define que los subsistemas estarán
compuestos por elementos que pertenecen a la misma infraestructura eléctrica
(subestación, central de generación, cargas, entre otros) y se establece que las líneas de
transmisión constituirán los enlaces de la metodología MATE. Posteriormente, este
sistema dividido es representando a través de modelos equivalentes obtenidos a partir de
la regla trapezoidal de integración y es solucionado completamente en la GPU mediante
la aplicación de la arquitectura CUDA.
La metodología anterior, como se muestra en el capítulo 6 en la Figura 6-11, exhibe un
paralelismo manteniendo el tiempo de ejecución por sistema aproximadamente constante
a pesar del incremento en la cantidad de subsistemas del sistema eléctrico de potencia a
resolver. Este comportamiento le permite a la metodología propuesta tener un desempeño
superior comparado con la solución de transitorios electromagnéticos en la CPU mediante
el uso de MATLAB.
Se identifica como clave el uso de los modelos equivalentes de Dommel para la simulación
de transitorios los cuales además de permitir desacoplar los sistemas, permiten la
representación de los componentes de la red a través de elementos resistivos y fuentes de
corriente con valores históricos, evitando el uso de modelos que implican la utilización de
números complejos, reduciendo así la complejidad de la programación y el respectivo
tiempo de ejecución.
Conclusiones y trabajos futuros 71
El desarrollo propuesto no incluye la simulación en tiempo real de sistemas eléctricos de
potencia, sin embargo, se estima que con el uso de unidades de procesamiento gráfico
GPUs especializadas, así como de los accesorios necesarios para conectar un controlador
o una protección real, la metodología propuesta puede ser empleada cumpliendo con las
restricciones de las simulaciones en tiempo real.
Se destaca que en la comparación del desempeño GPU vs CPU presentada en el
capítulo 6 se utilizó una unidad de procesamiento gráfico GPU GeForce GTX 1050 de
gama media. Esta tarjeta gráfica es pensada más para la ejecución de videojuegos que
para computación paralela; no obstante, a partir de cierta cantidad de subsistemas su uso
resultó ser más competente que el uso de unidades de procesamiento central CPU, Lo
cual evidencia que la metodología propuesta constituye una alternativa accesible
comparada con el uso de super computadores o RTS.
Se destaca que la cantidad de subsistemas a partir de la cual resulta más competente el
uso de la GPU que de la CPU puede ser reducido a medida que se utilicen GPUs más
especializadas.
7.2 Trabajos futuros
Se recomienda explorar la utilización de modelos de líneas de transmisión diferentes al
modelo de parámetros distribuidos.
A su vez, se identifica la posibilidad de que a partir de la metodología propuesta se
implementen simuladores de tiempo real para lo cual deberán utilizarse unidades de
procesamiento gráfico especializadas como la serie Tesla de NVIDIA.
A. Anexo 1: Código validación uso modelos equivalentes de Dommel
1. clear all 2. clc 3. R0=10; 4. E=1; 5. Zc=350; 6. tao=60/300000; 7. deltat=tao/15; 8. C=0.1*1e-6; 9. G=[1/R0+1/Zc 0;0 1/Zc+2*C/deltat]; 10. H=inv(G); 11. 12. %Condiciones iniciales considerando sistema relajado 13. 14. I1(1)=0; 15. I2(1)=0; 16. Ic(1)=0; 17. u1(1)=0; 18. u2(1)=0; 19. ic(1)=0; 20. i12(1)=0; 21. i21(1)=0; 22. 23. %Tiempo máximo de simulación y primer paso de tiempo 24. tmax=35e-3; 25. t=deltat; 26. i=1+1; 27. 28. 29. while(t<=tmax) 30. ttao=round((t-tao)/deltat+1); 31. tdel=round((t-deltat)/deltat+1); 32. if t-tao<0 33. I1(i)=0; 34. I2(i)=0; 35. Ic(i)=-(2*C/deltat*u2(tdel)+ic(tdel)); 36. b=H*[E/R0-I1(i) -I2(i)-Ic(i)]'; 37. u1(i)=b(1); 38. u2(i)=b(2); 39. ic(i)= 2*C/deltat*u2(i)+Ic(i); 40. i12(i)=1/R0*(E-u1(i)); 41. i21(i)=-ic(i); 42. else 43. I1(i)=-(u2(ttao)/Zc+i21(ttao));
74 Simulación de transitorios electromagnéticos mediante programación de GPUs
44. I2(i)=-(u1(ttao)/Zc+i12(ttao)); 45. Ic(i)=-(2*C/deltat*u2(tdel)+ic(tdel)); 46. b=H*[E/R0-I1(i) -I2(i)-Ic(i)]'; 47. u1(i)=b(1); 48. u2(i)=b(2); 49. ic(i)= 2*C/deltat*u2(i)+Ic(i); 50. i12(i)=1/R0*(E-u1(i)); 51. i21(i)=-ic(i); 52. 53. end 54. 55. %Actualización de parámetros 56. i=i+1; 57. t=t+deltat; 58. 59. end 60. %Se gráfican los resultados
61. plot([0:deltat:t-deltat],u2)
B. Anexo 2: Código implementación MATE + Dommel
1. %MATE+DOMMEL+LÍNEA DE TRANSMISIÓN
2. 3. %Se usa una sola línea como enlace entre sistema A y sistema B
4. 5. %Se define el valor de las variables de cada subsistema, así como de la
6. %líneas de interconexión. 7. clear all
8. clc 9.
10. %Sistema A Conformado por resistencias 11. Ra12=20;
12. Ra23=10; 13. Ra34=2.5;
14. Ra14=5; 15. Ra4=2;
16. %Se calculan admitancias del sistema A 17. Ga12=1/Ra12;
18. Ga23=1/Ra23; 19. Ga34=1/Ra34;
20. Ga14=1/Ra14; 21. Ga4=1/Ra4;
22. 23. %Sistema B Conformado por resistencias
24. Rb12=7; 25. Rb23=5;
26. Rb34=2; 27. Rb14=10;
28. Rb4=8; 29. %Se calculan admitancias del sistema B
30. Gb12=1/Rb12; 31. Gb23=1/Rb23;
32. Gb34=1/Rb34; 33. Gb14=1/Rb14;
34. Gb4=1/Rb4; 35.
36. %Línea 37. long=60; %km
38. Zc=200; 39. vel=300000;
40. tao=long/vel; 41. deltat=tao/10;
42. tmax=35e-3; %tiempo máximo de simulación
76 Simulación de transitorios electromagnéticos mediante programación de GPUs
43. Za1=Zc; 44. Za2=Zc;
45. 46. %Se definen las matrices Ybus respectivas, A y B, como si los sistemas A y
47. %B estuvieran separados
48. A=[Ga12+Ga14 -Ga12 0 -Ga14;-Ga12 Ga12+Ga23 -Ga23 0;0 -Ga23 Ga23+Ga34 -Ga34;-Ga14 0 -Ga34 Ga14+Ga34+Ga4]; %Matriz de admitancia sistema A
49. B=[Gb12+Gb14 -Gb12 0 -Gb14;-Gb12 Gb12+Gb23 -Gb23 0;0 -Gb23 Gb23+Gb34 -Gb34;-Gb14 0 -Gb34 Gb14+Gb34+Gb4];%Matriz de admitancia sistema B
50. 51. %Se define la matriz de enlace Z
52. Z=[Za1 0;0 Za2]; 53.
54. %Se definen matrices de inyección 55. p=[0 0 ;0 0;1 0 ;0 0]; %asociado a sistema A
56. q=[0 -1 ;0 0;0 0 ;0 0]; %asociado a sistema B 57.
58. a=inv(A)*p; 59. b=inv(B)*q;
60. 61. %Se define zalpha
62. Zalpha=p'*a+q'*b+Z; 63.
64. k=1; %Contador de posiciones para almacenar los datos 65. t=0; %Se inicia el tiempo
66. U_A3(k)=0; %Sistema inicialmente relajado 67. U_B1(k)=0;
68. t=t+deltat; 69. k=k+1;
70. 71. tic
72. while (t<=tmax) 73. ttao=round((t-tao)/deltat+1);
74. tdel=round((t-deltat)/deltat+1); 75. if t< 100*deltat
76. ramp(k)=t/(100*deltat)*1000; 77. else
78. ramp(k)=0; 79. end
80. if t-tao<0 %considerando el tiempo de viaje de la línea 81. I1(k)=0;
82. I2(k)=0; 83. else
84. I1(k)=-(U_B1(ttao)/Zc+i21(ttao)); 85. I2(k)=-(U_A3(ttao)/Zc+i12(ttao));
86. 87. end
88. 89. Ia=[ramp(k) 0 -I1(k) 0]'; %matriz de inyección sistema A
90. Ib=[-I2(k) 0 0 0]'; %matriz de inyección sistema B 91.
92. %Se determinan las tensiones de los equivalentes: 93. Ea=inv(A)*Ia;
94. Eb=inv(B)*Ib; 95. %Con las anteriores corrientes se determina la tensión asociada a
l enlace
96. %Ealpha
97. Ealpha=p'*Ea+q'*Eb; 98. %Se halla la corriente de los enlaces
99. Ialpha=inv(Zalpha)*Ealpha;
Anexo B. Código implementación MATE + Dommel 77
100.
101. %Con la corriente de los enlaces se actualizan las tensione
s de
102. %los enlaces
103. Eanuevo=inv(A)*(Ia-p*Ialpha);
104. Ebnuevo=inv(B)*(Ib-q*Ialpha);
105.
106. U_A3(k)=Eanuevo(3);
107. U_B1(k)=Ebnuevo(1);
108.
109. %Con Eanuevo usando dommel se halla la corriente de las lín
eas
110. i12(k)=U_A3(k)/Zc+I1(k);
111. i21(k)=U_B1(k)/Zc+I2(k);
112.
113. %Se actualiza contador y tiempo
114. k=k+1;
115. t=t+deltat;
116.
117.
118. end
119. toc %Se detiene conteo de tiempo de cálculo
120. %Se gráfican los resultados
121. figure(1)
122. plot([0:deltat:t],U_B1)
123. title('Voltaje (V) vs Tiempo (s) Nodo 1 -Sistema B')
124. xlabel('Tiempo (s)') % x-axis label
125. ylabel('Voltaje (V)') % y-axis label
126. figure(2)
127. plot([0:deltat:t],U_A3)
128. title('Voltaje (V) vs Tiempo (s) Nodo 3 - Sistema A')
129. xlabel('Tiempo (s)') % x-axis label
130. ylabel('Voltaje (V)') % y-axis label
131. figure(3)
132. plot([0:deltat:t],ramp)
133. title('Corriente(A) vs Tiempo (s) -Iramp')
134. xlabel('Tiempo (s)') % x-axis label
135. ylabel('Corriente (A)') % y-axis label
C. Anexo 3: Código computación paralela metodología CPU-GPU-1
1. #include <iostream> 2. #include <cmath> 3. #include <fstream> 4. #include "cuda.h" 5. #include "math.h" 6. #include <cstdio> 7. #include <chrono> 8. 9. 10. #define M 4 //M es el número de nodos de los subsistemas 11. #define N 6 //N es el número de enlaces entre los subsistemas, son 3 enla
ces pero por cada enlace es como si fueran 6
12. using namespace std; 13. using namespace std::chrono; 14. 15. __global__ void func1(double *A, double *B, double *C, int Col, int Row)
//Col y Row hacen alusión a la matriz que se esta multiplicando
16. 17. int ROW = blockIdx.x*blockDim.x + threadIdx.x; 18. double tmp = 0; 19. if (ROW < Row) //Multiplicación matriz vector siendo B el vector de
orden Col
20. for (int i = 0; i < Col; i++) 21. tmp += A[ROW * Col + i] * B[i]; 22. 23. 24. 25. C[ROW] = tmp; /*Por la forma como se linealiza la matriz*/ 26. 27. 28. __global__ void func2(double *A, double *B, double *C, double *D, double *
E, double *F, double *G, int Col, int Row)
29. 30. int ROW = blockIdx.x*blockDim.x + threadIdx.x; 31. double tmp = 0; 32. 33. 34. if (ROW < Row) 35. for (int i = 0; i < Col; i++) 36. tmp += A[ROW * Col + i] * B[i] + C[ROW * Col + i] * D[i] + E[R
OW * Col + i] * F[i];
37. 38. 39. 40. G[ROW] = tmp; 41.
Anexo C. Código computación paralela metodología CPU-GPU 1 79
42. 43. __global__ void func3(double *A, double *B, double *C, double *D, int Row,
int Col)
44. 45. int ROW = blockIdx.x*blockDim.x + threadIdx.x; 46. double tmp = 0; 47. if (ROW < Row) 48. for (int i = 0; i < Col; i++) 49. tmp += A[ROW * Col + i] * B[i]; 50. 51. 52. 53. D[ROW] = C[ROW] - tmp; /*Por la forma como se linealiza la matriz*/ 54. //printf("\n C = %f+%f i", C[ROW].x, C[ROW].y);
55. 56. 57. int main(void) 58. double Ea[M], Eb[M], Ec[M], Ealpha[N]; 59. double Ialpha[N], Ianuevo[M], Ibnuevo[M], Icnuevo[M], Eanuevo[M], Ebnu
evo[M], Ecnuevo[M];
60. double *dEa, *dEb, *dEc, *dInvA, *dInvB, *dInvC, *dIa, *dIb, *dIc, *dEalpha, *dptrans, *dqtrans, *drtrans, *dIalpha, *dinvZa, *dp, *dq, *dr, *dI
anuevo, *dIbnuevo, *dIcnuevo, *dEanuevo, *dEbnuevo, *dEcnuevo;
61. 62. 63. //Definición matrices inversas 64. double invA[M*M] = 0; 65. double invB[M*M] = 0; 66. double invC[M*M] = 0; 67. 68. ifstream archivo_invA; 69. archivo_invA.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\Trabajo
con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3_base\\Mate3_matl
ab\\invA.txt");
70. 71. //Comprobación de errores en apertura del archivo 72. if (!archivo_invA.is_open()) 73. cout << "Error del archivo1" << endl; 74. 75. 76. for (int i = 0; i < M*M; i++) 77. archivo_invA >> invA[i]; 78. 79. 80. archivo_invA.close(); 81. 82. ifstream archivo_invB; 83. archivo_invB.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\Trabajo
con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3_base\\Mate3_matl
ab\\invB.txt");
84. 85. //Comprobación de errores en apertura del archivo 86. if (!archivo_invB.is_open()) 87. cout << "Error del archivo2" << endl; 88. 89. 90. for (int i = 0; i < M*M; i++) 91. archivo_invB >> invB[i]; 92.
80 Simulación de transitorios electromagnéticos mediante programación de GPUs
93. 94. archivo_invB.close(); 95. 96. 97. ifstream archivo_invC; 98. archivo_invC.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\Trabajo
con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3_base\\Mate3_matl
ab\\invC.txt");
99. 100. //Comprobación de errores en apertura del archivo
101. if (!archivo_invC.is_open())
102. cout << "Error del archivo3" << endl;
103.
104.
105. for (int i = 0; i < M*M; i++)
106. archivo_invC >> invC[i];
107.
108.
109. archivo_invC.close();
110.
111. /*for (int i = 0; i < M*M; i++)
112. cout<<invB[i]<<endl;
113. */
114.
115.
116. //Definición parámetros de líneas
117. double delta[3];
118. //línea 1
119. double Zc1 = 200;
120. double Zc2 = Zc1;
121. double long1 = 60;
122. double tao1 = long1 / 300000;
123. delta[0] = tao1 / 10;
124. //línea 2
125. double Zc3 = 150;
126. double Zc4 = Zc3;
127. double long2 = 40;
128. double tao2 = long2 / 300000;
129. delta[1] = tao2 / 10;
130. //línea 3
131. double Zc5 = 180;
132. double Zc6 = Zc5;
133. double long3 = 20;
134. double tao3 = long3 / 300000;
135. delta[2] = tao3 / 10; //Ojo los vectores comienzan desde cero.
136.
137. double deltat = delta[0];
138. //printf("Deltat antes= %f \n", deltat);
139.
140. for (int i = 1; i < 3; i++)
141. if (delta[i] < deltat)
142. deltat = delta[i];
143.
144.
145. //printf("Deltat= %f \n", deltat);
146. //cout << "deltat= " << deltat << "\n";
147.
148. //Inicialización parámetro de tiempo
149. double t = 0;
150. int k = 0; //Inicialización parámetro de posición.
151. size_t kmax = ceil(0.035 / deltat) * sizeof(double);
Anexo C. Código computación paralela metodología CPU-GPU 1 81
152. //printf("/n máximo número de pasos Kmax = %d \n", kmax);
153.
154.
155. double *I1, *I2, *I3, *I4, *I5, *I6, *U_A2, *U_B1, *i21, *i12, *
U_B3, *U_C2, *U_A3, *U_C1, *ic2, *ib3, *ic1, *ia3, *t1;
156. I1 = (double *)malloc(kmax);
157. I2 = (double *)malloc(kmax);
158. I3 = (double *)malloc(kmax);
159. I4 = (double *)malloc(kmax);
160. I5 = (double *)malloc(kmax);
161. I6 = (double *)malloc(kmax);
162. U_A2 = (double *)malloc(kmax);
163. U_B1 = (double *)malloc(kmax);
164. i21 = (double *)malloc(kmax);
165. i12 = (double *)malloc(kmax);
166. t1 = (double *)malloc(kmax);
167. U_A2[0] = 0;
168. U_B1[0] = 0;
169. i12[0] = 0;
170. i21[0] = 0;
171. I1[0] = 0;
172. I2[0] = 0;
173. I3[0] = 0;
174. I4[0] = 0;
175. I5[0] = 0;
176. I6[0] = 0;
177. t1[0] = 0;
178.
179. U_C2 = (double *)malloc(kmax);
180. U_B3 = (double *)malloc(kmax);
181. ic2 = (double *)malloc(kmax); //relacionadas con línea 2
182. ib3 = (double *)malloc(kmax); //relacionadas con línea 2
183. U_C2[0] = 0;
184. U_B3[0] = 0;
185. ic2[0] = 0;
186. ib3[0] = 0;
187.
188. U_C1 = (double *)malloc(kmax);
189. U_A3 = (double *)malloc(kmax);
190. ic1 = (double *)malloc(kmax); //relacionadas con línea 3
191. ia3 = (double *)malloc(kmax); //relacionadas con línea 3
192. U_C1[0] = 0;
193. U_A3[0] = 0;
194. ic1[0] = 0;
195. ia3[0] = 0;
196.
197.
198. //Definición matriz inversa Zalpha
199. double invZa[N*N] = 0;
200.
201. ifstream archivo_invZalpha;
202. archivo_invZalpha.open("C:\\Users\\Quartas\\Google Drive\\Maestr
ía\\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3_base\
\Mate3_matlab\\invZalpha.txt");
203.
204. //Comprobación de errores en apertura del archivo
205. if (!archivo_invZalpha.is_open())
206. cout << "Error del archivo4" << endl;
207.
208.
82 Simulación de transitorios electromagnéticos mediante programación de GPUs
209. for (int i = 0; i < N*N; i++)
210. archivo_invZalpha >> invZa[i];
211.
212.
213. archivo_invZalpha.close();
214.
215. //definición matrices de relación traspuestas
216.
217. double ptrans[M*N] = 0;
218. double qtrans[M*N] = 0;
219. double rtrans[M*N] = 0;
220.
221. ifstream archivo_pprima;
222. archivo_pprima.open("C:\\Users\\Quartas\\Google Drive\\Maestría\
\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3_base\\Ma
te3_matlab\\pprima.txt");
223.
224. //Comprobación de errores en apertura del archivo
225. if (!archivo_pprima.is_open())
226. cout << "Error del archivo5" << endl;
227.
228.
229. for (int j = 0; j < N*M; j++)
230. archivo_pprima >> ptrans[j];
231.
232.
233.
234. archivo_pprima.close();
235.
236.
237. ifstream archivo_qprima;
238. archivo_qprima.open("C:\\Users\\Quartas\\Google Drive\\Maestría\
\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3_base\\Ma
te3_matlab\\qprima.txt");
239.
240. //Comprobación de errores en apertura del archivo
241. if (!archivo_qprima.is_open())
242. cout << "Error del archivo6" << endl;
243.
244.
245. for (int j = 0; j < N*M; j++)
246. archivo_qprima >> qtrans[j];
247.
248.
249.
250. archivo_qprima.close();
251.
252. ifstream archivo_rprima;
253. archivo_rprima.open("C:\\Users\\Quartas\\Google Drive\\Maestría\
\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3_base\\Ma
te3_matlab\\rprima.txt");
254.
255. //Comprobación de errores en apertura del archivo
256. if (!archivo_rprima.is_open())
257. cout << "Error del archivo7" << endl;
258.
259.
260. for (int j = 0; j < N*M; j++)
261. archivo_rprima >> rtrans[j];
262.
263.
Anexo C. Código computación paralela metodología CPU-GPU 1 83
264.
265. archivo_rprima.close();
266.
267.
268. //Definición Matriz p, matriz de orden MxN, asociada a los enlac
es del sistema A.
269. double p[M*N] = 0;
270.
271. //Definición Matriz q, matriz de orden MxN, asociada a los enlac
es del sistema B.
272. double q[M*N] = 0;
273.
274. //Definición Matriz r, matriz de orden MxN, asociada a los enlac
es del sistema C.
275. double r[M*N] = 0 ;
276.
277. ifstream archivo_p;
278. archivo_p.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\Trab
ajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3_base\\Mate3_m
atlab\\p.txt");
279.
280. //Comprobación de errores en apertura del archivo
281. if (!archivo_p.is_open())
282. cout << "Error del archivo8" << endl;
283.
284.
285. for (int j = 0; j < M*N; j++)
286. archivo_p >> p[j];
287.
288.
289.
290. archivo_p.close();
291.
292. ifstream archivo_q;
293. archivo_q.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\Trab
ajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3_base\\Mate3_m
atlab\\q.txt");
294.
295. //Comprobación de errores en apertura del archivo
296. if (!archivo_q.is_open())
297. cout << "Error del archivo9" << endl;
298.
299.
300. for (int j = 0; j < M*N; j++)
301. archivo_q >> q[j];
302.
303.
304.
305. archivo_q.close();
306.
307. ifstream archivo_r;
308. archivo_r.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\Trab
ajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3_base\\Mate3_m
atlab\\r.txt");
309.
310. //Comprobación de errores en apertura del archivo
311. if (!archivo_r.is_open())
312. cout << "Error del archivo10" << endl;
313.
314.
84 Simulación de transitorios electromagnéticos mediante programación de GPUs
315. for (int j = 0; j < M*N; j++)
316. archivo_r >> r[j];
317.
318.
319.
320. archivo_r.close();
321.
322.
323. cudaMalloc(&dEa, M * sizeof(double));
324. cudaMalloc(&dEb, M * sizeof(double));
325. cudaMalloc(&dEc, M * sizeof(double));
326. cudaMalloc(&dInvA, M*M * sizeof(double));
327. cudaMalloc(&dInvB, M*M * sizeof(double));
328. cudaMalloc(&dInvC, M*M * sizeof(double));
329. cudaMalloc(&dIa, M * sizeof(double));
330. cudaMalloc(&dIb, M * sizeof(double));
331. cudaMalloc(&dIc, M * sizeof(double));
332.
333.
334. cudaMemcpy(dInvA, invA, (M*M) * sizeof(double), cudaMemcpyHostTo
Device);
335. cudaMemcpy(dInvB, invB, (M*M) * sizeof(double), cudaMemcpyHostTo
Device);
336. cudaMemcpy(dInvC, invC, (M*M) * sizeof(double), cudaMemcpyHostTo
Device);
337.
338.
339. cudaMalloc(&dEalpha, N * sizeof(double));
340. cudaMalloc(&dptrans, (N*M) * sizeof(double));
341. cudaMalloc(&dqtrans, (N*M) * sizeof(double));
342. cudaMalloc(&drtrans, (N*M) * sizeof(double));
343. cudaMemcpy(dptrans, ptrans, (N*M) * sizeof(double), cudaMemcpyHo
stToDevice);
344. cudaMemcpy(dqtrans, qtrans, (N*M) * sizeof(double), cudaMemcpyHo
stToDevice);
345. cudaMemcpy(drtrans, rtrans, (N*M) * sizeof(double), cudaMemcpyHo
stToDevice);
346.
347.
348. cudaMalloc(&dIalpha, N * sizeof(double));
349. cudaMalloc(&dinvZa, (N*N) * sizeof(double));
350. cudaMemcpy(dinvZa, invZa, (N*N) * sizeof(double), cudaMemcpyHost
ToDevice);
351.
352.
353. cudaMalloc(&dp, (M*N) * sizeof(double));
354. cudaMalloc(&dq, (M*N) * sizeof(double));
355. cudaMalloc(&dr, (M*N) * sizeof(double));
356. cudaMalloc(&dIanuevo, (M) * sizeof(double));
357. cudaMalloc(&dIbnuevo, (M) * sizeof(double));
358. cudaMalloc(&dIcnuevo, (M) * sizeof(double));
359. cudaMemcpy(dp, p, (M*N) * sizeof(double), cudaMemcpyHostToDevice
);
360. cudaMemcpy(dq, q, (M*N) * sizeof(double), cudaMemcpyHostToDevice
);
361. cudaMemcpy(dr, r, (M*N) * sizeof(double), cudaMemcpyHostToDevice
);
362.
363. cudaMalloc(&dEanuevo, (M) * sizeof(double));
364. cudaMalloc(&dEbnuevo, (M) * sizeof(double));
365. cudaMalloc(&dEcnuevo, (M) * sizeof(double));
Anexo C. Código computación paralela metodología CPU-GPU 1 85
366.
367.
368. printf("Primer valor \n");
369. //time_t start, end;
370. //time(&start);
371. auto start = high_resolution_clock::now();
372. t = t + deltat;
373. k = k + 1;
374. t1[k] = t;
375.
376.
377. while (t < 0.035) //35ms es el tiempo máximo de cálculo
378.
379. //indicadores de posición para los valores al
macenados
380. int ttao1 = int((t - tao1) / deltat);
381. int ttao2 = int((t - tao2) / deltat);
382. int ttao3 = int((t - tao3) / deltat);
383.
384.
385.
386.
387. //printf("El tiempo ttao2 es %d \n", int(floor(ttao2)));
388.
389. if ((t - tao1) < 0)
390. I1[k] = 0;
391. I2[k] = 0;
392.
393. else
394. I1[k] = -(U_B1[ttao1] / Zc1 + i21[ttao1]);
395. I2[k] = -(U_A2[ttao1] / Zc1 + i12[ttao1]);
396.
397.
398.
399. if ((t - tao2) < 0)
400. I3[k] = 0;
401. I4[k] = 0;
402.
403. else
404.
405. I3[k] = -(U_C2[ttao2] / Zc3 + ic2[ttao2]);
406. I4[k] = -(U_B3[ttao2] / Zc3 + ib3[ttao2]);
407.
408.
409.
410. if ((t - tao3) < 0)
411. I5[k] = 0;
412. I6[k] = 0;
413.
414. else
415.
416. I5[k] = -(U_C1[ttao3] / Zc5 + ic1[ttao3]);
417. I6[k] = -(U_A3[ttao3] / Zc5 + ia3[ttao3]);
418.
419.
420.
421. //Iramp
422. double ramp;
423. if (t < 100 * deltat)
424. ramp = t / (100 * deltat) * 1000;
86 Simulación de transitorios electromagnéticos mediante programación de GPUs
425.
426. else
427. ramp = 0;
428.
429.
430. //Con I1, I2..., I6 puedo hallar las tensiones de los sistem
as Ia, Ib, Ic
431.
432.
433. double Ia[M] = ramp, -I1[k], -I5[k], 0 ;
434. double Ib[M] = -I2[k], 0, -I3[k], 0 ;
435. double Ic[M] = -I6[k], -I4[k], 0, 0 ;
436.
437.
438.
439. cudaMemcpy(dIa, Ia, M * sizeof(double), cudaMemcpyHostToDevi
ce);
440. cudaMemcpy(dIb, Ib, M * sizeof(double), cudaMemcpyHostToDevi
ce);
441. cudaMemcpy(dIc, Ic, M * sizeof(double), cudaMemcpyHostToDevi
ce);
442.
443.
444. dim3 blocksPerGrid(1, 1, 1);
445. dim3 threadsPerBlock(M, 1, 1);
446.
447. //Cálculo de Ea, Eb y Ec en streams diferentes
448.
449. func1 << <blocksPerGrid, threadsPerBlock >> >(dInvA, dIa, dE
a, M, M);
450. //cudaThreadSynchronize();
451. func1 << <blocksPerGrid, threadsPerBlock >> >(dInvB, dIb, dE
b, M, M);
452. //cudaThreadSynchronize();
453. func1 << <blocksPerGrid, threadsPerBlock >> >(dInvC, dIc, dE
c, M, M);
454. //cudaThreadSynchronize();
455.
456. cudaDeviceSynchronize();
457.
458. //Cálculo de Ealpha
459.
460. threadsPerBlock.x = N;
461.
462. func2 << <blocksPerGrid, threadsPerBlock >> >(dptrans, dEa,
dqtrans, dEb, drtrans, dEc, dEalpha, M, N);
463. //cudaThreadSynchronize();
464. cudaDeviceSynchronize();
465.
466.
467. //Cálculo de Ialpha
468.
469. func1 << <blocksPerGrid, threadsPerBlock >> >(dinvZa, dEalph
a, dIalpha, N, N);
470. //cudaThreadSynchronize();
471. cudaDeviceSynchronize();
472.
473. //Cálculo de corrientes de inyección nuevas
474.
475. threadsPerBlock.x = M;
476.
Anexo C. Código computación paralela metodología CPU-GPU 1 87
477.
478. func3 << <blocksPerGrid, threadsPerBlock >> >(dp, dIalpha, d
Ia, dIanuevo, M, N);
479. //cudaThreadSynchronize();
480. func3 << <blocksPerGrid, threadsPerBlock >> >(dq, dIalpha, d
Ib, dIbnuevo, M, N);
481. //cudaThreadSynchronize();
482. func3 << <blocksPerGrid, threadsPerBlock >> >(dr, dIalpha, d
Ic, dIcnuevo, M, N);
483. //cudaThreadSynchronize();
484.
485. cudaDeviceSynchronize();
486.
487. //Cálculo de tensiones nodales nuevas
488.
489. func1 << <blocksPerGrid, threadsPerBlock >> >(dInvA, dIanuev
o, dEanuevo, M, M);
490. //cudaThreadSynchronize();
491. func1 << <blocksPerGrid, threadsPerBlock >> >(dInvB, dIbnuev
o, dEbnuevo, M, M);
492. //cudaThreadSynchronize();
493. func1 << <blocksPerGrid, threadsPerBlock >> >(dInvC, dIcnuev
o, dEcnuevo, M, M);
494. //cudaThreadSynchronize();
495. cudaDeviceSynchronize();
496.
497. cudaMemcpy(Eanuevo, dEanuevo, (M) * sizeof(double), cudaMemc
pyDeviceToHost);
498. cudaMemcpy(Ebnuevo, dEbnuevo, (M) * sizeof(double), cudaMemc
pyDeviceToHost);
499. cudaMemcpy(Ecnuevo, dEcnuevo, (M) * sizeof(double), cudaMemc
pyDeviceToHost);
500. //cudaDeviceSynchronize();
501.
502. //Actualización de parámetros
503.
504. U_B1[k] = Ebnuevo[0];
505. i21[k] = U_B1[k] / Zc2 + I2[k];
506. U_A2[k] = Eanuevo[1];
507. i12[k] = U_A2[k] / Zc1 + I1[k];
508. U_B3[k] = Ebnuevo[2];
509. ib3[k] = U_B3[k] / Zc3 + I3[k];
510. U_C2[k] = Ecnuevo[1];
511. ic2[k] = U_C2[k] / Zc4 + I4[k];
512. U_A3[k] = Eanuevo[2];
513. ia3[k] = U_A3[k] / Zc5 + I5[k];
514. U_C1[k] = Ecnuevo[0];
515. ic1[k] = U_C1[k] / Zc6 + I6[k];
516.
517.
518. t += deltat;
519. k = k + 1;
520. t1[k] = t;
521.
522.
523. auto stop = high_resolution_clock::now();
524. auto duration = duration_cast<microseconds>(stop - start);
525.
526. FILE *fp;
527. fp = fopen("tension.txt", "w");
88 Simulación de transitorios electromagnéticos mediante programación de GPUs
528.
529. for (int i = 0; i < k-1; i++)
530. fprintf(fp, "%f %f %f %f %f %f \n", U_A2[i], U_B1[i], U_B3[i
], U_C2[i], U_A3[i], U_C1[i]);
531.
532.
533.
534.
535. cout << " Tiempo de ejecucion " << duration.count() << " microse
conds" << endl;
536. printf("ultimo valor \n");
537. fclose(fp);
538. cout << deltat << endl;
539. return 0;
540.
D. Anexo 4: Código computación paralela metodología CPU-GPU 2.
1. #include <iostream> 2. #include <cmath> 3. #include <fstream> 4. #include "cuda.h" 5. #include "math.h" 6. #include <cstdio> 7. #include <chrono> 8. 9. 10. #define M 4 //M es el número de nodos de los subsistemas 11. #define N 6 //N es el número de enlaces entre los subsistemas 12. using namespace std; 13. using namespace std::chrono; 14. 15. __global__ void func1(double *A, double *B, double *C, int Col, int Row)
//Col y Row hacen alusión a la matriz que se esta multiplicando
16. 17. int ROW = blockIdx.x*blockDim.x + threadIdx.x; 18. double tmp = 0; 19. if (ROW < Row) //Multiplicación matriz vector siendo B el vector de
orden Col
20. for (int i = 0; i < Col; ++i) 21. tmp += A[ROW * Col + i] * B[i]; 22. 23. 24. 25. C[ROW] = tmp; /*Por la forma como se linealiza la matriz*/ 26. 27. 28. __global__ void func2(double *A, double *B, double *C, double *D, double *
E, double *F, double *G, int Col, int Row)
29. 30. int ROW = blockIdx.x*blockDim.x + threadIdx.x; 31. double tmp = 0; 32. 33. 34. if (ROW < Row) 35. for (int i = 0; i < Col; ++i) 36. tmp += A[ROW * Col + i] * B[i] + C[ROW * Col + i] * D[i] + E[R
OW * Col + i] * F[i];
37. 38. 39. 40. G[ROW] = tmp; 41. 42.
90 Simulación de transitorios electromagnéticos mediante programación de GPUs
43. __global__ void func3(double *A, double *B, double *C, double *D, int Row, int Col)
44. 45. int ROW = blockIdx.x*blockDim.x + threadIdx.x; 46. double tmp = 0; 47. if (ROW < Row) 48. for (int i = 0; i < Col; ++i) 49. tmp += A[ROW * Col + i]* B[i]; 50. 51. 52. 53. D[ROW] = C[ROW]-tmp; /*Por la forma como se linealiza la matriz*/ 54. //printf("\n C = %f+%f i", C[ROW].x, C[ROW].y); 55. 56. 57. int main(void) 58. 59. double Eanuevo[M], Ebnuevo[M], Ecnuevo[M]; 60. double *dEa, *dEb, *dEc, *dInvA, *dInvB, *dInvC, *dIa, *dIb, *dIc, *dE
alpha, *dptrans, *dqtrans, *drtrans, *dIalpha, *dinvZa, *dp, *dq, *dr, *dI
anuevo, *dIbnuevo, *dIcnuevo, *dEanuevo, *dEbnuevo, *dEcnuevo;
61. 62. 63. //Definición matrices inversas 64. double invA[M*M] = 0 ; 65. double invB[M*M] = 0 ; 66. double invC[M*M] = 0 ; 67. 68. 69. ifstream archivo_invA; 70. archivo_invA.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\Trabajo
con Javier Herrera\\Tareas\\16. Códigos a validar\\MATE3_optimizado\\Mate
3_opt MATLAB\\invA.txt");
71. 72. //Comprobación de errores en apertura del archivo 73. if (!archivo_invA.is_open()) 74. cout << "Error del archivo1" << endl; 75. 76. 77. for (int i = 0; i < M*M; i++) 78. archivo_invA >> invA[i]; 79. 80. 81. archivo_invA.close(); 82. 83. ifstream archivo_invB; 84. archivo_invB.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\Trabajo
con Javier Herrera\\Tareas\\16. Códigos a validar\\MATE3_optimizado\\Mate
3_opt MATLAB\\invB.txt");
85. 86. //Comprobación de errores en apertura del archivo 87. if (!archivo_invB.is_open()) 88. cout << "Error del archivo2" << endl; 89. 90. 91. for (int i = 0; i < M*M; i++) 92. archivo_invB >> invB[i]; 93. 94. 95. archivo_invB.close(); 96.
Anexo D. Código computación paralela metodología CPU-GPU 2 91
97. 98. ifstream archivo_invC; 99. archivo_invC.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\Trabajo
con Javier Herrera\\Tareas\\16. Códigos a validar\\MATE3_optimizado\\Mate
3_opt MATLAB\\invC.txt");
100.
101. //Comprobación de errores en apertura del archivo
102. if (!archivo_invC.is_open())
103. cout << "Error del archivo3" << endl;
104.
105.
106. for (int i = 0; i < M*M; i++)
107. archivo_invC >> invC[i];
108.
109.
110. archivo_invC.close();
111.
112. //Definición parámetros de líneas
113. double delta[3];
114. //línea 1
115. double Zc1 = 200;
116. double Zc2 = Zc1;
117. double long1 = 60;
118. double tao1 = long1 / 300000;
119. delta[0] = tao1 / 10;
120. //línea 2
121. double Zc3 = 150;
122. double Zc4 = Zc3;
123. double long2 = 40;
124. double tao2 = long2 / 300000;
125. delta[1] = tao2 / 10;
126. //línea 3
127. double Zc5 = 180;
128. double Zc6 = Zc5;
129. double long3 = 20;
130. double tao3 = long3 / 300000;
131. delta[2] = tao3 / 10; //Ojo los vectores comienzan desde cero.
132.
133. double deltat = delta[0];
134. //printf("Deltat antes= %f \n", deltat);
135.
136. for (int i = 1; i < 3; i++)
137. if (delta[i] < deltat)
138. deltat = delta[i];
139.
140.
141. //printf("Deltat= %f \n", deltat);
142.
143. //Inicialización parámetro de tiempo
144. double t = 0;
145. int k = 0; //Inicialización parámetro de posición.
146. size_t kmax = ceil(0.035 / deltat) * sizeof(double);
147. //printf("/n máximo número de pasos Kmax = %f \n", ceil(0.035 /
deltat) );
148.
149. double *I1, *I2, *I3, *I4, *I5, *I6, *U_A2, *U_B1, *i21, *i12, *
U_B3, *U_C2, *U_A3, *U_C1, *ic2, *ib3, *ic1, *ia3, *t1;
150. I1 = (double *)malloc(kmax);
151. I2 = (double *)malloc(kmax);
152. I3 = (double *)malloc(kmax);
92 Simulación de transitorios electromagnéticos mediante programación de GPUs
153. I4 = (double *)malloc(kmax);
154. I5 = (double *)malloc(kmax);
155. I6 = (double *)malloc(kmax);
156. U_A2 = (double *)malloc(kmax);
157. U_B1 = (double *)malloc(kmax);
158. i21 = (double *)malloc(kmax);
159. i12 = (double *)malloc(kmax);
160. t1 = (double *)malloc(kmax);
161. U_A2[0] = 0;
162. U_B1[0] = 0;
163. i12[0] = 0;
164. i21[0] = 0;
165. I1[0] = 0;
166. I2[0] = 0;
167. I3[0] = 0;
168. I4[0] = 0;
169. I5[0] = 0;
170. I6[0] = 0;
171. t1[0] = 0;
172.
173. U_C2 = (double *)malloc(kmax);
174. U_B3 = (double *)malloc(kmax);
175. ic2 = (double *)malloc(kmax); //relacionadas con línea 2
176. ib3 = (double *)malloc(kmax); //relacionadas con línea 2
177. U_C2[0] = 0;
178. U_B3[0] = 0;
179. ic2[0] = 0;
180. ib3[0] = 0;
181.
182. U_C1 = (double *)malloc(kmax);
183. U_A3 = (double *)malloc(kmax);
184. ic1 = (double *)malloc(kmax); //relacionadas con línea 3
185. ia3 = (double *)malloc(kmax); //relacionadas con línea 3
186. U_C1[0] = 0;
187. U_A3[0] = 0;
188. ic1[0] = 0;
189. ia3[0] = 0;
190.
191. //Definición matriz inversa Zalpha
192. double invZa[N*N] = 0;
193.
194. ifstream archivo_invZalpha;
195. archivo_invZalpha.open("C:\\Users\\Quartas\\Google Drive\\Maestr
ía\\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\MATE3_optim
izado\\Mate3_opt MATLAB\\invZalpha.txt");
196.
197. //Comprobación de errores en apertura del archivo
198. if (!archivo_invZalpha.is_open())
199. cout << "Error del archivo4" << endl;
200.
201.
202. for (int i = 0; i < N*N; i++)
203. archivo_invZalpha >> invZa[i];
204.
205.
206. archivo_invZalpha.close();
207.
208. //definición matrices de relación traspuestas
209.
210. double ptrans[M*N] = 0;
211. double qtrans[M*N] = 0;
Anexo D. Código computación paralela metodología CPU-GPU 2 93
212. double rtrans[M*N] = 0;
213.
214. ifstream archivo_pprima;
215. archivo_pprima.open("C:\\Users\\Quartas\\Google Drive\\Maestría\
\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\MATE3_optimiza
do\\Mate3_opt MATLAB\\pprima.txt");
216.
217. //Comprobación de errores en apertura del archivo
218. if (!archivo_pprima.is_open())
219. cout << "Error del archivo5" << endl;
220.
221.
222. for (int j = 0; j < N*M; j++)
223. archivo_pprima >> ptrans[j];
224.
225.
226.
227. archivo_pprima.close();
228.
229.
230. ifstream archivo_qprima;
231. archivo_qprima.open("C:\\Users\\Quartas\\Google Drive\\Maestría\
\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\MATE3_optimiza
do\\Mate3_opt MATLAB\\qprima.txt");
232.
233. //Comprobación de errores en apertura del archivo
234. if (!archivo_qprima.is_open())
235. cout << "Error del archivo6" << endl;
236.
237.
238. for (int j = 0; j < N*M; j++)
239. archivo_qprima >> qtrans[j];
240.
241.
242.
243. archivo_qprima.close();
244.
245. ifstream archivo_rprima;
246. archivo_rprima.open("C:\\Users\\Quartas\\Google Drive\\Maestría\
\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\MATE3_optimiza
do\\Mate3_opt MATLAB\\rprima.txt");
247.
248. //Comprobación de errores en apertura del archivo
249. if (!archivo_rprima.is_open())
250. cout << "Error del archivo7" << endl;
251.
252.
253. for (int j = 0; j < N*M; j++)
254. archivo_rprima >> rtrans[j];
255.
256.
257.
258. archivo_rprima.close();
259.
260.
261. //Definición Matriz p, matriz de orden MxN, asociada a los enlac
es del sistema A.
262. double p[M*N] = 0 ;
263.
94 Simulación de transitorios electromagnéticos mediante programación de GPUs
264. //Definición Matriz q, matriz de orden MxN, asociada a los enlac
es del sistema B.
265. double q[M*N] = 0 ;
266.
267. //Definición Matriz r, matriz de orden MxN, asociada a los enlac
es del sistema C.
268. double r[M*N] = 0 ;
269.
270. ifstream archivo_p;
271. archivo_p.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\Trab
ajo con Javier Herrera\\Tareas\\16. Códigos a validar\\MATE3_optimizado\\M
ate3_opt MATLAB\\p.txt");
272.
273. //Comprobación de errores en apertura del archivo
274. if (!archivo_p.is_open())
275. cout << "Error del archivo8" << endl;
276.
277.
278. for (int j = 0; j < M*N; j++)
279. archivo_p >> p[j];
280.
281.
282.
283. archivo_p.close();
284.
285. ifstream archivo_q;
286. archivo_q.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\Trab
ajo con Javier Herrera\\Tareas\\16. Códigos a validar\\MATE3_optimizado\\M
ate3_opt MATLAB\\q.txt");
287.
288. //Comprobación de errores en apertura del archivo
289. if (!archivo_q.is_open())
290. cout << "Error del archivo9" << endl;
291.
292.
293. for (int j = 0; j < M*N; j++)
294. archivo_q >> q[j];
295.
296.
297.
298. archivo_q.close();
299.
300. ifstream archivo_r;
301. archivo_r.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\Trab
ajo con Javier Herrera\\Tareas\\16. Códigos a validar\\MATE3_optimizado\\M
ate3_opt MATLAB\\r.txt");
302.
303. //Comprobación de errores en apertura del archivo
304. if (!archivo_r.is_open())
305. cout << "Error del archivo10" << endl;
306.
307.
308. for (int j = 0; j < M*N; j++)
309. archivo_r >> r[j];
310.
311.
312.
313. archivo_r.close();
314.
315. cudaMalloc(&dEa, M * sizeof(double));
316. cudaMalloc(&dEb, M * sizeof(double));
Anexo D. Código computación paralela metodología CPU-GPU 2 95
317. cudaMalloc(&dEc, M * sizeof(double));
318. cudaMalloc(&dInvA, M*M * sizeof(double));
319. cudaMalloc(&dInvB, M*M * sizeof(double));
320. cudaMalloc(&dInvC, M*M * sizeof(double));
321. cudaMalloc(&dIa, M * sizeof(double));
322. cudaMalloc(&dIb, M * sizeof(double));
323. cudaMalloc(&dIc, M * sizeof(double));
324.
325.
326. cudaMemcpy(dInvA, invA, (M*M) * sizeof(double), cudaMemcpyHostTo
Device);
327. cudaMemcpy(dInvB, invB, (M*M) * sizeof(double), cudaMemcpyHostTo
Device);
328. cudaMemcpy(dInvC, invC, (M*M) * sizeof(double), cudaMemcpyHostTo
Device);
329.
330.
331. cudaMalloc(&dEalpha, N * sizeof(double));
332. cudaMalloc(&dptrans, (N*M) * sizeof(double));
333. cudaMalloc(&dqtrans, (N*M) * sizeof(double));
334. cudaMalloc(&drtrans, (N*M) * sizeof(double));
335. cudaMemcpy(dptrans, ptrans, (N*M) * sizeof(double), cudaMemcpyHo
stToDevice);
336. cudaMemcpy(dqtrans, qtrans, (N*M) * sizeof(double), cudaMemcpyHo
stToDevice);
337. cudaMemcpy(drtrans, rtrans, (N*M) * sizeof(double), cudaMemcpyHo
stToDevice);
338.
339.
340. cudaMalloc(&dIalpha, N * sizeof(double));
341. cudaMalloc(&dinvZa, (N*N) * sizeof(double));
342. cudaMemcpy(dinvZa, invZa, (N*N) * sizeof(double), cudaMemcpyHost
ToDevice);
343.
344.
345. cudaMalloc(&dp, (M*N) * sizeof(double));
346. cudaMalloc(&dq, (M*N) * sizeof(double));
347. cudaMalloc(&dr, (M*N) * sizeof(double));
348. cudaMalloc(&dIanuevo, (M) * sizeof(double));
349. cudaMalloc(&dIbnuevo, (M) * sizeof(double));
350. cudaMalloc(&dIcnuevo, (M) * sizeof(double));
351. cudaMemcpy(dp, p, (M*N) * sizeof(double), cudaMemcpyHostToDevice
);
352. cudaMemcpy(dq, q, (M*N) * sizeof(double), cudaMemcpyHostToDevice
);
353. cudaMemcpy(dr, r, (M*N) * sizeof(double), cudaMemcpyHostToDevice
);
354.
355. cudaMalloc(&dEanuevo, (M) * sizeof(double));
356. cudaMalloc(&dEbnuevo, (M) * sizeof(double));
357. cudaMalloc(&dEcnuevo, (M) * sizeof(double));
358.
359.
360. //Se crean los streams necesarios para ejecutar el kernel parale
lamente
361. cudaStream_t stream[3];
362. cudaStreamCreate(&stream[0]);
363. cudaStreamCreate(&stream[1]);
364. cudaStreamCreate(&stream[2]);
365.
96 Simulación de transitorios electromagnéticos mediante programación de GPUs
366. t = t + deltat;
367. k = k + 1;
368. t1[k] = t;
369.
370. dim3 blocksPerGrid(1, 1, 1);
371. dim3 threadsPerBlock(M, 1, 1);
372.
373. printf("Primer valor \n");
374. auto start = high_resolution_clock::now();
375.
376. while (t < 0.035) //35ms es el tiempo máximo de cálculo
377.
378. //indicadores de posición para los valores almacenados
379. int ttao1 = int((t - tao1) / deltat);
380. int ttao2 = int((t - tao2) / deltat);
381. int ttao3 = int((t - tao3) / deltat);
382.
383. //printf("El tiempo ttao2 es %d \n", int(floor(ttao2)));
384.
385. if ((t - tao1) < 0)
386. I1[k] =0;
387. I2[k] =0;
388.
389. else
390.
391. I1[k] = -(U_B1[ttao1] / Zc1 + i21[ttao1]);
392. I2[k] = -(U_A2[ttao1] / Zc1 + i12[ttao1]);
393.
394.
395.
396. if ((t - tao2) < 0)
397. I3[k] = 0;
398. I4[k] = 0;
399.
400. else
401.
402. I3[k] = -(U_C2[ttao2] / Zc3 + ic2[ttao2]);
403. I4[k] = -(U_B3[ttao2] / Zc3 + ib3[ttao2]);
404.
405.
406.
407. if ((t - tao3) < 0)
408. I5[k] = 0;
409. I6[k] = 0;
410.
411. else
412.
413. I5[k] = -(U_C1[ttao3] / Zc5 + ic1[ttao3]);
414. I6[k] = -(U_A3[ttao3] / Zc5 + ia3[ttao3]);
415.
416.
417. //Iramp
418. double ramp;
419. if (t < 100 * deltat)
420. ramp = t / (100 * deltat) * 1000;
421. //printf("El valor de la corriente es %f \n", ramp);
422.
423. else
424. ramp = 0;
425.
426.
Anexo D. Código computación paralela metodología CPU-GPU 2 97
427. //Con I1, I2..., I6 puedo hallar las tensiones de los sistem
as Ia, Ib, Ic
428.
429. double Ia[M] = ramp, -I1[k], -I5[k], 0 ;
430. double Ib[M] = -I2[k], 0, -I3[k], 0 ;
431. double Ic[M] = -I6[k], -I4[k], 0, 0 ;
432.
433.
434.
435.
436. cudaMemcpyAsync(dIa, Ia, M * sizeof(double), cudaMemcpyHostT
oDevice, stream[0]);
437. cudaMemcpyAsync(dIb, Ib, M * sizeof(double), cudaMemcpyHostT
oDevice, stream[1]);
438. cudaMemcpyAsync(dIc, Ic, M * sizeof(double), cudaMemcpyHostT
oDevice, stream[2]);
439. cudaDeviceSynchronize();
440.
441.
442.
443. threadsPerBlock.x = M;
444.
445. //Cálculo de Ea, Eb y Ec en streams diferentes
446.
447. func1 << <blocksPerGrid, threadsPerBlock, 0, stream[0] >> >(
dInvA, dIa, dEa, M, M);
448.
449. func1 << <blocksPerGrid, threadsPerBlock, 0, stream[1] >> >(
dInvB, dIb, dEb, M, M);
450.
451. func1 << <blocksPerGrid, threadsPerBlock, 0, stream[2] >> >(
dInvC, dIc, dEc, M, M);
452.
453.
454. cudaDeviceSynchronize();
455.
456. //Cálculo de Ealpha
457.
458. threadsPerBlock.x = N;
459.
460. func2 << <blocksPerGrid, threadsPerBlock, 0, stream[0] >> >(
dptrans, dEa, dqtrans, dEb, drtrans, dEc, dEalpha, M, N);
461.
462.
463.
464. //Cálculo de Ialpha
465.
466. func1 << <blocksPerGrid, threadsPerBlock, 0, stream[0] >> >(
dinvZa, dEalpha, dIalpha, N, N);
467. //cudaThreadSynchronize();
468. cudaDeviceSynchronize();
469.
470. //Cálculo de corrientes de inyección nuevas
471.
472. threadsPerBlock.x = M;
473.
474.
475. func3 << <blocksPerGrid, threadsPerBlock, 0, stream[0] >> >(
dp, dIalpha, dIa, dIanuevo, M, N);
476.
98 Simulación de transitorios electromagnéticos mediante programación de GPUs
477. func3 << <blocksPerGrid, threadsPerBlock, 0, stream[1] >> >(
dq, dIalpha, dIb, dIbnuevo, M, N);
478.
479. func3 << <blocksPerGrid, threadsPerBlock, 0, stream[2] >> >(
dr, dIalpha, dIc, dIcnuevo, M, N);
480.
481.
482. //Cálculo de tensiones nodales nuevas
483.
484. func1 << <blocksPerGrid, threadsPerBlock, 0, stream[0] >> >(
dInvA, dIanuevo, dEanuevo, M, M);
485. //cudaThreadSynchronize();
486. func1 << <blocksPerGrid, threadsPerBlock, 0, stream[1] >> >(
dInvB, dIbnuevo, dEbnuevo, M, M);
487. //cudaThreadSynchronize();
488. func1 << <blocksPerGrid, threadsPerBlock, 0, stream[2] >> >(
dInvC, dIcnuevo, dEcnuevo, M, M);
489. //cudaThreadSynchronize();
490.
491.
492. cudaMemcpyAsync(Eanuevo, dEanuevo, (M) * sizeof(double), cud
aMemcpyDeviceToHost, stream[0]);
493. cudaMemcpyAsync(Ebnuevo, dEbnuevo, (M) * sizeof(double), cud
aMemcpyDeviceToHost, stream[1]);
494. cudaMemcpyAsync(Ecnuevo, dEcnuevo, (M) * sizeof(double), cud
aMemcpyDeviceToHost, stream[2]);
495. cudaDeviceSynchronize();
496.
497. U_B1[k] = Ebnuevo[0];
498. i21[k] = U_B1[k] / Zc2 + I2[k];
499. U_A2[k] = Eanuevo[1];
500. i12[k] = U_A2[k] / Zc1 + I1[k];
501. U_B3[k] = Ebnuevo[2];
502. ib3[k] = U_B3[k] / Zc3 + I3[k];
503. U_C2[k] = Ecnuevo[1];
504. ic2[k] = U_C2[k] / Zc4 + I4[k];
505. U_A3[k] = Eanuevo[2];
506. ia3[k] = U_A3[k] / Zc5 + I5[k];
507. U_C1[k] = Ecnuevo[0];
508. ic1[k] = U_C1[k] / Zc6 + I6[k];
509.
510. t += deltat;
511. k = k+1;
512. t1[k] = t;
513.
514.
515. //time(&end);
516. auto stop = high_resolution_clock::now();
517. auto duration = duration_cast<microseconds>(stop - start);
518.
519. FILE *fp;
520. fp = fopen("tension.txt", "w");
521.
522. for (int i = 0; i < k-1; i++)
523. fprintf(fp, "%f %f %f %f %f %f \n", U_A2[i], U_B1[i], U_B3[i
], U_C2[i], U_A3[i], U_C1[i]);
524.
525.
526. cout << " Tiempo de ejecucion " << duration.count() << " microse
conds"<< endl;
527.
Anexo D. Código computación paralela metodología CPU-GPU 2 99
528. printf("ultimo valor \n");
529. fclose(fp);
530. return 0;
531.
E. Anexo 5: Código computación paralela metodología GPU-GPU O
1. #include <iostream> 2. #include <cmath> 3. #include <fstream> 4. #include "cuda.h" 5. #include "math.h" 6. #include <cstdio> 7. #include <stdlib.h> 8. #include <chrono> 9. 10. #define M 4 //M es el número de nodos de los subsistemas 11. #define N 6 //N es el número de enlaces entre los subsistemas 12. 13. using namespace std; 14. using namespace std::chrono; 15. 16. __global__ void func1(double *A, double *B, double *C, int Col, int Row)
//Col y Row hacen alusión a la matriz que se esta multiplicando
17. 18. int ROW = blockIdx.x*blockDim.x + threadIdx.x; 19. double tmp = 0; 20. if (ROW < Row) //Multiplicación matriz vector siendo B el vector de
orden Col
21. for (int i = 0; i < Col; i++) 22. tmp += A[ROW * Col + i] * B[i]; 23. 24. 25. 26. C[ROW] = tmp; /*Por la forma como se linealiza la matriz*/ 27. 28. 29. __global__ void func2(double *A, double *B, double *C, double *D, double *
E, double *F, double *G, int Col, int Row)
30. 31. int ROW = blockIdx.x*blockDim.x + threadIdx.x; 32. double tmp = 0; 33. 34. 35. if (ROW < Row) 36. for (int i = 0; i < Col; i++) 37. tmp += A[ROW * Col + i] * B[i] + C[ROW * Col + i] * D[i] + E[R
OW * Col + i] * F[i];
38. 39. 40. 41. G[ROW] = tmp; 42. 43.
102 Simulación de transitorios electromagnéticos mediante programación de GPUs
44. __global__ void func3(double *A, double *B, double *C, double *D, int Row, int Col)
45. 46. int ROW = blockIdx.x*blockDim.x + threadIdx.x; 47. double tmp = 0; 48. if (ROW < Row) 49. for (int i = 0; i < Col; i++) 50. tmp += A[ROW * Col + i] * B[i]; 51. 52. 53. 54. D[ROW] = C[ROW] - tmp; /*Por la forma como se linealiza la matriz*/ 55. //printf("\n C = %f+%f i", C[ROW].x, C[ROW].y);
56. 57. 58. __global__ void func4(int k, double ttao, double *U_A, double *U_B, double
deltat, double Zc, double *i12, double *i21, double *I1, double *I2)
59. int ttao_ind = int(ttao); 60. 61. if (ttao < 0) 62. I1[k] = 0; 63. I2[k] = 0; 64. 65. else 66. 67. I1[k] = -(U_B[ttao_ind] / Zc + i21[ttao_ind]); 68. I2[k] = -(U_A[ttao_ind] / Zc + i12[ttao_ind]); 69. 70. 71. 72. 73. __global__ void func5(int k, double ramp, double *I1, double *I2, double *
I3, double *I4, double *I5, double *I6, double *Ia, double *Ib, double *Ic
)
74. 75. Ia[0] = ramp; 76. Ia[1] = -I1[k]; 77. Ia[2] = -I5[k]; 78. Ia[3] = 0; 79. 80. Ib[0] = -I2[k]; 81. Ib[1] = 0; 82. Ib[2] = -I3[k]; 83. Ib[3] = 0; 84. 85. Ic[0] = -I6[k]; 86. Ic[1] = -I4[k]; 87. Ic[2] = 0; 88. Ic[3] = 0; 89. 90. 91. 92. __global__ void func6(int k, double *U_A2, double *U_B1, double *U_B3, dou
ble *U_C2, double *U_A3, double *U_C1, double *i12, double *i21, double *i
b3, double *ic2, double *ia3, double *ic1, double *Eanuevo, double *Ebnuev
o, double *Ecnuevo, double *I1, double *I2, double *I3, double *I4, double
*I5, double *I6, double Zc1, double Zc3, double Zc5)
93. U_B1[k] = Ebnuevo[0]; 94. i21[k] = U_B1[k] / Zc1 + I2[k]; 95. U_A2[k] = Eanuevo[1];
Anexo E. Código computación paralela metodología GPU-GPU O 103
96. i12[k] = U_A2[k] / Zc1 + I1[k]; 97. U_B3[k] = Ebnuevo[2]; 98. ib3[k] = U_B3[k] / Zc3 + I3[k]; 99. U_C2[k] = Ecnuevo[1]; 100. ic2[k] = U_C2[k] / Zc3 + I4[k];
101. U_A3[k] = Eanuevo[2];
102. ia3[k] = U_A3[k] / Zc5 + I5[k];
103. U_C1[k] = Ecnuevo[0];
104. ic1[k] = U_C1[k] / Zc5 + I6[k];
105.
106.
107. int main(void)
108. double Eanuevo[M], Ebnuevo[M], Ecnuevo[M];
109. double *dEa, *dEb, *dEc, *dInvA, *dInvB, *dInvC, *dIa, *dIb, *dI
c, *dEalpha, *dptrans, *dqtrans, *drtrans, *dIalpha, *dinvZa, *dp, *dq, *d
r, *dIanuevo, *dIbnuevo, *dIcnuevo, *dEanuevo, *dEbnuevo, *dEcnuevo;
110.
111.
112. //Definición matrices inversas
113. double invA[M*M] = 0 ;
114. double invB[M*M] = 0 ;
115. double invC[M*M] = 0 ;
116.
117. ifstream archivo_invA;
118. archivo_invA.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\T
rabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3gpu\\Mate3g
pu Matlab\\invA.txt");
119.
120. //Comprobación de errores en apertura del archivo
121. if (!archivo_invA.is_open())
122. cout << "Error del archivo1" << endl;
123.
124.
125. for (int i = 0; i < M*M; i++)
126. archivo_invA >> invA[i];
127.
128.
129. archivo_invA.close();
130.
131. ifstream archivo_invB;
132. archivo_invB.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\T
rabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3gpu\\Mate3g
pu Matlab\\invB.txt");
133.
134. //Comprobación de errores en apertura del archivo
135. if (!archivo_invB.is_open())
136. cout << "Error del archivo2" << endl;
137.
138.
139. for (int i = 0; i < M*M; i++)
140. archivo_invB >> invB[i];
141.
142.
143. archivo_invB.close();
144.
145.
146. ifstream archivo_invC;
147. archivo_invC.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\T
rabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3gpu\\Mate3g
pu Matlab\\invC.txt");
104 Simulación de transitorios electromagnéticos mediante programación de GPUs
148.
149. //Comprobación de errores en apertura del archivo
150. if (!archivo_invC.is_open())
151. cout << "Error del archivo3" << endl;
152.
153.
154. for (int i = 0; i < M*M; i++)
155. archivo_invC >> invC[i];
156.
157.
158. archivo_invC.close();
159.
160. //Definición parámetros de líneas
161. double delta[3];
162. //línea 1
163. double Zc1 = 200 ;
164. double Zc2 = 200 ;
165. double long1 = 60;
166. double tao1 = long1 / 300000;
167. delta[0] = tao1 / 10;
168. //línea 2
169. double Zc3 = 150 ;
170. double Zc4 = 150 ;
171. double long2 = 40;
172. double tao2 = long2 / 300000;
173. delta[1] = tao2 / 10;
174. //línea 3
175. double Zc5 = 180 ;
176. double Zc6 = 180 ;
177. double long3 = 20;
178. double tao3 = long3 / 300000;
179. delta[2] = tao3 / 10; //Ojo los vectores comienzan desde cero.
180.
181. double deltat = delta[0];
182.
183. for (int i = 1; i < 3; i++)
184. if (delta[i] < deltat)
185. deltat = delta[i];
186.
187.
188.
189.
190. //Inicialización parámetro de tiempo
191. double t = 0;
192. int k = 0; //Inicialización parámetro de posición.
193. size_t kmax = ceil(0.035 / deltat) * sizeof(double);
194.
195.
196.
197. double *I1, *I2, *I3, *I4, *I5, *I6, *t1, *ttao1, *ttao2, *ttao3
;
198. I1 = (double *)malloc(kmax);
199. I2 = (double *)malloc(kmax);
200. I3 = (double *)malloc(kmax);
201. I4 = (double *)malloc(kmax);
202. I5 = (double *)malloc(kmax);
203. I6 = (double *)malloc(kmax);
204. t1 = (double *)malloc(kmax);
205.
206. double U_A2[5260] = 0 ;
207. double U_B1[5260] = 0 ;
Anexo E. Código computación paralela metodología GPU-GPU O 105
208. double U_C2[5260] = 0 ;
209. double U_B3[5260] = 0 ;
210. double U_C1[5260] = 0 ;
211. double U_A3[5260] = 0 ;
212. double i12[5260] = 0 ;
213. double i21[5260] = 0 ;
214. double ic2[5260] = 0 ;
215. double ib3[5260] = 0 ;
216. double ic1[5260] = 0 ;
217. double ia3[5260] = 0 ;
218.
219.
220.
221. I1[0] = 0;
222. I2[0] = 0;
223. I3[0] = 0;
224. I4[0] = 0;
225. I5[0] = 0;
226. I6[0] = 0;
227. t1[0] = 0;
228.
229.
230. //Definición matriz inversa Zalpha
231. double invZa[N*N] = 0 ;
232.
233. ifstream archivo_invZalpha;
234. archivo_invZalpha.open("C:\\Users\\Quartas\\Google Drive\\Maestr
ía\\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3gpu\\M
ate3gpu Matlab\\invZalpha.txt");
235.
236. //Comprobación de errores en apertura del archivo
237. if (!archivo_invZalpha.is_open())
238. cout << "Error del archivo4" << endl;
239.
240.
241. for (int i = 0; i < N*N; i++)
242. archivo_invZalpha >> invZa[i];
243.
244.
245. archivo_invZalpha.close();
246.
247. //definición matrices de relación traspuestas
248.
249. double ptrans[M*N] = 0;
250. double qtrans[M*N] = 0;
251. double rtrans[M*N] = 0;
252.
253. ifstream archivo_pprima;
254. archivo_pprima.open("C:\\Users\\Quartas\\Google Drive\\Maestría\
\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3gpu\\Mate
3gpu Matlab\\pprima.txt");
255.
256. //Comprobación de errores en apertura del archivo
257. if (!archivo_pprima.is_open())
258. cout << "Error del archivo5" << endl;
259.
260.
261. for (int j = 0; j < N*M; j++)
262. archivo_pprima >> ptrans[j];
263.
106 Simulación de transitorios electromagnéticos mediante programación de GPUs
264.
265.
266. archivo_pprima.close();
267.
268.
269. ifstream archivo_qprima;
270. archivo_qprima.open("C:\\Users\\Quartas\\Google Drive\\Maestría\
\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3gpu\\Mate
3gpu Matlab\\qprima.txt");
271.
272. //Comprobación de errores en apertura del archivo
273. if (!archivo_qprima.is_open())
274. cout << "Error del archivo6" << endl;
275.
276.
277. for (int j = 0; j < N*M; j++)
278. archivo_qprima >> qtrans[j];
279.
280.
281.
282. archivo_qprima.close();
283.
284. ifstream archivo_rprima;
285. archivo_rprima.open("C:\\Users\\Quartas\\Google Drive\\Maestría\
\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3gpu\\Mate
3gpu Matlab\\rprima.txt");
286.
287. //Comprobación de errores en apertura del archivo
288. if (!archivo_rprima.is_open())
289. cout << "Error del archivo7" << endl;
290.
291.
292. for (int j = 0; j < N*M; j++)
293. archivo_rprima >> rtrans[j];
294.
295.
296.
297. archivo_rprima.close();
298.
299. //Definición Matriz p, matriz de orden MxN, asociada a los enlac
es del sistema A.
300. double p[M*N] = 0 ;
301.
302. //Definición Matriz q, matriz de orden MxN, asociada a los enlac
es del sistema B.
303. double q[M*N] = 0 ;
304.
305. //Definición Matriz r, matriz de orden MxN, asociada a los enlac
es del sistema C.
306. double r[M*N] = 0 ;
307.
308. ifstream archivo_p;
309. archivo_p.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\Trab
ajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3gpu\\Mate3gpu
Matlab\\p.txt");
310.
311. //Comprobación de errores en apertura del archivo
312. if (!archivo_p.is_open())
313. cout << "Error del archivo8" << endl;
314.
315.
Anexo E. Código computación paralela metodología GPU-GPU O 107
316. for (int j = 0; j < M*N; j++)
317. archivo_p >> p[j];
318.
319.
320.
321. archivo_p.close();
322.
323. ifstream archivo_q;
324. archivo_q.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\Trab
ajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3gpu\\Mate3gpu
Matlab\\q.txt");
325.
326. //Comprobación de errores en apertura del archivo
327. if (!archivo_q.is_open())
328. cout << "Error del archivo9" << endl;
329.
330.
331. for (int j = 0; j < M*N; j++)
332. archivo_q >> q[j];
333.
334.
335.
336. archivo_q.close();
337.
338. ifstream archivo_r;
339. archivo_r.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\Trab
ajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate3gpu\\Mate3gpu
Matlab\\r.txt");
340.
341. //Comprobación de errores en apertura del archivo
342. if (!archivo_r.is_open())
343. cout << "Error del archivo10" << endl;
344.
345.
346. for (int j = 0; j < M*N; j++)
347. archivo_r >> r[j];
348.
349.
350.
351. archivo_r.close();
352.
353. cudaMalloc(&dEa, M * sizeof(double));
354. cudaMalloc(&dEb, M * sizeof(double));
355. cudaMalloc(&dEc, M * sizeof(double));
356. cudaMalloc(&dInvA, M*M * sizeof(double));
357. cudaMalloc(&dInvB, M*M * sizeof(double));
358. cudaMalloc(&dInvC, M*M * sizeof(double));
359. cudaMalloc(&dIa, M * sizeof(double));
360. cudaMalloc(&dIb, M * sizeof(double));
361. cudaMalloc(&dIc, M * sizeof(double));
362.
363.
364. cudaMemcpy(dInvA, invA, (M*M) * sizeof(double), cudaMemcpyHostTo
Device);
365. cudaMemcpy(dInvB, invB, (M*M) * sizeof(double), cudaMemcpyHostTo
Device);
366. cudaMemcpy(dInvC, invC, (M*M) * sizeof(double), cudaMemcpyHostTo
Device);
367.
368.
108 Simulación de transitorios electromagnéticos mediante programación de GPUs
369. cudaMalloc(&dEalpha, N * sizeof(double));
370. cudaMalloc(&dptrans, (N*M) * sizeof(double));
371. cudaMalloc(&dqtrans, (N*M) * sizeof(double));
372. cudaMalloc(&drtrans, (N*M) * sizeof(double));
373. cudaMemcpy(dptrans, ptrans, (N*M) * sizeof(double), cudaMemcpyHo
stToDevice);
374. cudaMemcpy(dqtrans, qtrans, (N*M) * sizeof(double), cudaMemcpyHo
stToDevice);
375. cudaMemcpy(drtrans, rtrans, (N*M) * sizeof(double), cudaMemcpyHo
stToDevice);
376.
377.
378. cudaMalloc(&dIalpha, N * sizeof(double));
379. cudaMalloc(&dinvZa, (N*N) * sizeof(double));
380. cudaMemcpy(dinvZa, invZa, (N*N) * sizeof(double), cudaMemcpyHost
ToDevice);
381.
382.
383. cudaMalloc(&dp, (M*N) * sizeof(double));
384. cudaMalloc(&dq, (M*N) * sizeof(double));
385. cudaMalloc(&dr, (M*N) * sizeof(double));
386. cudaMalloc(&dIanuevo, (M) * sizeof(double));
387. cudaMalloc(&dIbnuevo, (M) * sizeof(double));
388. cudaMalloc(&dIcnuevo, (M) * sizeof(double));
389. cudaMemcpy(dp, p, (M*N) * sizeof(double), cudaMemcpyHostToDevice
);
390. cudaMemcpy(dq, q, (M*N) * sizeof(double), cudaMemcpyHostToDevice
);
391. cudaMemcpy(dr, r, (M*N) * sizeof(double), cudaMemcpyHostToDevice
);
392.
393. cudaMalloc(&dEanuevo, (M) * sizeof(double));
394. cudaMalloc(&dEbnuevo, (M) * sizeof(double));
395. cudaMalloc(&dEcnuevo, (M) * sizeof(double));
396.
397.
398. cudaStream_t stream[3];
399. cudaStreamCreate(&stream[0]);
400. cudaStreamCreate(&stream[1]);
401. cudaStreamCreate(&stream[2]);
402.
403. k = k + 1;
404. t = t + deltat;
405.
406.
407.
408. dim3 blocksPerGrid(1, 1, 1);
409. dim3 threadsPerBlock(M, 1, 1);
410.
411.
412. double *dU_A2, *dU_B1, *dU_C2, *dU_B3, *dU_C1, *dU_A3;
413. cudaMalloc(&dU_A2, kmax);
414. cudaMalloc(&dU_B1, kmax);
415. cudaMalloc(&dU_C2, kmax);
416. cudaMalloc(&dU_B3, kmax);
417. cudaMalloc(&dU_C1, kmax);
418. cudaMalloc(&dU_A3, kmax);
419.
420. cudaMemcpy(dU_A2, U_A2, kmax, cudaMemcpyHostToDevice);
421. cudaMemcpy(dU_B1, U_B1, kmax, cudaMemcpyHostToDevice);
422. cudaMemcpy(dU_C2, U_C2, kmax, cudaMemcpyHostToDevice);
Anexo E. Código computación paralela metodología GPU-GPU O 109
423. cudaMemcpy(dU_B3, U_B3, kmax, cudaMemcpyHostToDevice);
424. cudaMemcpy(dU_C1, U_C1, kmax, cudaMemcpyHostToDevice);
425. cudaMemcpy(dU_A3, U_A3, kmax, cudaMemcpyHostToDevice);
426.
427. double *d_i12, *d_i21, *d_ic2, *d_ib3, *d_ic1, *d_ia3;
428. cudaMalloc(&d_i12, kmax);
429. cudaMalloc(&d_i21, kmax);
430. cudaMalloc(&d_ic2, kmax);
431. cudaMalloc(&d_ib3, kmax);
432. cudaMalloc(&d_ic1, kmax);
433. cudaMalloc(&d_ia3, kmax);
434.
435.
436. cudaMemcpy(d_i12, i12, kmax, cudaMemcpyHostToDevice);
437. cudaMemcpy(d_i21, i21, kmax, cudaMemcpyHostToDevice);
438. cudaMemcpy(d_ic2, ic2, kmax, cudaMemcpyHostToDevice);
439. cudaMemcpy(d_ib3, ib3, kmax, cudaMemcpyHostToDevice);
440. cudaMemcpy(d_ic1, ic1, kmax, cudaMemcpyHostToDevice);
441. cudaMemcpy(d_ia3, ia3, kmax, cudaMemcpyHostToDevice);
442.
443.
444. //I1, I2, I3, I4, I5, I6
445. double *d_I1, *d_I2, *d_I3, *d_I4, *d_I5, *d_I6;
446. cudaMalloc(&d_I1, kmax);
447. cudaMalloc(&d_I2, kmax);
448. cudaMalloc(&d_I3, kmax);
449. cudaMalloc(&d_I4, kmax);
450. cudaMalloc(&d_I5, kmax);
451. cudaMalloc(&d_I6, kmax);
452.
453.
454. printf("Primer valor \n");
455. auto start = high_resolution_clock::now();
456. while (t < 0.035) //35ms es el tiempo máximo de cálculo
457.
458. //indicadores de posición para los valores almacenados
459. int ttao1 = int((t - tao1) / deltat);
460. int ttao2 = int((t - tao2) / deltat);
461. int ttao3 = int((t - tao3) / deltat);
462.
463.
464. threadsPerBlock.x = 1;
465.
466.
467. func4 << <blocksPerGrid, threadsPerBlock, 0, stream[0] >> >(
k, ttao1, dU_A2, dU_B1, deltat, Zc1, d_i12, d_i21, d_I1, d_I2);
468. func4 << <blocksPerGrid, threadsPerBlock, 0, stream[1] >> >
(k, ttao2, dU_B3, dU_C2, deltat, Zc3, d_ib3, d_ic2, d_I3, d_I4);
469. func4 << <blocksPerGrid, threadsPerBlock, 0, stream[1] >> >
(k, ttao3, dU_A3, dU_C1, deltat, Zc5, d_ia3, d_ic1, d_I5, d_I6);
470.
471. cudaDeviceSynchronize();
472.
473. //Iramp
474. double ramp;
475. if (t < 100 * deltat)
476. ramp = t / (100 * deltat) * 1000;
477. //printf("El valor de la corriente es %f \n", ramp);
478.
479. else
110 Simulación de transitorios electromagnéticos mediante programación de GPUs
480. ramp = 0;
481.
482.
483.
484. func5 << <blocksPerGrid, threadsPerBlock, 0, stream[0] >> >
(k, ramp, d_I1, d_I2, d_I3, d_I4, d_I5, d_I6, dIa, dIb, dIc);
485. cudaDeviceSynchronize();
486.
487. threadsPerBlock.x = M;
488.
489. //Cálculo de Ea, Eb y Ec en streams diferentes
490.
491. func1 << <blocksPerGrid, threadsPerBlock, 0, stream[0] >> >(
dInvA, dIa, dEa, M, M);
492. func1 << <blocksPerGrid, threadsPerBlock, 0, stream[1] >> >(
dInvB, dIb, dEb, M, M);
493. func1 << <blocksPerGrid, threadsPerBlock, 0, stream[2] >> >(
dInvC, dIc, dEc, M, M);
494.
495. cudaDeviceSynchronize();
496.
497. //Cálculo de Ealpha
498.
499. threadsPerBlock.x = N;
500.
501. func2 << <blocksPerGrid, threadsPerBlock, 0, stream[0] >> >(
dptrans, dEa, dqtrans, dEb, drtrans, dEc, dEalpha, M, N);
502.
503.
504. //Cálculo de Ialpha
505.
506. func1 << <blocksPerGrid, threadsPerBlock, 0, stream[0] >> >(
dinvZa, dEalpha, dIalpha, N, N);
507. cudaDeviceSynchronize();
508.
509. //Cálculo de corrientes de inyección nuevas
510.
511. threadsPerBlock.x = M;
512.
513.
514. func3 << <blocksPerGrid, threadsPerBlock, 0, stream[0] >> >(
dp, dIalpha, dIa, dIanuevo, M, N);
515. func3 << <blocksPerGrid, threadsPerBlock, 0, stream[1] >> >(
dq, dIalpha, dIb, dIbnuevo, M, N);
516. func3 << <blocksPerGrid, threadsPerBlock, 0, stream[2] >> >(
dr, dIalpha, dIc, dIcnuevo, M, N);
517.
518.
519.
520. //Cálculo de tensiones nodales nuevas
521.
522. func1 << <blocksPerGrid, threadsPerBlock, 0, stream[0] >> >(
dInvA, dIanuevo, dEanuevo, M, M);
523. func1 << <blocksPerGrid, threadsPerBlock, 0, stream[1] >> >(
dInvB, dIbnuevo, dEbnuevo, M, M);
524. func1 << <blocksPerGrid, threadsPerBlock, 0, stream[2] >> >(
dInvC, dIcnuevo, dEcnuevo, M, M);
525. cudaDeviceSynchronize;
526.
527. threadsPerBlock.x = 1;
528.
Anexo E. Código computación paralela metodología GPU-GPU O 111
529.
530.
531.
532. func6 << <blocksPerGrid, threadsPerBlock, 0, stream[0] >> >(
k,dU_A2, dU_B1, dU_B3, dU_C2, dU_A3, dU_C1, d_i12, d_i21, d_ib3, d_ic2, d_
ia3, d_ic1, dEanuevo, dEbnuevo, dEcnuevo, d_I1, d_I2, d_I3, d_I4, d_I5, d_
I6, Zc1, Zc3, Zc5);
533. cudaDeviceSynchronize;
534.
535. t = t + deltat;
536. k = k + 1;
537.
538.
539.
540.
541. auto stop = high_resolution_clock::now();
542. auto duration = duration_cast<microseconds>(stop - start);
543. cout << " Tiempo de ejecucion " << duration.count() << " microse
conds" << endl;
544.
545. //dU_A2, dU_B1, dU_B3, dU_C2, dU_A3, dU_C1
546. cudaMemcpy(U_A2, dU_A2, kmax, cudaMemcpyDeviceToHost);
547. cudaMemcpy(U_B1, dU_B1, kmax, cudaMemcpyDeviceToHost);
548. cudaMemcpy(U_B3, dU_B3, kmax, cudaMemcpyDeviceToHost);
549. cudaMemcpy(U_C2, dU_C2, kmax, cudaMemcpyDeviceToHost);
550. cudaMemcpy(U_A3, dU_A3, kmax, cudaMemcpyDeviceToHost);
551. cudaMemcpy(U_C1, dU_C1, kmax, cudaMemcpyDeviceToHost);
552.
553. FILE *fp;
554. fp = fopen("tension.txt", "w");
555.
556. for (int i = 0; i < k-1; i++)
557. fprintf(fp, "%f %f %f %f %f %f \n", U_A2[i], U_B1[i], U_B3[i
], U_C2[i], U_A3[i], U_C1[i]);
558.
559.
560. fclose(fp);
561.
562. printf("ultimo valor \n");
563. return 0;
564.
F. Anexo 6: Código CUDA para la solución de transitorios de sistema eléctrico aleatorio en la GPU
1. //Se definen las librerias necesarias 2. #include <iostream> 3. #include <cmath> 4. #include <fstream> 5. #include "cuda.h" 6. #include "math.h" 7. #include <cstdio> 8. #include <stdlib.h> 9. #include <chrono> 10. 11. double P[2000][4 * 2000 * 2] = 0 ; //Para crear inicialmente el vector
P, se prevee que máximo se generaran 2000 sistemas, 2000 enlaces y cada si
stema tiene un valor fijo de nodos igual a 4
12. double Pprima[2000][2000 * 2 * 4] = 0 ; //Para crear inicialmente el vector P', se prevee que máximo se generaran 2000 sistemas, 2000 enlaces y c
ada sistema tiene un valor fijo de nodos igual a 4
13. double Pabs[2000][4 * 2000 * 2] = 0 ; //Para crear inicialmente el vector P, se prevee que máximo se generaran 2000 sistemas, 2000 enlaces y cada
sistema tiene un valor fijo de nodos igual a 4
14. double invZalpha[2000 * 2 * 2000 * 2] = 0 ; //Se prevé un sistema de max 2000 enlaces
15. double nod_UA[2000] = 0 ; //Máximo 2000 enlaces 16. double nod_UB[2000] = 0 ; //Máximo 2000 enlaces 17. double sist_UA[2000] = 0 ; //Máximo 2000 enlaces 18. double sist_UB[2000] = 0 ; //Máximo 2000 enlaces 19. 20. __global__ void func1(int k, double ttao, double Zc, double *U_A, double *
U_B, double *i12, double *i21, double *I1, double *I2) //Para cálculo de
corrientes de línea
21. 22. 23.
//int k1 = int(k);
24. int ttao1 = int(ttao); 25. 26. if (ttao < 0) 27. I1[k] = 0; 28. I2[k] = 0; 29. 30. else 31. I1[k] = -(U_B[ttao1] / Zc + i21[ttao1]); 32. I2[k] = -(U_A[ttao1] / Zc + i12[ttao1]); 33. 34.
114 Simulación de transitorios electromagnéticos mediante programación de GPUs
35. 36. 37. __global__ void func7(int i, int j, int h, int k, double *I1, double *I2,
double *Ilineas)
38. 39. 40. 41. 42. if (j % 2 == 0) 43. Ilineas[h] = -I1[k]; 44. 45. else if (j % 2 != 0) 46. Ilineas[h] = -I2[k]; 47. 48. 49. 50. 51. 52. __global__ void func3(double *A, double *B, double *C, int Col, int Row)
//Col y Row hacen alusión a la matriz que esta multiplicando
53. 54. int ROW = blockIdx.x*blockDim.x + threadIdx.x; 55. double tmp = 0; 56. if (ROW < Row) //Multiplicación matriz vector siendo B el vector de
orden Col
57. for (int i = 0; i < Col; i++) 58. tmp += A[ROW * Col + i] * B[i]; 59. 60. 61. 62. C[ROW] = tmp; /*Por la forma como se linealiza la matriz*/ 63. 64. 65. __global__ void func3_1(int rampa, double *I_iny, double Iramp) 66. I_iny[rampa] = Iramp; 67. 68. 69. 70. __global__ void func4_1(double *A, double *B, int Row) // Row hace alusió
n a la dimensión de los vectores que se estan sumando
71. 72. int ROW = blockIdx.x*blockDim.x + threadIdx.x; 73. if (ROW < Row) //Multiplicación matriz vector siendo B el vector de
orden Col
74. B[ROW] = A[ROW]; 75. 76. 77. 78. 79. __global__ void func4_2(double *A, double *B, int Row) //Row hace alusión
a la dimensión de los vectores que se estan sumando
80. 81. int ROW = blockIdx.x*blockDim.x + threadIdx.x; 82. 83. if (ROW < Row) //Multiplicación matriz vector siendo B el vector de
orden Col
84. 85. B[ROW] = B[ROW] + A[ROW]; 86. 87. 88.
Anexo F. Código CUDA para la solución de transitorios de sistema eléctrico
aleatorio en la GPU
115
89. 90. __global__ void func5(double *A, double *B, double *C, double *D, int Row,
int Col)
91. 92. int ROW = blockIdx.x*blockDim.x + threadIdx.x; 93. double tmp = 0; 94. if (ROW < Row) 95. for (int i = 0; i < Col; i++) 96. tmp += A[ROW * Col + i] * B[i]; 97. 98. 99. 100. D[ROW] = C[ROW] - tmp; /*Por la forma como se linealiza la matri
z*/
101. //printf("\n C = %f+%f i", C[ROW].x, C[RO
W].y);
102.
103.
104. __global__ void func6_1(double *U_A, double *U_B, double *i12, doubl
e *i21, double *Eanuevo, double *Ebnuevo, double *I1, double *I2, int Zc,
int k, double nod_UA, double nod_UB)
105.
106. int ind_A = int(nod_UA);
107. int ind_B = int(nod_UB);
108.
109.
110.
111. U_A[k] = Eanuevo[ind_A];
112. U_B[k] = Ebnuevo[ind_B];
113. i12[k] = U_A[k] / Zc + I1[k];
114. i21[k] = U_B[k] / Zc + I2[k];
115.
116.
117.
118.
119. int main(void)
120.
121. double M, L, N, Zc, tao;
122.
123. using namespace std;
124. using namespace std::chrono;
125.
126. dim3 blocksPerGrid(1, 1, 1);
127. dim3 threadsPerBlock(1, 1, 1);
128.
129. cudaStream_t stream[2000]; //Máximo 2000 sistemas
130.
131. for (int i = 0; i < 2000; i++) //se crean 2000 streams
132. cudaStreamCreate(&stream[i]);
133.
134.
135.
136. //Lectura de archivos con parámetros
137.
138. ifstream archivo_param;
139. archivo_param.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\
Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate_aleatorio2
\\Mate_aleatorio2_MATLAB\\param.txt");
140.
116 Simulación de transitorios electromagnéticos mediante programación de GPUs
141. //Comprobación de errores en apertura del archivo
142. if (!archivo_param.is_open())
143. cout << "Error del archivo1" << endl;
144.
145. archivo_param >> M >> L >> N >> Zc >> tao;
146. cout << M << endl; //M es número de sistemas
147. cout << L << endl; //L es número de enlaces
148. cout << N << endl; //N es el número de nodos de los subsistemas
, N es igual en ambos subsistemas A y B
149. cout << Zc << endl; //Zc es la impedancia caracteristica de los
enlaces, todos los enlaces igual Zc
150. cout << tao << endl; // tao es el tiempo de viaje en las líneas,
igual en todos los enlaces
151.
152.
153. archivo_param.close();
154.
155. //Lectura de archivos con matrices inversas
156. double invA[16] = 0 ; //se limita el tamaño de los subsistem
as a 4 nodos.
157. double invB[16] = 0 ;
158. ifstream archivo_invA;
159. archivo_invA.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\T
rabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate_aleatorio2\
\Mate_aleatorio2_MATLAB\\invA.txt");
160.
161. //Comprobación de errores en apertura del archivo
162. if (!archivo_invA.is_open())
163. cout << "Error del archivo2" << endl;
164.
165.
166. for (int i = 0; i < N*N; i++)
167. archivo_invA >> invA[i];
168.
169.
170. archivo_invA.close();
171.
172. ifstream archivo_invB;
173. archivo_invB.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\T
rabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate_aleatorio2\
\Mate_aleatorio2_MATLAB\\invB.txt");
174.
175. //Comprobación de errores en apertura del archivo
176. if (!archivo_invB.is_open())
177. cout << "Error del archivo3" << endl;
178.
179.
180. for (int i = 0; i < N*N; i++)
181. archivo_invB >> invB[i];
182.
183.
184. archivo_invB.close();
185.
186. ifstream archivo_P;
187. archivo_P.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\Trab
ajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate_aleatorio2\\Ma
te_aleatorio2_MATLAB\\P.txt");
188.
189. //Comprobación de errores en apertura del archivo
190. if (!archivo_P.is_open())
191. cout << "Error del archivo4" << endl;
Anexo F. Código CUDA para la solución de transitorios de sistema eléctrico
aleatorio en la GPU
117
192.
193.
194. for (int i = 0; i < M; i++)
195. for (int j = 0; j < N*L * 2; j++)
196. archivo_P >> P[i][j];
197.
198.
199.
200. archivo_P.close();
201.
202.
203.
204. ifstream archivo_Pprima;
205. archivo_Pprima.open("C:\\Users\\Quartas\\Google Drive\\Maestría\
\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate_aleatorio
2\\Mate_aleatorio2_MATLAB\\Pprima.txt");
206.
207. //Comprobación de errores en apertura del archivo
208. if (!archivo_Pprima.is_open())
209. cout << "Error del archivo5" << endl;
210.
211.
212.
213. for (int i = 0; i < M; i++)
214. for (int j = 0; j < L * 2 * N; j++)
215. archivo_Pprima >> Pprima[i][j];
216.
217.
218.
219.
220. archivo_Pprima.close();
221.
222.
223.
224. ifstream archivo_Pabs;
225. archivo_Pabs.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\T
rabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate_aleatorio2\
\Mate_aleatorio2_MATLAB\\Pabs.txt");
226.
227. //Comprobación de errores en apertura del archivo
228. if (!archivo_Pabs.is_open())
229. cout << "Error del archivo6" << endl;
230.
231.
232. for (int i = 0; i < M; i++)
233. for (int j = 0; j < N*L * 2; j++)
234. archivo_Pabs >> Pabs[i][j];
235.
236.
237.
238. archivo_Pabs.close();
239.
240.
241. ifstream archivo_invZalpha;
242. archivo_invZalpha.open("C:\\Users\\Quartas\\Google Drive\\Maestr
ía\\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate_aleato
rio2\\Mate_aleatorio2_MATLAB\\invZalpha.txt");
243.
244. //Comprobación de errores en apertura del archivo
118 Simulación de transitorios electromagnéticos mediante programación de GPUs
245. if (!archivo_invZalpha.is_open())
246. cout << "Error del archivo7" << endl;
247.
248.
249. for (int i = 0; i < L * 2 * L * 2; i++)
250. archivo_invZalpha >> invZalpha[i];
251.
252.
253. archivo_invZalpha.close();
254.
255.
256. ifstream archivo_nod_UA;
257. archivo_nod_UA.open("C:\\Users\\Quartas\\Google Drive\\Maestría\
\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate_aleatorio
2\\Mate_aleatorio2_MATLAB\\nod_UA.txt");
258.
259. //Comprobación de errores en apertura del archivo
260. if (!archivo_nod_UA.is_open())
261. cout << "Error del archivo8" << endl;
262.
263.
264. for (int i = 0; i < L ; i++)
265. archivo_nod_UA >>nod_UA[i];
266.
267.
268. archivo_nod_UA.close();
269.
270. ifstream archivo_nod_UB;
271. archivo_nod_UB.open("C:\\Users\\Quartas\\Google Drive\\Maestría\
\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate_aleatorio
2\\Mate_aleatorio2_MATLAB\\nod_UB.txt");
272.
273. //Comprobación de errores en apertura del archivo
274. if (!archivo_nod_UB.is_open())
275. cout << "Error del archivo9" << endl;
276.
277.
278. for (int i = 0; i < L; i++)
279. archivo_nod_UB >> nod_UB[i];
280.
281.
282. archivo_nod_UB.close();
283.
284.
285. ifstream archivo_sist_UA;
286. archivo_sist_UA.open("C:\\Users\\Quartas\\Google Drive\\Maestría
\\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate_aleatori
o2\\Mate_aleatorio2_MATLAB\\sist_UA.txt");
287.
288. //Comprobación de errores en apertura del archivo
289. if (!archivo_sist_UA.is_open())
290. cout << "Error del archivo10" << endl;
291.
292.
293. for (int i = 0; i < L; i++)
294. archivo_sist_UA >> sist_UA[i];
295.
296.
297. archivo_sist_UA.close();
298.
299. ifstream archivo_sist_UB;
Anexo F. Código CUDA para la solución de transitorios de sistema eléctrico
aleatorio en la GPU
119
300. archivo_sist_UB.open("C:\\Users\\Quartas\\Google Drive\\Maestría
\\Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate_aleatori
o2\\Mate_aleatorio2_MATLAB\\sist_UB.txt");
301.
302. //Comprobación de errores en apertura del archivo
303. if (!archivo_sist_UB.is_open())
304. cout << "Error del archivo11" << endl;
305.
306.
307. for (int i = 0; i < L; i++)
308. archivo_sist_UB >> sist_UB[i];
309.
310.
311. archivo_sist_UB.close();
312.
313. double dispo[4] = 0 ;
314.
315. ifstream archivo_dispo;
316. archivo_dispo.open("C:\\Users\\Quartas\\Google Drive\\Maestría\\
Trabajo con Javier Herrera\\Tareas\\16. Códigos a validar\\Mate_aleatorio2
\\Mate_aleatorio2_MATLAB\\dispo.txt");
317.
318. //Comprobación de errores en apertura del archivo
319. if (!archivo_dispo.is_open())
320. cout << "Error del archivo12" << endl;
321.
322.
323. int rampa;
324. rampa = 100; //valor por fuera de los nodos, solo para verificar
si hay disponibilidad.
325.
326. for (int i = 0; i < N; i++) //Tomar solo primer sistema
327. archivo_dispo >> dispo[i];
328. if (dispo[i] == 0)
329. rampa = i;
330.
331.
332.
333. if (rampa == 100)
334. cout << "no hay nodos disponibles sistema 1 para Iramp" << e
ndl;
335.
336.
337. else if (rampa != 100)
338. cout << "Iramp estará conectada a nodo: " << rampa+1 << endl
;
339.
340.
341.
342. //Tiempo máximo de ejecución 35 ms
343. double deltat = tao / 10; //paso de tiempo definido como la deci
ma parte de tao
344. //cout << deltat << endl;
345.
346. double kmax = (0.0350) / deltat;
347. //cout << "Pasos son: "<<kmax << endl;
348.
349. double *d_I1[2000], *d_I2[2000]; //sistema de máximo 2000 enlac
es
120 Simulación de transitorios electromagnéticos mediante programación de GPUs
350.
351. for (int i = 0; i < L; i++)
352.
353. cudaMalloc(&d_I1[i], sizeof(double)*kmax);
354. cudaMalloc(&d_I2[i], sizeof(double)*kmax);
355.
356.
357.
358. //Tensiones asociadas a los extremos de línea
359.
360. double *U_A[2000], *U_B[2000]; //Máximo 2000 sistemas, 2000 enla
ces
361. for (int i = 0; i < L; i++)
362. U_A[i] = (double *)malloc(sizeof(double)*kmax);
363. U_B[i] = (double *)malloc(sizeof(double)*kmax);
364.
365.
366. for (int i = 0; i < L; i++)
367. for (int j = 0; j < kmax; j++)
368. U_A[i][j] = 0;
369. U_B[i][j] = 0;
370.
371.
372.
373.
374. double *dU_A[2000], *dU_B[2000]; //Máximo 2000 sistemas y 2000 e
nlaces
375. for (int i = 0; i < L; i++)
376. cudaMalloc(&dU_A[i], sizeof(double)*kmax);
377. cudaMalloc(&dU_B[i], sizeof(double)*kmax);
378.
379.
380. for (int i = 0; i < L; i++)
381. cudaMemcpy(dU_A[i], U_A[i], sizeof(double)*kmax, cudaMemcpyH
ostToDevice);
382. cudaMemcpy(dU_B[i], U_B[i], sizeof(double)*kmax, cudaMemcpyH
ostToDevice);
383.
384.
385. //Parámetro tiempo
386. double t = deltat;
387.
388. double ttao = (t - tao) / deltat;
389.
390. int k = 1;
391.
392. //Parámetro tao ya fue leído del archivo
393.
394. //Parámetro Zc ya fue leído del archivo
395.
396. //Corrientes asociadas a las líneas i12 e i21.
397.
398. double *i12[2000], *i21[2000]; //Máximo 2000 sistemas y 2000 enl
aces
399. for (int i = 0; i < L; i++)
400. i12[i] = (double *)malloc(sizeof(double)*kmax);
401. i21[i] = (double *)malloc(sizeof(double)*kmax);
402.
403.
404. for (int i = 0; i < L; i++)
405. for (int j = 0; j < kmax; j++)
Anexo F. Código CUDA para la solución de transitorios de sistema eléctrico
aleatorio en la GPU
121
406. i12[i][j] = 0;
407. i21[i][j] = 0;
408.
409.
410.
411.
412. double *d_i12[2000], *d_i21[2000]; //Máximo 2000 sistemas y 2000
enlaces
413. for (int i = 0; i < L; i++)
414. cudaMalloc(&d_i12[i], sizeof(double)*kmax);
415. cudaMalloc(&d_i21[i], sizeof(double)*kmax);
416.
417.
418. for (int i = 0; i < L; i++)
419. cudaMemcpy(d_i12[i], i12[i], sizeof(double)*kmax, cudaMemcpy
HostToDevice);
420. cudaMemcpy(d_i21[i], i21[i], sizeof(double)*kmax, cudaMemcpy
HostToDevice);
421.
422.
423. //Corrientes de inyección
424.
425. double *dI_iny[2000]; //máximo 2000 subsistemas
426.
427. for (int i = 0; i < M; i++)
428.
429. cudaMalloc(&dI_iny[i], sizeof(double)*N);
430.
431.
432. double Iramp;
433. //Pasar las matrices inversas InvA e InvB a la GPU
434. double *d_invA, *d_invB;
435. cudaMalloc(&d_invA, sizeof(double)*N*N);
436. cudaMalloc(&d_invB, sizeof(double)*N*N);
437. cudaMemcpy(d_invA, invA, sizeof(double)*N*N, cudaMemcpyHostToDev
ice);
438. cudaMemcpy(d_invB, invB, sizeof(double)*N*N, cudaMemcpyHostToDev
ice);
439.
440. // dEa, una única variables dEa[sistema][nodo]
441. double *d_Ea[2000]; //máximo 2000 sistemas
442.
443. for (int i = 0; i < M; i++)
444.
445. cudaMalloc(&d_Ea[i], sizeof(double)*N);
446.
447.
448. //dEalpha_temp es cada una de las partes de Ealpha asociada a ca
da sistema, las cuales al final se sumarán
449. double *dEalpha_temp[2000]; //Máximo 2000 sistemas
450.
451. for (int i = 0; i < M; i++)
452.
453. cudaMalloc(&dEalpha_temp[i], sizeof(double)*L * 2);
454.
455.
456. //Transfiero Pprima a la GPU
457.
458. double *d_Pprima[2000]; //máximo 2000 sistemas
122 Simulación de transitorios electromagnéticos mediante programación de GPUs
459.
460. for (int i = 0; i < M; i++)
461.
462. cudaMalloc(&d_Pprima[i], sizeof(double)*L * 2 * N);
463.
464.
465. for (int i = 0; i < M; i++)
466. cudaMemcpy(d_Pprima[i], Pprima[i], sizeof(double)*L * 2 * N,
cudaMemcpyHostToDevice);
467.
468.
469.
470. //Ealpha total
471.
472. double *dEalpha;
473. cudaMalloc(&dEalpha, L * 2 * sizeof(double));
474.
475. //Ialpha
476.
477. double *dIalpha;
478. cudaMalloc(&dIalpha, L * 2 * sizeof(double));
479.
480. //Transferir invZalpha a GPU
481.
482. double *d_invZalpha;
483. cudaMalloc(&d_invZalpha, sizeof(double)*L * 2 * L * 2);
484. cudaMemcpy(d_invZalpha, invZalpha, sizeof(double)*L * 2 * L * 2,
cudaMemcpyHostToDevice);
485.
486. //Ianuevo
487.
488. double *d_Ianuevo[2000]; //máximo 2000 subsistemas
489.
490. for (int i = 0; i < M; i++)
491.
492. cudaMalloc(&d_Ianuevo[i], sizeof(double)*N);
493.
494.
495. //Transferir P a GPU
496.
497. double *d_P[2000]; //máximo 2000 sistemas
498.
499. for (int i = 0; i < M; i++)
500.
501. cudaMalloc(&d_P[i], sizeof(double)* N*L * 2);
502.
503.
504. for (int i = 0; i < M; i++)
505. cudaMemcpy(d_P[i], P[i], sizeof(double) *N*L * 2, cudaMemcpy
HostToDevice);
506.
507.
508.
509. //Transferir Pabs a GPU
510.
511. double *d_Pabs[2000]; //máximo 2000 sistemas
512.
513. for (int i = 0; i < M; i++)
514.
515. cudaMalloc(&d_Pabs[i], sizeof(double)* N*L * 2);
516.
Anexo F. Código CUDA para la solución de transitorios de sistema eléctrico
aleatorio en la GPU
123
517.
518. for (int i = 0; i < M; i++)
519. cudaMemcpy(d_Pabs[i], Pabs[i], sizeof(double) *N*L * 2, cuda
MemcpyHostToDevice);
520.
521.
522.
523. //Eanuevo
524.
525. double *d_Eanuevo[2000]; //máximo 2000 subsistemas
526.
527. for (int i = 0; i < M; i++)
528.
529. cudaMalloc(&d_Eanuevo[i], sizeof(double)*N);
530.
531.
532. //Sist U_A, sist U_B, nod U_A y nod U_B
533.
534. double *dsist_UA, *dsist_UB, *dnod_UA, *dnod_UB;
535. cudaMalloc(&dsist_UA, L* sizeof(double));
536. cudaMalloc(&dsist_UB, L * sizeof(double));
537. cudaMalloc(&dnod_UA, L * sizeof(double));
538. cudaMalloc(&dnod_UB, L * sizeof(double));
539.
540. cudaMemcpy(dsist_UA, sist_UA, sizeof(double) *L, cudaMemcpyHostT
oDevice);
541. cudaMemcpy(dsist_UB, sist_UB, sizeof(double) *L, cudaMemcpyHostT
oDevice);
542. cudaMemcpy(dnod_UA, nod_UA, sizeof(double) *L, cudaMemcpyHostToD
evice);
543. cudaMemcpy(dnod_UB, nod_UB, sizeof(double) *L, cudaMemcpyHostToD
evice);
544.
545. //Vector para todas las I de las líneas, usado para el cálculo d
e las corrientes de inyección
546. double *d_Ilineas; //máximo 2000 enlaces
547. cudaMalloc(&d_Ilineas, sizeof(double)*L*2);
548.
549. int sist_A = 0;
550. int sist_B = 0;
551.
552.
553.
554. printf("Primer valor \n");
555. auto start = high_resolution_clock::now();
556. while (t < 0.035) //35ms es el tiempo máximo de cálculo
557.
558. if (t <= 100 * deltat)
559. Iramp = t / (100 * deltat) * 10000;
560.
561. else
562. Iramp = 0;
563.
564.
565. threadsPerBlock.x = 1;
566.
567. for (int i = 0; i < L; i++)
124 Simulación de transitorios electromagnéticos mediante programación de GPUs
568. func1 << <blocksPerGrid, threadsPerBlock, 0, stream[i] >
> > (k, ttao, Zc, dU_A[i], dU_B[i], d_i12[i], d_i21[i], d_I1[i], d_I2[i]);
569.
570. cudaDeviceSynchronize();
571.
572.
573. int h = 0;
574. for (int i = 0; i < L ; i++)
575. for (int j = 0; j < 2; j++)
576. //cout << "paso " << j<< endl;
577. func7 << <blocksPerGrid, threadsPerBlock, 0, stream[
i] >> > (i, j, h, k, d_I1[i], d_I2[i], d_Ilineas);
578. h = h + 1;
579.
580.
581.
582.
583.
584. cudaDeviceSynchronize();
585.
586.
587. //Cálculo de las corrientes de inyección
588.
589. threadsPerBlock.x = N;
590.
591. for (int i = 0; i < M; i++)
592. func3 << <blocksPerGrid, threadsPerBlock, 0, stream[i] >
> > (d_Pabs[i], d_Ilineas, dI_iny[i], L*2, N);
593.
594.
595. func3_1 << <blocksPerGrid, threadsPerBlock, 0, stream[0] >>
> (rampa, dI_iny[0], Iramp);
596.
597. cudaDeviceSynchronize();
598.
599. //Cálculo de Ea
600.
601. threadsPerBlock.x = N; //invA es una matriz 4x4
602.
603. for (int i = 0; i < M; i++)
604. if (i == 0)
605. func3 << <blocksPerGrid, threadsPerBlock, 0, stream[
i] >> > (d_invA, dI_iny[i], d_Ea[i], N, N);
606.
607. if (i != 0)
608. func3 << <blocksPerGrid, threadsPerBlock, 0, stream[
i] >> > (d_invB, dI_iny[i], d_Ea[i], N, N);
609.
610.
611.
612.
613. cudaDeviceSynchronize();
614.
615. //Cálculo de Ealpha
616.
617. threadsPerBlock.x = L * 2; //Pprima es una matriz de orden L
x2
618.
619. for (int i = 0; i < M; i++)
Anexo F. Código CUDA para la solución de transitorios de sistema eléctrico
aleatorio en la GPU
125
620. func3 << <blocksPerGrid, threadsPerBlock, 0, stream[i] >
> > (d_Pprima[i], d_Ea[i], dEalpha_temp[i], N, L * 2);
621.
622.
623. cudaDeviceSynchronize();
624.
625.
626. for (int i = 0; i < M; i++)
627. if (i == 0)
628. func4_1 << <blocksPerGrid, threadsPerBlock, 0, strea
m[0] >> > (dEalpha_temp[i], dEalpha, L * 2);
629.
630. if (i != 0)
631. func4_2 << <blocksPerGrid, threadsPerBlock, 0, strea
m[0] >> > (dEalpha_temp[i], dEalpha, L * 2);
632.
633.
634.
635.
636. cudaDeviceSynchronize();
637.
638. //Cálculo de Ialpha
639.
640. func3 << <blocksPerGrid, threadsPerBlock, 0, stream[1] >> >
(d_invZalpha, dEalpha, dIalpha, L * 2, L * 2);
641.
642. cudaDeviceSynchronize();
643.
644. //Cálculo de Ia nuevo
645.
646. threadsPerBlock.x = N; //P es de orden N* (Lx2)
647.
648. for (int i = 0; i < M; i++)
649. func5 << <blocksPerGrid, threadsPerBlock, 0, stream[i] >
> > (d_P[i], dIalpha, dI_iny[i], d_Ianuevo[i], N, L * 2);
650.
651.
652. cudaDeviceSynchronize();
653.
654. //Cálculo de Eanuevo
655.
656. for (int i = 0; i < M; i++)
657. if (i == 0)
658. func3 << <blocksPerGrid, threadsPerBlock, 0, stream[
i] >> > (d_invA, d_Ianuevo[i], d_Eanuevo[i], N, N);
659.
660. if (i != 0)
661. func3 << <blocksPerGrid, threadsPerBlock, 0, stream[
i] >> > (d_invB, d_Ianuevo[i], d_Eanuevo[i], N, N);
662.
663.
664.
665.
666. cudaDeviceSynchronize();
667.
668. threadsPerBlock.x = 1;
669. for (int i = 0; i < L; i++)
670. sist_A = int(sist_UA[i]);
671. sist_B = int(sist_UB[i]);
126 Simulación de transitorios electromagnéticos mediante programación de GPUs
672. //cout << "sist A " << sist_A<<endl;
673. func6_1<< <blocksPerGrid, threadsPerBlock, 0, stream[i]
>> > (dU_A[i], dU_B[i],d_i12[i], d_i21[i], d_Eanuevo[sist_A], d_Eanuevo[si
st_B], d_I1[i], d_I2[i], Zc, k, nod_UA[i], nod_UB[i]);
674.
675.
676.
677. cudaDeviceSynchronize();
678.
679.
680.
681. t = t + deltat;
682. k = k + 1;
683. ttao = (t - tao) / deltat;
684.
685.
686. auto stop = high_resolution_clock::now();
687. auto duration = duration_cast<microseconds>(stop - start);
688. cout << " con " << M << " sistemas" << endl;
689. cout << " con " << L << " enlaces" << endl;
690. cout << " Tiempo de ejecucion " << duration.count() << " microse
conds" << endl;
691.
692.
693. for (int i = 0; i < L; i++)
694. cudaMemcpy(U_A[i], dU_A[i], sizeof(double)*kmax, cudaMemcpyD
eviceToHost);
695. cudaMemcpy(U_B[i], dU_B[i], sizeof(double)*kmax, cudaMemcpyD
eviceToHost);
696.
697.
698. //Se crean un solo archivo, una columna para U_A y otra para U_B
699.
700. FILE *fp;
701. fp = fopen("CUDA_Ulinea.txt", "w");
702.
703. for (int i = 0; i < L; i++)
704. for (int j = 0; j < kmax; j++)
705. fprintf(fp, "%f %f\n", U_A[i][j], U_B[i][j]);
706.
707.
708.
709.
710.
711. fclose(fp);
712.
713.
714. printf("último valor \n");
715. cudaDeviceReset();
716. return 0;
717.
G. Anexo 7: Código en MATLAB para la solución de transitorios de sistema eléctrico aleatorio en la CPU
1. %Antes de ejecutar este programa se debe haber ejecutado el de generación
2. clc 3. 4. k=1; %Contador de posiciones para almacenar los datos 5. t=0; %Se inicia el tiempo 6. 7. U_A=zeros(L,kmax); 8. U_B=zeros(L,kmax); 9. i12=zeros(L,kmax); 10. i21=zeros(L,kmax); 11. 12. tmax=35e-3; %tiempo máximo de simulación 13. t=t+deltat; 14. k=k+1; 15. 16. rampa=100; 17. for i=1:N 18. if dispo(1,i)==0 19. rampa=i; 20. end 21. end 22. if rampa==100 23. disp("no hay nodos disponibles sistema 1 para Iramp") 24. elseif rampa~=100 25. fprintf("Iram estará conectada a nodo %d\n",rampa); 26. end 27. 28. tic 29. while (t<=tmax) 30. ttao=((t-tao)/deltat+1); %Indicador de posición para cada línea, t-
tao
31. 32. 33. %Fuente rampa 34. if t< 100*deltat 35. ramp(k)=t/(100*deltat)*10000; 36. else 37. ramp(k)=0; 38. end 39. %cálculo corrientes de línea 40.
128 Simulación de transitorios electromagnéticos mediante programación de GPUs
41. 42. for i=1:L 43. if ttao<1 44. I1(i,k)=0; 45. I2(i,k)=0; 46. elseif ttao>=1 47. I1(i,k)=-(U_B(i,round(ttao))/Zc+i21(i,round(ttao))); 48. I2(i,k)=-(U_A(i,round(ttao))/Zc+i12(i,round(ttao))); 49. end 50. end 51. 52. %Armo vector Ilineas para corrientes de inyección 53. h=1; 54. for i=1:L 55. for j=1:2 56. if j==1 57. Ilineas(h)=-I1(i,k); 58. elseif j==2 59. Ilineas(h)=-I2(i,k); 60. end 61. h=h+1; 62. end 63. end 64. 65. for i=1:M 66. I_iny(:,i)=Pabs(:,:,i)*(Ilineas'); 67. end 68. 69. I_iny(rampa,1)=ramp(k); 70. 71. %calculo de Ea 72. for i=1:M 73. Ea(:,i)=invA*I_iny(:,i); 74. end 75. 76. %calculo de Ealpha 77. 78. Ealpha= zeros(L*2,1); 79. 80. for i=1:M 81. Ealpha=Pprima(:,:,i)*Ea(:,i)+Ealpha; 82. end 83. Ialpha= invZalpha*Ealpha; 84. 85. for i=1:M 86. if i==1 87. Eanuevo(:,i)=invA*(I_iny(:,i)-P(:,:,i)*Ialpha); 88. else 89. Eanuevo(:,i)=invB*(I_iny(:,i)-P(:,:,i)*Ialpha); 90. end 91. end 92. 93. %Actualización de parámetros 94. 95. for i=1:L 96. 97. U_A(i,k)=Eanuevo(nod_UA(i)+1,sist_UA(i)+1); 98. U_B(i,k)=Eanuevo(nod_UB(i)+1,sist_UB(i)+1); 99. i12(i,k)= U_A(i,k)/Zc+I1(i,k); 100. i21(i,k)= U_B(i,k)/Zc+I2(i,k);
101.
Anexo G. Código MATLAB para la solución de transitorios de sistema
eléctrico aleatorio en la CPU
129
102. end
103.
104.
105. t=t+deltat;
106. k=k+1;
107. end
108. toc
109. M
110. L
111.
112. U_A(:,kmax+1)=[];
113. U_B(:,kmax+1)=[];
114.
115. figure(1)
116. hold on
117. plot(t2,U_A(1,:),'r');
118. figure(2)
119. hold on
120. plot(t2,U_B(1,:),'r');
H. Anexo 8: Código en MATLAB para la generación de sistemas eléctricos aleatorios
1. %Código para la generación aleatoria de sistemas de topología variada. 2. %Se emplean dos tipos de sistemas, A y B 3. clear all 4. close all 5. clc 6. tic 7. %Sistema A Conformado por resistencias 8. Ra12=20; 9. Ra23=10; 10. Ra34=2.5; 11. Ra14=5; 12. Ra4=2; 13. %Se calculan admitancias del sistema A 14. Ga12=1/Ra12; 15. Ga23=1/Ra23; 16. Ga34=1/Ra34; 17. Ga14=1/Ra14; 18. Ga4=1/Ra4; 19. 20. A=[Ga12+Ga14 -Ga12 0 -Ga14;-Ga12 Ga12+Ga23 -Ga23 0;0 -Ga23 Ga23+Ga34 -Ga34;-Ga14 0 -
Ga34 Ga14+Ga34+Ga4]; %Matriz de admitancia sistema A 21. invA= inv(A); 22. %Sistema B Conformado por resistencias 23. Rb12=7; 24. Rb23=5; 25. Rb34=2; 26. Rb14=10; 27. Rb4=8; 28. %Se calculan admitancias del sistema B 29. Gb12=1/Rb12; 30. Gb23=1/Rb23; 31. Gb34=1/Rb34; 32. Gb14=1/Rb14; 33. Gb4=1/Rb4; 34. 35. B=[Gb12+Gb14 -Gb12 0 -Gb14;-Gb12 Gb12+Gb23 -Gb23 0;0 -Gb23 Gb23+Gb34 -Gb34;-Gb14 0 -
Gb34 Gb14+Gb34+Gb4];%Matriz de admitancia sistema B 36. invB= inv(B); 37. %Solo se considera un tipo de línea 38. 39. long=60; %km 40. Zc=200; 41. vel=300000; 42. tao=long/vel; 43. deltat=tao/10;
132 Simulación de transitorios electromagnéticos mediante programación de GPUs
44. 45. prompt = 'Número de sistemas = enlaces '; 46. L=input(prompt); %número de enlaces 47. M =L; %número de sistemas 48. N=4; %Número de nodos 49. 50. if L*2>M*N 51. error('el número de sistemas excede la cantidad de nodos disponibles') 52. end 53. 54. %Defino P con todas las entradas cero, luego cambio algunos para definir 55. %enlaces. 56. 57. for i=1:M 58. P(:,:,i)=zeros(N,L*2); 59. end 60. 61. dispo = zeros(M, N); 62. c=1; %contador para recorrer todos los sistemas 63. k=randi([1,N]); %aleatorio para seleccionar nodo 64. h=1; %contador columna, para los +1 es de dos en dos columnas 65. for i=1:L 66. 67. if (dispo(c,k)==0) 68. P(k,h,c)=1; 69. dispo(c,k)=1; 70. 71. elseif dispo(c,k)~=0 72. while dispo(c,k)~=0 73. k=randi([1,N]); 74. end 75. P(k,h,c)=1; 76. dispo(c,k)=1; 77. end 78. dispo; 79. sist_UA(i)=c-1; %En CUDA los indices comienzan desde cero. 80. nod_UA(i)=k-1; 81. 82. c=c+1; 83. if c==M+1 84. c=1; 85. end 86. 87. k=randi([1,N]); 88. dispo; 89. h=h+2; 90. 91. end 92. 93. % columna 2 es para -1 y columna 1 es para +1 y así sucesivamente. Se llena cada dos 94. 95. %Debo asignar los -1 en sistema aleatorio para cada enlace. 96. 97. h=2; 98. c=randi([1,M]); 99. k=randi([1,N]); 100. s=1; 101. 102. for i=1:L 103. while c==s
Anexo H. Código MATLAB para la generación aleatoria de sistemas eléctricos 133
104. c=randi([1,M]); 105. end 106. if dispo(c,k)==0 107. P(k,h,c)=-1; 108. dispo(c,k)=1; 109. elseif dispo(c,k)~=0 110. while dispo(c,k)~=0 111. k=randi([1,N]); 112. c=randi([1,M]); 113. while c==s 114. c=randi([1,M]); 115. end 116. 117. end 118. P(k,h,c)=-1; 119. dispo(c,k)=1; 120. end 121. sist_UB(i)=c-1; 122. nod_UB(i)=k-1; 123. h=h+2; 124. k=randi([1,N]); 125. c=randi([1,M]); 126. 127. s=s+1; 128. if s==M+1 129. s=1; 130. end 131. 132. %como evitar que dos enlaces lleguen al mismo nodo, se crea variable s 133. %pues el +1 fue asignado de sistema en sistema en orden, c puede ser 134. %cualquier sistema menos el correspondiente a s 135. 136. 137. end 138. 139. %Matrices usadas para Zalpha considero que el primer sistema es tipo A y el 140. %resto tipo B 141. for i=1:M 142. if i==1 143. a(:,:,i)=invA*P(:,:,i); 144. else 145. a(:,:,i)= invB*P(:,:,i); 146. end 147. end 148. %Calculo de Z 149. Z=diag(ones(L*2,1)*Zc); 150. 151. %Cálculo de Zalpha 152. Zalpha1= zeros(L*2,L*2); 153. for i=1:M 154. Zalpha1= P(:,:,i)'*a(:,:,i)+Zalpha1; 155. end 156. Zalpha =Zalpha1 + Z; 157. invZalpha=inv(Zalpha); 158. 159. for i=1:M 160. Pprima(:,:,i)=P(:,:,i)'; 161. end 162.
134 Simulación de transitorios electromagnéticos mediante programación de GPUs
163. for i=1:M 164. Pabs(:,:,i)=abs(P(:,:,i)); 165. end 166. 167. param=[M L N Zc tao]; 168. fileID = fopen('param.txt','w'); 169. fprintf(fileID, '%f\n',param); 170. fclose(fileID); 171. 172. fileID = fopen('invA.txt','w'); 173. for i=1:N 174. for j=1:N 175. fprintf(fileID,'%f\n', invA(i,j)); 176. end 177. 178. end 179. fclose(fileID); 180. 181. 182. fileID = fopen('invB.txt','w'); 183. for i=1:N 184. for j=1:N 185. fprintf(fileID,'%f\n', invB(i,j)); 186. end 187. end 188. fclose(fileID); 189. 190. fileID = fopen('P.txt','w'); 191. for i=1:M 192. for j=1:N 193. for k=1:L*2 194. fprintf(fileID,'%f\n', P(j,k,i)); 195. end 196. end 197. end 198. fclose(fileID); 199. 200. fileID = fopen('Pprima.txt','w'); 201. for i=1:M 202. for j=1:L*2 203. for k=1:N 204. fprintf(fileID,'%f\n', Pprima(j,k,i)); 205. end 206. end 207. end 208. 209. fileID = fopen('Pabs.txt','w'); 210. for i=1:M 211. for j=1:N 212. for k=1:L*2 213. fprintf(fileID,'%f\n', Pabs(j,k,i)); 214. end 215. end 216. end 217. fclose(fileID); 218. 219. fileID = fopen('invZalpha.txt','w'); 220. for i=1:L*2 221. for j=1:L*2 222. fprintf(fileID,'%f\n', invZalpha(i,j));
Anexo H. Código MATLAB para la generación aleatoria de sistemas eléctricos 135
223. end 224. end 225. fclose(fileID); 226. 227. fileID = fopen('sist_UA.txt','w'); 228. for i=1:L 229. fprintf(fileID,'%f\n', sist_UA(i)); 230. end 231. 232. fclose(fileID); 233. 234. 235. fileID = fopen('sist_UB.txt','w'); 236. for i=1:L 237. fprintf(fileID,'%f\n', sist_UB(i)); 238. end 239. 240. fclose(fileID); 241. 242. fileID = fopen('nod_UA.txt','w'); 243. for i=1:L 244. fprintf(fileID,'%f\n', nod_UA(i)); 245. end 246. 247. fclose(fileID); 248. 249. fileID = fopen('nod_UB.txt','w'); 250. for i=1:L 251. fprintf(fileID,'%f\n', nod_UB(i)); 252. end 253. 254. fclose(fileID); 255. 256. fileID = fopen('dispo.txt','w'); 257. for i=1:M 258. for j=1:N 259. fprintf(fileID,'%f\n', dispo(i,j)); 260. end 261. end 262. fclose(fileID); 263. 264. %Grafica de resultados de CUDA 265. %Espera mientras el código se ejecuta en C++, el usuario deberá presionar 266. %cualquier tecla 2 veces para continuar 267. toc 268. disp("Pausa, ejecute el código en CUDA y luego regrese, debe presionar cualquier tecla 2 veces") 269. for ind = 1:2 270. pause; 271. disp(ind); 272. end 273. 274. deltat=tao/10; 275. kmax=35e-3/deltat; 276. 277. fidi = fopen('C:\Users\Quartas\Google Drive\Maestría\Trabajo con Javier Herrera\Tareas\16. Códigos
a validar\Mate_aleatorio2\Mate_aleatorio2_CUDA\Mate_aleatorio2\CUDA_Ulinea.txt','r'); 278. U = textscan(fidi, '%f %f'); 279. 280. fclose(fidi);
136 Simulación de transitorios electromagnéticos mediante programación de GPUs
281. 282. uA=U1; 283. uB=U2; 284. 285. h=1; 286. for i=1:L 287. for j=1:kmax 288. U_A(i,j)=uA(h); 289. U_B(i,j)=uB(h); 290. h=h+1; 291. end 292. end 293. 294. t2=[0:deltat:35e-3-deltat]; 295. figure(1) 296. plot(t2, U_A(1,:)) 297. title('\bfVoltaje vs Tiempo CUDA U_A1') 298. xlabel('Tiempo') 299. ylabel('Voltaje') 300. 301. figure(2) 302. plot(t2, U_B(1,:)) 303. title('\bfVoltaje vs Tiempo CUDA U_B1') 304. xlabel('Tiempo') 305. ylabel('Voltaje')
Bibliografía
[1] J. Bélanger, P. Venne, and J. Paquin, “The What, Where and Why of Real-Time
Simulation,” Planet RT, pp. 37–49, 2010.
[2] V. Jalili-Marandi and V. Dinavahi, “Large-scale transient stability simulation on
graphics processing units,” 2009 IEEE Power Energy Soc. Gen. Meet. PES ’09, pp.
1–6, 2009, doi: 10.1109/PES.2009.5275844.
[3] P. Zhang, J. R. Martí, and H. W. Dommel, “Network Partitioning for Real-time Power
System Simulation,” Network, pp. 1–6, 2005.
[4] J. Martinez-Velasco, “Real time simulation technologies in Engineering,” Wiley-IEEE
Press, p. 648, 2014.
[5] S. Cieslik, “GPU Implementation of the Electric Power System Model for Real-Time
Simulation of Electromagnetic Transients,” no. January 2013, pp. 1–6, 2013, doi:
10.2991/iccsee.2013.279.
[6] L. Chen, Y. Chen, Y. Xu, and Y. Gong, “A novel algorithm for parallel electromagnetic
transient simulation of power systems with switching events,” 2010 Int. Conf. Power
Syst. Technol., no. 1, pp. 1–7, 2010, doi: 10.1109/POWERCON.2010.5666405.
[7] F. A. Moreira, J. R. Martí, L. C. Zanetta, and L. R. Linares, “Multirate simulations with
simultaneous-solution using direct integration methods in a partitioned network
environment,” IEEE Trans. Circuits Syst. I Regul. Pap., vol. 53, no. 12, pp. 2765–
2778, 2006, doi: 10.1109/TCSI.2006.882821.
[8] J. Martí and L. Linares, “OVNI: Integrated software/hardware solution for real-time
simulation of large power systems,” Proc. PSCC, no. June, pp. 1–7, 2002.
[9] M. A. Tomim, T. De Rybel, and J. R. Martí, “Extending the Multi-Area Thévenin
Equivalents method for parallel solutions of bulk power systems,” Int. J. Electr. Power
Energy Syst., vol. 44, no. 1, pp. 192–201, 2013, doi: 10.1016/j.ijepes.2012.07.037.
[10] F. A. Moreira, J. R. Martí, L. C. Zanetta, and L. R. Linares, “Multirate simulations with
simultaneous-solution using direct integration methods in a partitioned network
environment,” IEEE Trans. Circuits Syst. I Regul. Pap., vol. 53, no. 12, pp. 2765–
2778, 2006, doi: 10.1109/TCSI.2006.882821.
138 Simulación de transitorios electromagnéticos mediante programación de GPUs
[11] NVIDIA, “Procesamiento paralelo CUDA,” 2017. [Online]. Available:
http://www.nvidia.es/object/cuda-parallel-computing-es.html.
[12] NVIDIA, “Aceleración computacional,” 2017. [Online]. Available:
http://www.nvidia.es/object/gpu-computing-es.html.
[13] Y. Tang, L. Wan, and J. Hou, “Full electromagnetic transient simulation for large
power systems,” Glob. Energy Interconnect., vol. 2, no. 1, pp. 29–36, 2019, doi:
10.1016/j.gloei.2019.06.004.
[14] T. Strasser, “Real-Time Simulation Technologies for Power Systems Design ,
Testing , and Analysis,” IEEE Power Energy Technol. Syst. J., vol. 2, no. 2, pp. 63–
73, 2015.
[15] S. Santoso, Fundamentals of Electrical Power Quality. Austin: The University of
texas at Austin, 2012.
[16] R. Bansal and P. T. Manditereza, “Fault Analysis,” Power Syst. Prot. Smart Grid
Environ., pp. 33–79, 2019, doi: 10.1201/9780429401756-2.
[17] K. Karimi, N. G. Dickson, and F. Hamze, “A Performance Comparison of CUDA and
OpenCL,” no. 1, 2010.
[18] T. Sörman, “Comparison of Technologies for Computing on Graphics Processing
Units,” 2016.
[19] NVIDIA, “Cuda C Programming Guide,” Program. Guid., no. September, pp. 1–261,
2015.
[20] C.-W. HO, A. E. Ruehli, and P. A. Brennan, “The Modified Nodal Approach to
Network Analysis,” Proc. IEEE, vol. 73, no. 3, pp. 485–487, 1975, doi:
10.1109/PROC.1985.13168.
[21] J. Martinez-Velasco, Coordinación de aislamiento en redes eléctricas de Alta y Extra
Alta tensión, 1st ed. Matrid: McGraw-Hill, 2007.
[22] L. H-restrepo, G. Caicedo, and F. Castro-aranda, “Modelos de línea de transmisión
para transitorios electromagnéticos en sistemas de potencia,” vol. 16, no. 1, pp. 21–
32, 2008.
[23] H. W. Dommel and W. S. Meyer, “Computation of Electromagnetic Transients,” Proc.
IEEE, vol. 62, no. 7, pp. 983–993, 1974, doi: 10.1109/PROC.1974.9550.
[24] EEUG, “ATP/EMTP,” 2020. [Online]. Available: https://www.emtp.org/.
[25] A. Gray and J. Perry, “Learn CUDA in an Afternoon : Hands-on Practical Exercises
Getting Started with CUDA,” pp. 1–5.
Bibliografía 139
[26] C. Pérez Represa, J. M. Cámara Nebreda, and P. L. Sánchez Ortega, “Introducción
a la programación en CUDA,” Univ. Burgos, 2016.
[27] J. Larkin, “GPU fundamentals,” NVIDIA, 2016.
[28] J. Luitjens, “CUDA Streams: Best Practices and Common Pitfalls,” GPU Technol.
Conf., 2014.
[29] NVIDIA, “CUDA Enabled GPUs,” 2020. [Online]. Available:
https://developer.nvidia.com/cuda-gpus.
top related