Meep: Fuente Continua y Punta – Simulación

Para continuar con la serie de artículos del Meep se presenta la primera fuente para poder realizar una simulación más acorde con lo que se quiere hacer, una fuente es simplemente una emisión del campo electromagnético, en Meep una fuente es separable en espacio y tiempo y es calculada por medio de las ecuaciones de Maxwell cada vez que exista un paso en el tiempo.

Existen tres tipos de fuentes en Meep que se enlistan a continuación:

  • Fuente Continua: Se refiere a una onda continua puede ser prendida o apagada y tiene propiedades como frecuencia, tiempo de inicio, tiempo final y ancho.
  • Fuente Gaussiana: Un pulso gaussiano que básicamente es el derivado en el tiempo de la función gaussiana, tiene propiedades como la frecuencia, el ancho, el tiempo de inicio y el numero de corte.
  • Fuente Personalizada: Es donde el usuario especifica una función como fuente y tiene propiedades como tiempo de inicio y tiempo final.

A continuación se enlistan los cambios necesarios para agregar una fuente continua y al mismo tiempo utilizando la figura geométrica de la punta para ver el comportamiento y la tendencia de la onda.

Primero que nada se declara la fuente continua para lo cual se define la frecuencia, el ancho, el tiempo de inicio y el tiempo final, el código correspondiente se enlista a continuación:

punta.cpp

double freq = 0.5, fwidth = 0.5;
double start_time = 0, end_time = 100;
continuous_src_time src(freq, fwidth, start_time, end_time);

Una vez que se tiene declarada la fuente continua con todos sus parámetros, se procede a agregar la fuente a la clase field que contiene la estructura general en donde a su vez contiene la malla y la función para la geometría, para agregar la fuente en forma de punto en el componente Ez se utiliza el siguiente código:

punta.cpp

field.add_point_source(Ez, src, vec(2, -4.5));

En la declaración se define el componente, en este caso Ez, a continuación la fuente continua que ya se había declarado y para finalizar se define un punto en donde la fuente vivirá por medio de un vector.

A continuación se define el archivo HDF5 en donde se guardarán todos los datos para después generar imágenes o videos a partir de los datos. La manera en que Meep funciona es que utiliza todo un mecanismo interno para por medio de una serie de herramientas generar datos en formato HDF5, dichos datos contienen el épsilon de cada material en cada punto de la malla, dichos datos y por medio de algunas utilerias del MIT son convertidos a distintos formatos para volverse gráficos, a continuación se enlista el código para definir un archivo personalizado de HDF5 por medio de la librería de Meep:

punta.cpp

h5file *h5_file = field.open_h5file("ez", h5file::WRITE, "", true);

Los parámetros que se definen para crear y abrir el archivo en formato HDF5 son: primero el nombre del archivo, el modo en que el archivo se abrirá, un prefijo para el archivo y si se define un identificador de tiempo.

A continuación se define el ciclo de tiempo que generara los datos HDF5 y la forma en que se guardan en el archivo que se acaba de crear:

punta.cpp

while (field.time() < field.last_source_time()) {
    field.output_hdf5(Ez, grid_vol.surroundings(), h5_file, true, false, "");
    field.step();
}

El ciclo básicamente le dice a la clase field que haga pequeños pasos por default de .1 en C++ desde el tiempo de inicio de la simulación definido y hasta el tiempo final, dentro del ciclo se define un output en donde se especifica el componente, el volumen, el archivo que se acaba de crear en modo de escritura, una bandera para definir si se agregan los datos o se crean un archivo HDF5 cada vez, si se tendrá soporte de precisión y por último algún prefijo deseado.

A continuación se enlista el código de la simulación completo:

punta.cpp

#include <meep.hpp>
#include <iostream>
using namespace meep;
 
double PuntaObject(const vec &p) {
    if ((p.x() >= 0 && p.x() <= 4) && (p.y() >= -4 && p.y() <= 8))     {
        if (p.x() == 2 && p.y() == 4)
            return 1.0;
 
        // define area for end point
        if (p.y() >= 4)      {
            if (p.x() <= (p.y()/2)-2)
                return 1.0;
 
            if (p.x() >= (p.y()/2)-(p.y()-6))
                return 1.0;
        }
 
        return 8.0;
    }
    return 1.0;
}
 
int main(int argc, char **argv) {
    meep::initialize mpi(argc, argv);   // Do this even for non-MPI Meep
    double resolution = 10;             // pixels per distance
    const double pml_thickness = 1.0;
    const double x = 30 + pml_thickness;
    const double y = 30 + pml_thickness;
 
    grid_volume grid_vol = vol2d(x, y, resolution);  // 30x30 2d cell
    grid_vol.center_origin();                        // set the origin as the center of cell
 
    structure strct(grid_vol, PuntaObject, pml(pml_thickness));  // structure punta
    fields field(&strct);
    field.use_real_fields();     // this is for optimization purposes
    field.output_hdf5(Dielectric, grid_vol.surroundings());
 
    double freq = 0.5, fwidth = 0.5;
    double start_time = 0, end_time = 100;
    continuous_src_time src(freq, fwidth, start_time, end_time);
    field.add_point_source(Ez, src, vec(2, -4.5));
 
    h5file *h5_file = field.open_h5file("ez", h5file::WRITE, "", true);
    while (field.time() < field.last_source_time()) {
        field.output_hdf5(Ez, grid_vol.surroundings(), h5_file, true, false, "");
        field.step();
    }
    return 0;
}

Para ejecutar la simulación anterior es necesario crear un shell script en donde se especifican algunos paquetes que ayudaran en la conversión de datos en formato HDF5 a formato de imagen así como también hará todo el compilado del código anterior y la generación de la animación para obtener los resultados deseados, para el caso anterior y suponiendo que el programa se llama punta.cpp se crea el siguiente archivo bash:

make punta.dac
./punta.dac

h5ls eps-000000.00.h5
h5ls ez-000000.00.h5
h5topng -Zc dkbluered eps-000000.00.h5
h5topng -t 0:1999 -R -Zc dkbluered -a yarg -A eps-000000.00.h5 ez-000000.00.h5
convert ez-000000.00.t*.png ez-000000.00.mpg

rm eps-000000.00.h5
rm ez-000000.00.h5
rm _punta.dac
rm ez-000000.00.t*.png

El shell script anterior compila el programa C++ mediante la instrucción make y crea un archivo de ejecución con extensión “.dac” la cual se ejecuta en la siguiente instrucción, a continuación se utiliza un comando propio de el paquete h5utils desarrollado también por el MIT, el comando h5ls enlista el tamaño del dataset creado que vive en el archivo con extensión H5 y en formato HDF5 este enlistado es solamente con fines informativos, a continuación se ejecuta el comando h5topng el cual como describe su nombre hace una conversión de los datos en formato HDF5 a una imagen en formato PNG.

Después, se utilizan los datos de la geometría así como los datos de el campo generado para generar una serie de archivos en formato PNG que representan una imagen en el tiempo en cada uno de los pasos de la simulación, después se utiliza un paquete llamado ImageMagick para convertir la serie de imágenes creadas en formato de video y se finaliza removiendo archivos que ya no serán utilizados al final de la simulación ya que lo que nos interesa por ahora es el video.

Para concluir con la ejecución del programa Meep creado, se debe ejecutar el shell script que hará todo el trabajo de escribir todos esos comandos por nosotros con la siguiente instrucción, suponiendo que nuestro script se llame punta.sh.

chmod +x punta.sh
sh punta.sh

Listo!, el video resultante de la simulacion anterior se enlista a continuacion:

¡Enjoy! 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *