Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP:MaterialGrid #1242

Merged
merged 14 commits into from
Jul 4, 2020
25 changes: 25 additions & 0 deletions python/geom.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,31 @@ def _get_epsmu(self, diag, offdiag, susceptibilities, conductivity_diag, conduct
# Convert list matrix to 3D numpy array size [freqs,3,3]
return np.squeeze(epsmu)

class MaterialGrid(object):
def __init__(self,grid_size,medium1,medium2,design_parameters=None):
self.grid_size = grid_size
self.medium1 = medium1
self.medium2 = medium2
if self.grid_size.x == 0:
self.grid_size.x = 1
elif self.grid_size.y == 0:
self.grid_size.y = 1
elif self.grid_size.z == 0:
self.grid_size.z = 1
self.num_params=self.grid_size.x*self.grid_size.y*self.grid_size.z

if design_parameters is None:
self.design_parameters = np.zeros((self.num_params,))
elif design_parameters.size != self.num_params:
raise ValueError("design_parameters of shape {} do not match user specified grid dimension: {}".format(design_parameters.size,grid_size))
else:
self.design_parameters = design_parameters.flatten().astype(np.float64)

return
def update_parameters(sim,x):
return
def get_gradient(fields,grid):
return

class Susceptibility(object):

Expand Down
5 changes: 5 additions & 0 deletions python/meep.i
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,7 @@ meep::volume_list *make_volume_list(const meep::volume &v, int c,
if (((material_data *)$1.material)->medium.H_susceptibilities.items) {
delete[] ((material_data *)$1.material)->medium.H_susceptibilities.items;
}
delete[] ((material_data *)$1.material)->design_parameters;
delete[] ((material_data *)$1.material)->epsilon_data;
delete (material_data *)$1.material;
geometric_object_destroy($1);
Expand Down Expand Up @@ -720,6 +721,7 @@ meep::volume_list *make_volume_list(const meep::volume &v, int c,
delete[] ((material_data *)$1.items[i].material)->medium.H_susceptibilities.items;
}
delete[] ((material_data *)$1.items[i].material)->epsilon_data;
delete[] ((material_data *)$1.items[i].material)->design_parameters;
delete (material_data *)$1.items[i].material;
geometric_object_destroy($1.items[i]);
}
Expand Down Expand Up @@ -841,6 +843,7 @@ meep::volume_list *make_volume_list(const meep::volume &v, int c,
if ($1->medium.H_susceptibilities.items) {
delete[] $1->medium.H_susceptibilities.items;
}
delete[] $1->design_parameters;
delete[] $1->epsilon_data;
delete $1;
}
Expand Down Expand Up @@ -1190,6 +1193,7 @@ meep::volume_list *make_volume_list(const meep::volume &v, int c,
if ($1.items[i]->medium.H_susceptibilities.items) {
delete[] $1.items[i]->medium.H_susceptibilities.items;
}
delete[] $1.items[i]->design_parameters;
delete[] $1.items[i]->epsilon_data;
}
delete[] $1.items;
Expand Down Expand Up @@ -1404,6 +1408,7 @@ PyObject *_get_array_slice_dimensions(meep::fields *f, const meep::volume &where
GyrotropicSaturatedSusceptibility,
Lattice,
LorentzianSusceptibility,
MaterialGrid,
Matrix,
Medium,
MultilevelAtom,
Expand Down
64 changes: 64 additions & 0 deletions python/tests/material_grid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import meep as mp
import numpy as np
import matplotlib.pyplot as plt

resolution = 50 # pixels/μm

cell_size = mp.Vector3(14,14)

pml_layers = [mp.PML(thickness=2)]

# rotation angle (in degrees) of waveguide, counter clockwise (CCW) around z-axis
rot_angle = np.radians(20)

w = 1.0 # width of waveguide

m1 = mp.Medium(epsilon=2)
m2 = mp.Medium(epsilon=12)
n = 100
gs = mp.Vector3(n,n)
np.random.seed(1)
dp = np.random.rand(n*n)
mg = mp.MaterialGrid(gs,m1,m2,dp)

geometry = [mp.Block(center=mp.Vector3(),
size=mp.Vector3(2,2,mp.inf),
e1=mp.Vector3(x=1).rotate(mp.Vector3(z=1), rot_angle),
e2=mp.Vector3(y=1).rotate(mp.Vector3(z=1), rot_angle),
material=mg)]

fsrc = 0.15 # frequency of eigenmode or constant-amplitude source
bnum = 1 # band number of eigenmode

kpoint = mp.Vector3(x=1).rotate(mp.Vector3(z=1), rot_angle)

compute_flux = True # compute flux (True) or plot the field profile (False)

eig_src = True # eigenmode (True) or constant-amplitude (False) source

if eig_src:
sources = [mp.EigenModeSource(src=mp.GaussianSource(fsrc,fwidth=0.2*fsrc) if compute_flux else mp.ContinuousSource(fsrc),
center=mp.Vector3(),
size=mp.Vector3(y=3*w),
direction=mp.NO_DIRECTION,
eig_kpoint=kpoint,
eig_band=bnum,
eig_parity=mp.EVEN_Y+mp.ODD_Z if rot_angle == 0 else mp.ODD_Z,
eig_match_freq=True)]
else:
sources = [mp.Source(src=mp.GaussianSource(fsrc,fwidth=0.2*fsrc) if compute_flux else mp.ContinuousSource(fsrc),
center=mp.Vector3(),
size=mp.Vector3(y=3*w),
component=mp.Ez)]

sim = mp.Simulation(cell_size=cell_size,
resolution=resolution,
boundary_layers=pml_layers,
sources=sources,
#eps_averaging=False,
geometry=geometry
#symmetries=[mp.Mirror(mp.Y)] if rot_angle == 0 else []
)

sim.plot2D()
plt.show()
37 changes: 36 additions & 1 deletion python/typemap_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ static PyObject *py_material_object() {
return material_object;
}

static PyObject *py_material_grid_object() {
static PyObject *material_object = NULL;
if (material_object == NULL) {
PyObject *geom_mod = get_geom_mod();
material_object = PyObject_GetAttrString(geom_mod, "MaterialGrid");
}
return material_object;
}

static PyObject *py_vector3_object() {
static PyObject *vector3_object = NULL;
if (vector3_object == NULL) {
Expand Down Expand Up @@ -421,13 +430,39 @@ static int py_list_to_susceptibility_list(PyObject *po, susceptibility_list *sl)
return 1;
}

static int pymaterial_grid_to_material_grid(PyObject *po, material_data *md) {
//po must be a python MaterialGrid object

// initialize grid size
if (!get_attr_v3(po, &md->grid_size, "grid_size")) { meep::abort("MaterialGrid grid_size failed to init.");}

// initialize user specified materials
PyObject *po_medium1 = PyObject_GetAttrString(po, "medium1");
if (!pymedium_to_medium(po_medium1, &md->medium_1)) { meep::abort("MaterialGrid medium1 failed to init."); }
PyObject *po_medium2 = PyObject_GetAttrString(po, "medium2");
if (!pymedium_to_medium(po_medium2, &md->medium_2)) { meep::abort("MaterialGrid medium2 failed to init."); }

// Initialize design parameters
PyObject *po_dp = PyObject_GetAttrString(po, "design_parameters");
PyArrayObject *pao = (PyArrayObject *)po_dp;
if (!PyArray_Check(pao)) { meep::abort("MaterialGrid design_parameters failed to init.");}
if (!PyArray_ISCARRAY(pao)) { meep::abort("Numpy array design_parameters must be C-style contiguous."); }
md->design_parameters = new realnum[PyArray_SIZE(pao)];
memcpy(md->design_parameters, (realnum *)PyArray_DATA(pao), PyArray_SIZE(pao) * sizeof(realnum));
return 1;
}

static int pymaterial_to_material(PyObject *po, material_type *mt) {
material_data *md;

if (PyObject_IsInstance(po, py_material_object())) {
md = make_dielectric(1);
if (!pymedium_to_medium(po, &md->medium)) { return 0; }
}
else if (PyObject_IsInstance(po, py_material_grid_object())) { // Material grid subclass
md = make_material_grid();
if (!pymaterial_grid_to_material_grid(po, md)) { return 0; }
}
else if (PyFunction_Check(po)) {
PyObject *eps = PyObject_GetAttrString(po, "eps");
PyObject *py_do_averaging = PyObject_GetAttrString(po, "do_averaging");
Expand Down Expand Up @@ -462,7 +497,7 @@ static int pymaterial_to_material(PyObject *po, material_type *mt) {
md->epsilon_dims[1], md->epsilon_dims[2]);
}
else {
meep::abort("Expected a Medium, a function, or a filename");
meep::abort("Expected a Medium, a Material Grid, a function, or a filename");
}

*mt = md;
Expand Down
6 changes: 3 additions & 3 deletions src/fields.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -678,9 +678,9 @@ realnum linear_interpolate(realnum rx, realnum ry, realnum rz, realnum *data, in
rz = 1.0 - rz;

/* get the point corresponding to r in the epsilon array grid: */
x = pmod(int(rx * nx), nx);
y = pmod(int(ry * ny), ny);
z = pmod(int(rz * nz), nz);
x = rx == 1.0 ? nx-1 : pmod(int(rx * nx), nx);
y = ry == 1.0 ? ny-1 : pmod(int(ry * ny), ny);
z = rz == 1.0 ? nz-1 : pmod(int(rz * nz), nz);

/* get the difference between (x,y,z) and the actual point
smartalecH marked this conversation as resolved.
Show resolved Hide resolved
... we shift by 0.5 to center the data points in the pixels */
Expand Down
20 changes: 18 additions & 2 deletions src/material_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,16 +159,21 @@ typedef void (*user_material_func)(vector3 x, void *user_data, medium_struct *me
// 'medium' field is filled in appropriately at
// each evaluation point by calling the user's
// routine.
// MATERIAL_GRID: material properties position-dependent, described
// by user-supplied array of grid points. In this case
// the 'medium' field is filled in appropriately at
// each evaluation point by interpolating the array.
// PERFECT_METAL: the 'medium' field is never referenced in this case.
struct material_data {
enum {
MEDIUM,
MATERIAL_FILE, // formerly MATERIAL_TYPE_SELF
MATERIAL_USER, // formerly MATERIAL_FUNCTION
MATERIAL_GRID,
PERFECT_METAL
} which_subclass;

// this field is used for all material types except PERFECT_METAL
// this field is used for all material types except PERFECT_METAL and MATERIAL_GRID
medium_struct medium;

// these fields used only if which_subclass==MATERIAL_USER
Expand All @@ -180,11 +185,20 @@ struct material_data {
meep::realnum *epsilon_data;
size_t epsilon_dims[3];

// these fields used only if which_subclass==MATERIAL_GRID
vector3 grid_size;
meep::realnum* design_parameters;
medium_struct medium_1;
medium_struct medium_2;

material_data()
: which_subclass(MEDIUM), medium(), user_func(NULL), user_data(NULL), epsilon_data(NULL) {
: which_subclass(MEDIUM), medium(), user_func(NULL), user_data(NULL), epsilon_data(NULL), design_parameters(NULL), medium_1(), medium_2() {
epsilon_dims[0] = 0;
epsilon_dims[1] = 0;
epsilon_dims[2] = 0;
grid_size.x = 0;
grid_size.y = 0;
grid_size.z = 0;
}
};

Expand All @@ -204,7 +218,9 @@ extern material_type vacuum;
material_type make_dielectric(double epsilon);
material_type make_user_material(user_material_func user_func, void *user_data);
material_type make_file_material(char *epsilon_input_file);
material_type make_material_grid();
void read_epsilon_file(const char *eps_input_file);
void update_design_parameters(material_type matgrid, double* design_parameters);

}; // namespace meep_geom

Expand Down
Loading