add field plot utilities for normalization run

This commit is contained in:
2026-05-25 14:30:01 +02:00
parent 3be89321ee
commit d113f54164
2 changed files with 87 additions and 10 deletions
+49
View File
@@ -0,0 +1,49 @@
#visualize fields from hdf5 files
import h5py
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import glob
import numpy as np
input_files = sorted(glob.glob("metapeg_v2-ex-*.h5"))
data = []
times = []
for filename in input_files:
with h5py.File(filename, "r") as f:
Ex = f["ex"][:]
# Extract time from filename (e.g., "metapeg_v2-ex-000050.00.h5" → 50.00)
time = float(filename.split("-")[-1].split(".h5")[0])
times.append(time)
data.append(Ex)
print(f"Loaded {filename}, time={time}")
print(len(data))
# Create animation
fig, ax = plt.subplots()
x = np.linspace(-4, 4) #assuming x is the last dimension
z = np.linspace(-3, 3) #assuming z is the first dimension
max_clim = np.max([np.abs(data[i][:,0,:]) for i in range(len(data))])
min_clim = np.min([np.abs(data[i][:,0,:]) for i in range(len(data))])
print(max_clim)
def animate(frame):
ax.clear()
im = ax.imshow(np.rot90(np.abs(data[frame][:,0,:]),k=1), origin="lower",
extent=[z.min(), z.max(),x.min(), x.max(),],
cmap="viridis",
vmin=min_clim, vmax=max_clim)
ax.set_xlabel("x (um)")
ax.set_ylabel("z (um)")
ax.set_title(f"Electric field (Ex) at t={times[frame]:.2f}")
#plt.colorbar(im, ax=ax, label="Ex (a.u.)")
return im,
anim = animation.FuncAnimation(fig, animate, frames=len(data),
interval=100, blit=True, repeat=True)
anim.save("results/Ex_animation.gif", writer="ffmpeg", fps=2)
plt.close()
print("Animation saved to results/Ex_animation.gif")
+38 -10
View File
@@ -2,6 +2,7 @@ from typing import List, NamedTuple, Tuple
from autograd import numpy as npa, tensor_jacobian_product, grad from autograd import numpy as npa, tensor_jacobian_product, grad
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import matplotlib.animation as animation
import meep as mp import meep as mp
import meep.adjoint as mpa import meep.adjoint as mpa
import nlopt import nlopt
@@ -10,25 +11,25 @@ import os
import xarray as xr import xarray as xr
from PIL import Image from PIL import Image
mp.verbosity(1) mp.verbosity(3)
if not os.path.exists("results"): if not os.path.exists("results"):
os.makedirs("results") os.makedirs("results")
###### PHYSICS SETUP ###### ###### PHYSICS SETUP ######
RESOLUTION = 30 #50 #pixels per unit length RESOLUTION = 18 #pixels per meep unit length (1um)
MAX_RUN_TIME = 1100 #meep units MAX_RUN_TIME = 1100 #meep units
WAVELENGTH_MIN_UM = 1.50 WAVELENGTH_MIN_UM = 1.50
WAVELENGTH_MAX_UM = 1.60 WAVELENGTH_MAX_UM = 1.60
PML_UM = 1.0 #PML thickness PML_UM = 1.0 #PML thickness
BUFFER = 3.0 BUFFER = 2.0
DESIGN_WAVELENGTHS_UM = [1.50,1.55,1.60] #wavelengths at which to optimize the device DESIGN_WAVELENGTHS_UM = [1.50,1.55,1.60] #wavelengths at which to optimize the device
DESIGN_REGION_UM = mp.Vector3(5,5,1) DESIGN_REGION_UM = mp.Vector3(2,2,1)
DESIGN_REGION_RESOLUTION = int(2 * RESOLUTION) DESIGN_REGION_RESOLUTION = int(2 * RESOLUTION)
DESIGN_REGION_CENTER = mp.Vector3(0, 0, DESIGN_REGION_UM.z / 2) DESIGN_REGION_CENTER = mp.Vector3(0, 0, DESIGN_REGION_UM.z / 2)
NX_DESIGN_GRID = int(DESIGN_REGION_UM.x * DESIGN_REGION_RESOLUTION) + 1 NX_DESIGN_GRID = int(DESIGN_REGION_UM.x * DESIGN_REGION_RESOLUTION) + 1
NY_DESIGN_GRID = int(DESIGN_REGION_UM.y * DESIGN_REGION_RESOLUTION) + 1 NY_DESIGN_GRID = int(DESIGN_REGION_UM.y * DESIGN_REGION_RESOLUTION) + 1
MIN_LENGTH_UM = 0.15 #150 nm minimum length scale MIN_LENGTH_UM = 0.5 #500 nm minimum length scale
SILICON = mp.Medium(index = 3.5) SILICON = mp.Medium(index = 3.5)
SILICON_DIOXIDE = mp.Medium(index = 1.5) SILICON_DIOXIDE = mp.Medium(index = 1.5)
AIR = mp.Medium(index = 1.0) AIR = mp.Medium(index = 1.0)
@@ -63,10 +64,10 @@ frequency_center = 0.5 * (frequency_min + frequency_max)
wavelength_center = 1 / frequency_center #remember that c = 1 in meep units wavelength_center = 1 / frequency_center #remember that c = 1 in meep units
frequency_width = frequency_max - frequency_min frequency_width = frequency_max - frequency_min
SOURCE_CENTER = mp.Vector3(0,0,-2) SOURCE_CENTER = mp.Vector3(0,0,-BUFFER/2)
SOURCE_SIZE = mp.Vector3(physical_domains_size.x,physical_domains_size.y,0) SOURCE_SIZE = mp.Vector3(physical_domains_size.x,physical_domains_size.y,0)
NEAR_REGION_MONITOR_CENTER = mp.Vector3(0,0, DESIGN_REGION_UM.z + BUFFER/2) NEAR_REGION_MONITOR_CENTER = mp.Vector3(0,0, DESIGN_REGION_UM.z)
NEAR_REGION_MONITOR_SIZE = mp.Vector3(physical_domains_size.x,physical_domains_size.y,0) NEAR_REGION_MONITOR_SIZE = mp.Vector3(physical_domains_size.x,physical_domains_size.y,0)
ff_monitor_center = mp.Vector3(0,0,DESIGN_REGION_UM.z + BUFFER) ff_monitor_center = mp.Vector3(0,0,DESIGN_REGION_UM.z + BUFFER)
@@ -75,7 +76,7 @@ xs = ys = np.linspace(-ff_monitor_size.x/2, ff_monitor_size.x/2, NX_DESIGN_GRID)
#collection of points in the far-field monitor #collection of points in the far-field monitor
ff_points = [mp.Vector3(x_p,y_p,ff_monitor_center.z) for x_p in xs for y_p in ys] ff_points = [mp.Vector3(x_p,y_p,ff_monitor_center.z) for x_p in xs for y_p in ys]
stop_cond = mp.stop_when_fields_decayed(50, mp.Ex, NEAR_REGION_MONITOR_CENTER, 1e-6) stop_cond = mp.stop_when_fields_decayed(25, mp.Ex, NEAR_REGION_MONITOR_CENTER, 1e-6)
pml_layers = [mp.PML(PML_UM)] pml_layers = [mp.PML(PML_UM)]
frequencies = [1/wavelength for wavelength in DESIGN_WAVELENGTHS_UM] frequencies = [1/wavelength for wavelength in DESIGN_WAVELENGTHS_UM]
@@ -343,6 +344,15 @@ def intensity_desired_fn_pattern(
return pattern_to_return return pattern_to_return
def record_fields(sim):
plt.figure()
ax = plt.gca()
sim.plot2D(output_plane=view_2D_plane, fields=mp.Ex, ax=ax)
plt.savefig(f"results/fields_t{sim.timestep()}.pdf")
plt.close()
return True
def normalization_sim() -> np.ndarray: def normalization_sim() -> np.ndarray:
''' Computes the Far-Field pattern at the monitor location and ''' Computes the Far-Field pattern at the monitor location and
without the design region. Used for normalization purposes. without the design region. Used for normalization purposes.
@@ -354,7 +364,9 @@ def normalization_sim() -> np.ndarray:
sources = [ sources = [
mp.Source( mp.Source(
src=mp.GaussianSource(frequency_center, fwidth=frequency_width), src=mp.GaussianSource(
frequency=frequency_center,
fwidth=frequency_width/2),
component=mp.Ex, component=mp.Ex,
center=SOURCE_CENTER, center=SOURCE_CENTER,
size=SOURCE_SIZE, size=SOURCE_SIZE,
@@ -379,6 +391,7 @@ def normalization_sim() -> np.ndarray:
geometry=geometry, geometry=geometry,
boundary_layers=pml_layers, boundary_layers=pml_layers,
k_point=mp.Vector3(), k_point=mp.Vector3(),
split_chunks_evenly=False,
) )
plt.figure() plt.figure()
@@ -395,7 +408,21 @@ def normalization_sim() -> np.ndarray:
norm_near2far = norm_sim.add_near2far(frequencies, *NearRegions) norm_near2far = norm_sim.add_near2far(frequencies, *NearRegions)
norm_sim.run(until_after_sources=stop_cond) #norm_sim.run(until_after_sources=stop_cond)
norm_sim.run(
mp.at_every(20,mp.in_volume(
mp.Volume(center=mp.Vector3(), size=physical_domains_size),
mp.output_efield_x
)),
#mp.at_every(20,record_fields),
until_after_sources=stop_cond
)
#make a plot of the fields
plt.figure()
ax = plt.gca()
norm_sim.plot2D(output_plane=view_2D_plane, fields=mp.Ex, ax=ax)
plt.savefig("results/NORM_FIELDS.pdf")
ref_fields = np.array( ref_fields = np.array(
[norm_sim.get_farfield(norm_near2far, point) for point in ff_points] [norm_sim.get_farfield(norm_near2far, point) for point in ff_points]
@@ -507,6 +534,7 @@ def intensity_optimization(
geometry=geometry, geometry=geometry,
boundary_layers=pml_layers, boundary_layers=pml_layers,
k_point=mp.Vector3(), k_point=mp.Vector3(),
split_chunks_evenly=False,
) )
plt.figure() plt.figure()