gym icon indicating copy to clipboard operation
gym copied to clipboard

POWER SPLITTER DESIGN CHANGE Issues: **ResolutionError**: Cannot neatly resolve quantity (unyt_quantity(7040, 'nm')) at given resolution (unyt_quantity(100, 'nm'))

Open VikramReddy-Anapana opened this issue 10 months ago • 10 comments

Hello All,

I'm trying to scale the power splitter problem to "mmWave frequencies". From what I understand, the current design region is 1.6 um x 1.6 um, but I need to modify this to better suit my target frequencies.

However, when I try changing the design, I keep running into errors like:

  1. FrozenIssues.
  2. ValueError: The design_var array with shape (500, 500) does not fit into the destination array with shape (344, 280)
  3. ResolutionError: Cannot neatly resolve quantity (unyt_quantity(7040, 'nm')) at given resolution (unyt_quantity(100, 'nm')) ---> this error has been repeating irrespective of changes I made.

I'm not sure what's causing these issues. I'd appreciate any insights on how to properly scale the design without running into these errors.

Thanks in advance.

VikramReddy-Anapana avatar Mar 15 '25 23:03 VikramReddy-Anapana

Hi @VikramReddy-Anapana , can you paste the code that is causing you issues?

mfschubert avatar Mar 16 '25 19:03 mfschubert

  1. I tried to modify the existing Power_splitter ---> attempted to increase the design region by a little ---> ValueError
  2. I tried to scale it to mmWave frequencies ---> ResolutionError

Modified_DefaultPOWER_SPLITTER_Invrs_gym.txt

import jax import jax.numpy as jnp import matplotlib.pyplot as plt from skimage import measure import unyt as u from invrs_gym import challenges from invrs_gym.challenges.ceviche import defaults from totypes import types

Define the desired design extent and grid spacing

Setting design extent in nm

desired_design_extent = u.unyt_array([5000, 5000], u.nm)

Set grid spacing to 10 nm

grid_spacing = u.unyt_quantity(10, u.nm)

Adjust the design extent to be divisible by grid spacing

adjusted_design_extent = u.unyt_array( [ round(desired_design_extent[0].value / grid_spacing.value) * grid_spacing.value, round(desired_design_extent[1].value / grid_spacing.value) * grid_spacing.value, ], u.nm, )

print("Adjusted Design Extent:", adjusted_design_extent)

Define the new grid shape based on the adjusted design extent

grid_shape = (int(adjusted_design_extent[0].value // grid_spacing.value), int(adjusted_design_extent[1].value // grid_spacing.value))

print("New grid shape:", grid_shape)

Create the custom wdm_spec using the adjusted design extent

custom_wdm_spec = defaults.wdm_spec( design_extent_ij=adjusted_design_extent, design_wg_offset=u.unyt_quantity(120, u.nm), intended_sim_resolution=grid_spacing, )

Custom density initializer to modify waveguide and middle box layout

def custom_density_initializer(key, density_array): new_shape = (int(adjusted_design_extent[0].value // grid_spacing.value), int(adjusted_design_extent[1].value // grid_spacing.value))

# Create a new design array with the desired pattern
density_array = jnp.ones(new_shape) 

middle_box_start_x, middle_box_end_x = 120, 180 
middle_box_start_y, middle_box_end_y = 100, 150 

if middle_box_end_x <= new_shape[0] and middle_box_end_y <= new_shape[1]:
    density_array = density_array.at[middle_box_start_x:middle_box_end_x, middle_box_start_y:middle_box_end_y].set(1)

# Return the density array for the custom design
return types.Density2DArray(
    array=density_array, 
    lower_bound=0.0,  
    upper_bound=1.0,  
    fixed_solid=None, 
    fixed_void=None,  
)

Create the challenge with the custom density initializer

challenge = challenges.ceviche_power_splitter( density_initializer=custom_density_initializer )

Applying the updated design region spec to the challenge

Applying custom design region

challenge.component.ceviche_model.spec = custom_wdm_spec

Initialize parameters --> for the updated challenge

default_params = challenge.component.init(jax.random.PRNGKey(0))

def plot_params(ax, params, contour_levels=(0.5,)): density = challenge.component.ceviche_model.density(params.array) im = ax.imshow(1 - density, cmap="gray") im.set_clim(-2, 1) for level in contour_levels: for c in measure.find_contours(density, level=level): plt.plot(c[:, 1], c[:, 0], 'k') _ = ax.axis(False)

plt.figure(figsize=(8, 6)) plot_params(ax=plt.subplot(111), params=default_params, contour_levels=(0.6, 0.6)) plt.show()


mmWave_specifications.txt

Adjusted Design Extent: [5000 5000] nm New grid shape: (500, 500)

ValueError Traceback (most recent call last) Cell In[39], line 85 82 _ = ax.axis(False) 84 plt.figure(figsize=(8, 6)) ---> 85 plot_params(ax=plt.subplot(111), params=default_params, contour_levels=(0.6, 0.6)) 86 plt.show()

Cell In[39], line 76, in plot_params(ax, params, contour_levels) 75 def plot_params(ax, params, contour_levels=(0.5,)): ---> 76 density = challenge.component.ceviche_model.density(params.array) 77 im = ax.imshow(1 - density, cmap="gray") 78 im.set_clim(-2, 1)

File ~\anaconda3\Lib\site-packages\ceviche_challenges\model_base.py:227, in Model.density(self, design_variable) 218 if design_variable.shape != self.design_variable_shape: 219 raise ValueError( 220 'Invalid design variable shape. Got ({}, {},) but expected ({}, {},)' 221 .format( (...) 225 self.design_variable_shape[1], 226 )) --> 227 return primitives.insert_design_variable( 228 self.transform_design_variable(design_variable), 229 self.density_bg, 230 self.design_region_coords, 231 )

File ~\anaconda3\Lib\site-packages\autograd\tracer.py:48, in primitive..f_wrapped(*args, **kwargs) 46 return new_box(ans, trace, node) 47 else: ---> 48 return f_raw(*args, **kwargs)

File ~\anaconda3\Lib\site-packages\ceviche_challenges\primitives.py:44, in insert_design_variable(design_var, destination, coords) 41 (x_min, y_min, x_max, y_max) = coords 42 if (design_var.shape[0] > destination.shape[0] or 43 design_var.shape[1] > destination.shape[1]): ---> 44 raise ValueError( 45 'The design_var array with shape {} does not fit into the ' 46 'destination array with shape {}'.format(design_var.shape, 47 destination.shape)) 48 if not np.all([coord > 0 for coord in coords]): 49 raise ValueError('All values in coord must be positive')

ValueError: The design_var array with shape (500, 500) does not fit into the destination array with shape (344, 280)

------------------------------ for mmWave specifications code ----------------------------------------------------------------- File ~\anaconda3\Lib\site-packages\ceviche_challenges\units.py:77, in resolve(v, resolution) 75 resolved = _resolve_or_none(v, resolution) 76 if resolved is None: ---> 77 raise ResolutionError( 78 "Cannot neatly resolve quantity (%r) at given resolution (%r)." % 79 (v, resolution)) 80 else: 81 return resolved

ResolutionError: Cannot neatly resolve quantity (unyt_quantity(403040, 'nm')) at given resolution (unyt_quantity(10000, 'nm')).

VikramReddy-Anapana avatar Mar 16 '25 20:03 VikramReddy-Anapana

Image

Please take a look at the attached code.

VikramReddy-Anapana avatar Mar 16 '25 20:03 VikramReddy-Anapana

Sorry, can you pare down your code to the bare minimum which exhibits the problem, and then paste it in a code block? See here for help: https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks

mfschubert avatar Mar 17 '25 02:03 mfschubert

mmwave_wavelengths_nm = [10710000.0, 5000000.0]
mmwave_grid_spacing_nm = 10000
design_extent = u.unyt_array([400000, 400000], u.nm)

if (design_extent[0] % mmwave_grid_spacing_nm != 0) or (design_extent[1] % mmwave_grid_spacing_nm != 0):
    raise ValueError("Design extent must be a multiple of grid spacing!")

custom_wdm_spec = defaults.wdm_spec(
    design_extent_ij=design_extent,
    design_wg_offset=u.unyt_quantity(1200, u.nm),
    intended_sim_resolution=u.unyt_quantity(mmwave_grid_spacing_nm, u.nm),
)

challenge = challenges.ceviche_power_splitter(
    grid_spacing_nm=mmwave_grid_spacing_nm,
    wavelengths_nm=mmwave_wavelengths_nm,
)

challenge.component.ceviche_model.spec = custom_wdm_spec

VikramReddy-Anapana avatar Mar 17 '25 02:03 VikramReddy-Anapana

Can you please provide the full code that reproduces the problem? So that I can just copy and paste it in an empty notebook and reproduce the issue.

mfschubert avatar Mar 17 '25 13:03 mfschubert

Please see the following full code

import unyt as u
from invrs_gym import challenges
from invrs_gym.challenges.ceviche import defaults
import jax.random as jax_random
import jax.numpy as jnp
from totypes import types
import matplotlib.pyplot as plt
from skimage import measure

# mmWave parameters
mmwave_wavelengths_nm = [10710000.0, 5000000.0]  
# Grid spacing in nanometers (10 um)
mmwave_grid_spacing_nm = 10000  

# custom wdm_spec
custom_wdm_spec = defaults.wdm_spec(
    design_extent_ij=u.unyt_array([400000, 400000], u.nm), 
    design_wg_offset=u.unyt_quantity(1200, u.nm),         
    intended_sim_resolution=mmwave_grid_spacing_nm * u.nm 
)

# custom density initializer --> fix shape mismatch issues
def custom_density_initializer(key, density_array):
    new_shape = (40, 40)
    
    fixed_solid = jnp.ones(new_shape, dtype=bool) if density_array.fixed_solid is not None else None
    fixed_void = jnp.zeros(new_shape, dtype=bool) if density_array.fixed_void is not None else None
    
    return types.Density2DArray(
        array=jnp.ones(new_shape), 
        lower_bound=density_array.lower_bound,
        upper_bound=density_array.upper_bound,
        fixed_solid=fixed_solid,
        fixed_void=fixed_void,
    )

challenge_mmwave = challenges.ceviche_power_splitter(
    grid_spacing_nm=mmwave_grid_spacing_nm,
    wavelengths_nm=mmwave_wavelengths_nm,
    density_initializer=custom_density_initializer,
)

# Override the default spec
challenge_mmwave.component.ceviche_model.spec = custom_wdm_spec

default_params_mmwave = challenge_mmwave.component.init(jax_random.PRNGKey(0))

def plot_params(ax, params, contour_levels=(0.5,)):
    density = challenge_mmwave.component.ceviche_model.density(params.array)
    im = ax.imshow(1 - density, cmap="gray")
    im.set_clim(-2, 1)
    for level in contour_levels:
        for c in measure.find_contours(density, level=level):
            ax.plot(c[:, 1], c[:, 0], 'k')
    _ = ax.axis(False)

plt.figure(figsize=(8, 6))
plot_params(ax=plt.subplot(111), params=default_params_mmwave, contour_levels=(0.4, 0.6))
plt.show()

VikramReddy-Anapana avatar Mar 17 '25 14:03 VikramReddy-Anapana

OK, the issue is that there are several parameters which define the geometry, and you are adjusting only some of them. I suggest taking a look at the ceviche.defaults module to see how the spec is constructed, and then make your own constructor where all the parameters are adjusted.

mfschubert avatar Mar 17 '25 15:03 mfschubert

Apologies, I didn’t notice your response earlier. I went through defaults.py, but it’s still unclear how to use it to scale the structure for mmWave frequencies. Could you please guide me on the correct approach? I have explored various options but haven’t found a solution.

VikramReddy-Anapana avatar Mar 18 '25 23:03 VikramReddy-Anapana

I think you need to implement your own version of this function:

https://github.com/invrs-io/gym/blob/4758d3ae29bcc088b086bc8fb0f97dea2e4d1ab4/src/invrs_gym/challenges/ceviche/defaults.py#L184-L264

mfschubert avatar Mar 19 '25 15:03 mfschubert

Please create a new issue if you have new questions.

mfschubert avatar May 27 '25 16:05 mfschubert