Managing Projects in vipdopt¶
vipdopt includes a Project class for organizing all of your simulations, output data, and plots in one project directory. The Project class also enables saving the progress of an optimization and restarting from that checkpoint.
[9]:
# imports
from pathlib import Path
import sys
import numpy as np
import matplotlib.pyplot as plt
np.set_printoptions(threshold=100)
# Get vipdopt directory path from Notebook
parent_dir = str(Path().resolve().parents[2])
# Add to sys.path
sys.path.insert(0, parent_dir)
# Imports from vipdopt
from vipdopt.optimization import Device, Sigmoid, Scale, LumericalOptimization, BayerFilterFoM, AdamOptimizer, SuperFoM
from vipdopt.simulation import LumericalSimulation, GaussianSource, DipoleSource, Power, Profile
from vipdopt.configuration import SonyBayerConfig
from vipdopt.project import Project, create_internal_folder_structure
When you initialize a new Project it will be mostly empty. You’ll need to set all of the parts (base simulation, optimization, optimizer, etc.) manually.
Throughout this notebook, we will be using the “Sony Color Router” design that’s appeared in the other tutorial notebooks.
[10]:
# Creating all of the parts first
cfg = SonyBayerConfig()
cfg.read_file('config_example_3d.yml')
base_sim = LumericalSimulation('simulation_example.json')
optimizer = AdamOptimizer(cfg['fixed_step_size'], (0.9, 0.999))
coords = {
'x': np.linspace(0, 2.04e-6, 60),
'y': np.linspace(0, 2.04e-6, 60),
'z': np.linspace(0, 2.04e-6, 60),
}
lambda_vector = np.linspace(
cfg['lambda_min_um'],
cfg['lambda_max_um'],
cfg['num_bands'] * cfg['num_points_per_band']
)
n_freq = len(lambda_vector)
device = Device(
(60, 60, 60),
(0, 1),
coords,
'color_router',
randomize=True,
init_seed=23,
filters=[Sigmoid(0.05, 0.1)]
)
foms = [
BayerFilterFoM(
'TE',
[GaussianSource(f'forward_src_{axis}')],
[GaussianSource(f'forward_src_{axis}'), DipoleSource(f'adjoint_src_{n}{axis}')],
[
Power(f'focal_monitor_{n}'),
Power(f'transmission_monitor_{n}'),
Profile('design_efield_monitor')
],
[Profile('design_efield_monitor')],
range(n_freq),
[],
all_freqs=lambda_vector
) for axis in 'xy' for n in range(4)
]
weights = [1] * len(foms)
combined_fom = SuperFoM(((f,) for f in foms), weights)
opt = LumericalOptimization(
base_sim,
device,
optimizer,
combined_fom,
epoch_list=np.linspace(
cfg['iter_per_epoch'],
cfg['iter_per_epoch'] * cfg['max_epochs'],
cfg['max_epochs'], dtype=int
),
)
Now that the parts are made we can make our Project manually.
[11]:
project = Project()
project.config = cfg
project.optimization = opt
project.optimizer = optimizer
project.base_sim = base_sim
project.foms = foms
project.weights = weights
A Project has a specific folder structure. This structure can be created automatically using create_internal_structure. Below is what the internal structure looks like:
├───.tmp
├───data
│ ├───checkpoints
│ ├───opt_info
│ │ └───plots
│ └───saved_scripts
├───device
└───eval
├───configs
└───utils
.tmpstores intermediate files and completed simulation datadata/checkpointscontains checkpoints for optimiztion progressdata/opt_infocontains information about the optimizationdata/opt_info/plotscontains plots generated during the optimizationdata/saved_scriptscontains scripts that are included as part of the optimizationdevicecontains saved device parameters over each iterationevalcontains configurations and utility functions for evaluating the optimization
[ ]:
# Let's use the directory "color_router_proj" as our project folder
proj_dir = Path('color_router_proj')
project.subdirectories = create_internal_folder_structure(proj_dir)
project.save_as(proj_dir)
If we have a previously saved project folder, we can load our project into code for faster setup.
[ ]:
project.load_project(proj_dir)