#include <stdio.h>
#include <string.h>
#include "../common/progress.h"
using namespace af;
struct pml_t {
int npml_x, npml_z;
int pml_vec[4];
};
struct medium_t {
float Mstart, epsilon_r, chi_1, tau_0, sigma, dt;
bool back_bound;
};
typedef enum { P_GAUSS = 1, P_SINE = 2 } pchoice_t;
typedef enum { P_ADDITIVE = 1, P_HARD = 0 } ptype_t;
struct pulse_t {
int Az, Aw, Ac;
pchoice_t choice;
ptype_t type;
float stdev, cut_off, t0, dt, freq_in, amplitude;
};
static float *cpu_constant(float val, int n)
{
float *vals = (float *)malloc(n*sizeof(*vals));
for (
int i = 0;
i < n; ++
i)
return vals;
}
static void get_pulse(int Nx, float dt, struct pulse_t& pulse)
{
if (pulse.choice == P_GAUSS) {
pulse.t0 = 20;
pulse.stdev = 6;
pulse.cut_off = 2 * pulse.t0;
} else if (pulse.choice == P_SINE) {
float freq_in_MHz = 3000;
pulse.freq_in = 1e6f * freq_in_MHz;
float cut_off = 3;
pulse.cut_off = cut_off / (pulse.freq_in * dt);
if (
ceil(cut_off) != cut_off) {
fprintf(stderr, __FILE__":%d: nonzero sine wave cuttoff\n", __LINE__);
}
pulse.dt = dt;
} else {
fprintf(stderr, __FILE__":%d: undefined wave type: %d\n", __LINE__, pulse.choice);
exit(EXIT_FAILURE);
}
pulse.amplitude = 1;
pulse.type = P_HARD;
int Az = pulse.Az, Aw = pulse.Aw, Ac = pulse.Ac;
pulse.ind = Nx * Az + Ac - 1 +
seq(-Aw / 2, Aw / 2);
}
static void medium_params_debye(
array& ga,
array& gb,
array& gbc,
int Nx,
int Nz,
float dt,
struct medium_t& m)
{
seq dielectric(m.Mstart - 1, Nz - m.Mstart + 1);
epsilon_r_vec(
span, dielectric) = m.epsilon_r;
sigma_vec(
span, dielectric) = m.sigma;
if (m.back_bound) {
}
float epsilon_0 = 8.8e-12f;
gb = (dt * sigma_vec) / epsilon_0;
gbc(
span, dielectric) = m.chi_1 * dt / m.tau_0;
ga = 1 / (epsilon_r_vec + gb + gbc);
m.gbc = gbc;
m.dt = dt;
}
int Nz, int Nx, pml_t p)
{
float *gi1 = cpu_constant(0,Nx), *gi2 = cpu_constant(1,Nx), *gi3 = cpu_constant(1,Nx);
float *gj1 = cpu_constant(0,Nz), *gj2 = cpu_constant(1,Nz), *gj3 = cpu_constant(1,Nz);
float *fi2 = cpu_constant(1,Nx), *fi3 = cpu_constant(1,Nx);
float *fj2 = cpu_constant(1,Nz), *fj3 = cpu_constant(1,Nz);
if (p.npml_x != 0) {
for (
int i = 0;
i <= p.npml_x; ++
i) {
float xnum = (float)p.npml_x -
i;
float xxn = xnum / p.npml_x;
float xn = .333f *
pow(xxn, 3);
if (p.pml_vec[1] == 1) {
gi3[
i] = (1 - xn) / (1 + xn);
}
if (p.pml_vec[0] == 1) {
gi2[Nx -
i - 1] = 1 / (1 + xn);
gi3[Nx -
i - 1] = (1 - xn) / (1 + xn);
}
xxn = (xnum - 0.5f) / p.npml_x;
xn = .333f *
pow(xxn, 3);
if (p.pml_vec[1] == 1) {
fi3[
i] = (1 - xn) / (1 + xn);
}
if (p.pml_vec[0] == 1) {
fi2[Nx -
i - 2] = 1 / (1 + xn);
fi3[Nx -
i - 2] = (1 - xn) / (1 + xn);
}
}
}
if (p.npml_z != 0) {
for (int j = 0; j <= p.npml_z; ++j) {
float xnum = (float)p.npml_z - j;
float xxn = xnum / p.npml_z;
float xn = .333f *
pow(xxn, 3);
if (p.pml_vec[3] == 1) {
gj1[j] = xn;
gj2[j] = 1 / (1 + xn);
gj3[j] = (1 - xn) / (1 + xn);
}
if (p.pml_vec[2] == 1) {
gj1[Nz - j - 1] = xn;
gj2[Nz - j - 1] = 1 / (1 + xn);
gj3[Nz - j - 1] = (1 - xn) / (1 + xn);
}
xxn = (xnum - 0.5f) / p.npml_z;
xn = .333f *
pow(xxn, 3);
if (p.pml_vec[3] == 1) {
fj2[j] = 1 / (1 + xn);
fj3[j] = (1 - xn) / (1 + xn);
}
if (p.pml_vec[2] == 1) {
fj2[Nz - j - 2] = 1 / (1 + xn);
fj3[Nz - j - 2] = (1 - xn) / (1 + xn);
}
}
}
_gi1 =
tile(
array(Nx, gi1), 1, Nz); free(gi1);
_gi2 =
tile(
array(Nx, gi2), 1, Nz); free(gi2);
_gi3 =
tile(
array(Nx, gi3), 1, Nz); free(gi3);
_gj1 =
tile(
array(Nz, gj1), 1, Nx).
T(); free(gj1);
_gj2 =
tile(
array(Nz, gj2), 1, Nx).
T(); free(gj2);
_gj3 =
tile(
array(Nz, gj3), 1, Nx).
T(); free(gj3);
_fi2 =
tile(
array(Nx, fi2), 1, Nz); free(fi2);
_fi3 =
tile(
array(Nx, fi3), 1, Nz); free(fi3);
_fj2 =
tile(
array(Nz, fj2), 1, Nx).
T(); free(fj2);
_fj3 =
tile(
array(Nz, fj3), 1, Nx).
T(); free(fj3);
}
static void compute_pulse(
array& d,
float T,
struct pulse_t& params)
{
float cut_off = params.cut_off;
bool is_hard = (params.type == P_HARD);
if (params.choice == P_GAUSS && T < cut_off) {
float pulse = params.amplitude *
exp(-0.5f *
pow((params.t0 - T) / params.stdev, 2));
if (is_hard) { d(ind) = pulse; }
else { d(ind) += pulse; }
} else if (params.choice == P_SINE && T < cut_off) {
float pulse = params.amplitude *
sin(2 * 3.14159f * params.freq_in * params.dt * T);
if (is_hard) { d(ind) = pulse; }
else { d(ind) += pulse; }
} else {
if (is_hard) { d(ind) = 0; }
}
}
static void update_s_debye_TM(
array& py,
const array& ey,
const struct medium_t& medium)
{
float dt = medium.dt;
float tau_0 = medium.tau_0;
py = ((1 - 0.5f * dt / tau_0) * py + gbc * ey) / (1 + 0.5f * dt / tau_0);
}
void fdtd(bool console)
{
double time_total = 30;
float Lz = .4f;
int Nz = 160;
int Nx = 400;
float ddx = Lz / Nz;
float dt = ddx / 6e8f;
struct pml_t pml;
pml.npml_x = 8;
pml.npml_z = 20;
pml.pml_vec[0] = 1;
pml.pml_vec[1] = 1;
pml.pml_vec[2] = 0;
pml.pml_vec[3] = 1;
Nx += (pml.pml_vec[0] + pml.pml_vec[1]) * pml.npml_x;
Nz += (pml.pml_vec[2] + pml.pml_vec[3]) * pml.npml_z;
struct medium_t medium;
float Ml = .3f;
medium.Mstart =
ceil((Lz - Ml) / ddx) + pml.npml_z;
medium.epsilon_r = 5;
medium.chi_1 = 30;
medium.tau_0 = 1e-11f;
medium.sigma = .01f;
medium.back_bound = false;
struct pulse_t pulse;
int Az = 10;
pulse.Az = pml.npml_z + (Az - 1);
pulse.Aw = 8;
pulse.Ac = Nx / 2;
pulse.choice = P_SINE;
array fi2, fi3, fj2, fj3;
get_pmlr(gi1, gi2, gi3, gj1, gj2, gj3, fi2, fi3, fj2, fj3, Nz, Nx, pml);
medium_params_debye(ga, gb, gbc, Nx, Nz, dt, medium);
get_pulse(Nx, dt, pulse);
printf("Finite-difference time-domain simulation of electromagnetic field\n");
unsigned iter = 0;
while (progress(iter, t, time_total)) {
array dy_hat_temp = gi3 * dy_hat + 0.5f * gi2 * (dyhz - dxhx);
dy = gj3 * dy + gj2 * (dy_hat_temp - dy_hat);
dy_hat = dy_hat_temp;
compute_pulse(dy, (float)iter++, pulse);
array ey = ga * (dy - iy - sy);
iy = iy + gb * ey;
update_s_debye_TM(sy, ey, medium);
ihz += gj1 * cez;
hz = fi3 * hz + fi2 * (0.5f * cez + ihz);
ihx += gi1 * cey;
hx = fj3 * hx + fj2 * (0.5f * cey + ihx);
if (!console) {
} else {
}
}
}
int main(int argc, char* argv[])
{
int device = argc > 1 ? atoi(argv[1]) : 0;
bool console = argc > 2 ? argv[2][0] == '-' : false;
try {
fdtd(console);
fprintf(stderr,
"%s\n", e.
what());
throw;
}
return 0;
}