def collect_Boundary(self, item, additional_transform=None, **kwargs): shape = item.shape.transform_copy(item.transformation + additional_transform) shape.snap_to_grid(self.grids_per_unit) shape.remove_identicals() coordinates = shape # BOUNDARIES if len(shape) < 3: LOG.warning( "BOUNDARY with fewer than 3 coordinates not allowed in structure %s" % self.__current_structure__.name) return if len(shape) > TECH.GDSII.MAX_VERTEX_COUNT: LOG.warning("BOUNDARY with more than " + str(TECH.GDSII.MAX_VERTEX_COUNT) + " coordinates not supported in structure " + self.__current_structure__.name) # shape must be closed! if not (coordinates[0] == coordinates[-1]): coordinates.append(coordinates[0]) self.collect_boundary_element(layer=item.layer, coordinates=coordinates) return
def __addMeepFluxplane(self, flx, meep_fields): '''Convert a fluxplane (runtime.basic.Fluxplane) into a Meep fluxplane and add it to the Meep fields object''' if not isinstance(flx, Fluxplane): raise InvalidArgumentException("Invalid argument:: not of type runtime.basic.Fluxplane") LOG.debug("Meep node %i -Creating Meep volume object for the flux plane..." %(self.node_nr)) vec1 = self.__make_meep_vec__(flx.north) vec2 = self.__make_meep_vec__(flx.south) print "Meep node %i : flux plane between points (%f , %f) and (%f , %f) " %(self.node_nr, vec1.x(), vec1.y(), vec2.x(), vec2.y()) meepFlxVol = Meep.volume(vec1,vec2) center_freq = 1.0 / (float(flx.center_wavelength) / 1000.0) pw = ( (float(flx.pulse_width)/1000.0) / (float(flx.center_wavelength)/1000.0) ) * center_freq max_freq = center_freq + pw / 2.0 min_freq = center_freq - pw / 2.0 LOG.debug("Meep node %i -Now adding the fluxplane to the Meep field..." %(self.node_nr)) meepFluxplane = meep_fields.add_dft_flux_plane(meepFlxVol, min_freq, max_freq, flx.number_of_sampling_freq ) flx.flux_per_freq_callback = lambda : Meep.getFluxData(meepFluxplane) setattr(flx, "save_hdf5", lambda fn: self.__saveFluxToHDF5(meepFluxplane, fn) ) setattr(flx, "scale", lambda factor: self.__scaleFluxplane(meepFluxplane, factor) ) setattr(flx, "load_hdf5", lambda fn: self.__loadFluxFromHDF5(meepFluxplane, fn) ) LOG.debug("Meep node %i -initializeing the fluxplane ..." %(self.node_nr)) flx.initialize() LOG.debug("Meep node %i - done with fluxplane ..." %(self.node_nr))
def __addMeepSource(self, src, meep_fields): '''Convert a source (runtime.basic.__EMSource__) into a Meep source and add it to the Meep fields object''' if not isinstance(src, __EMSource__): raise InvalidArgumentException( "Invalid argument:: not of type runtime.basic.__EMSource__") LOG.debug("Meep node %i -Adding source...." % (self.node_nr)) #create Meep source object meepSource = None center_freq = 1.0 / (float(src.center_wavelength) / 1000.0) if isinstance(src, __GaussianSource__): pw = ((float(src.pulse_width) / 1000.0) / (float(src.center_wavelength) / 1000.0)) * center_freq meepSource = Meep.gaussian_src_time(center_freq, pw) if isinstance(src, __ContinuousSource__): meepSource = Meep.continuous_src_time(center_freq, src.smoothing_width, src.start_time, src.stop_time, src.cutoff) #create Meep component meepComp = self.__makeMeepComponent(src.field_component) #add source to the Meep field if isinstance(src, __EMPointSource__): vec = self.__make_meep_vec__(src.point) meep_fields.add_point_source(meepComp, meepSource, vec) print "Point source at point (%f , %f)" % (vec.x(), vec.y()) elif isinstance(src, __EMVolumeSource__): vec1 = self.__make_meep_vec__(src.south) vec2 = self.__make_meep_vec__(src.north) LOG.debug("Meep node %i -Creating volume for source plane..." % (self.node_nr)) meepSrcVol = Meep.volume(vec1, vec2) print "Meep node %i - source plane between points (%f , %f) and (%f , %f)." % ( self.node_nr, vec1.x(), vec1.y(), vec2.x(), vec2.y()) LOG.debug("Meep node %i -Now adding the volume source to Meep..." % (self.node_nr)) if isinstance(src, __AmplitudeShapedSource__): ampl = AmplitudeFactor(source=src) Meep.set_AMPL_Callback(ampl.__disown__()) meep_fields.add_volume_source(meepComp, meepSource, meepSrcVol, Meep.AMPL) else: meep_fields.add_volume_source(meepComp, meepSource, meepSrcVol, src.amplitude) else: raise NotImplementedException( "Unexpected case in MeepSimulationEngine::__addMeepSource")
def __filter_Path__(self, item): if item.line_width != 0: LOG.debug("Converting path %s into boundary." % item) resultBoundary = Boundary(item.layer, ShapePath(original_shape=item.shape, path_width=abs( item.line_width), path_type=item.path_type), transformation=item.transformation) resultBoundaryList = [resultBoundary] LOG.debug("Result has %i points" % len(resultBoundary.shape.points)) return resultBoundaryList else: LOG.debug( "Path linewidth is zero: PathToBoundaryFilter not applied.") return [item]
def initialise_engine(self, landscape): '''Initializes the Meep simulation engine. Parameter is a reference to the simulation landscape (object of type runtime.basic.SimulationLandscape) .''' self.node_nr = int(Meep.my_rank()) LOG.debug("Meep node %i -Defining the landscape in Meep..." %(self.node_nr)) if not isinstance(landscape, SimulationLandscape): raise InvalidArgumentException("Invalid argument for function setLandscape:: not of type runtime.basic.SimulationLandscape.") self.landscape = landscape Meep.use_averaging(self.use_averaging) Meep.quiet(False) LOG.debug("Meep node %i -Defining material..." %(self.node_nr)) [self.meepVol, self.dim] = self.__createMeepComputationalVolume(landscape.simulation_volume) if self.dim == 2: try: self.material = MeepMaterial2DPolygons(landscape.simulation_volume, self.meepVol) except Exception, err: LOG.error("MeepMaterial2DPolygons gives errors -> using MeepMaterial2DMatrix instead...") self.material = MeepMaterial2DMatrix(landscape.simulation_volume, self.meepVol)
def define_points(self, pts): sa = self.angle_start * DEG2RAD ea = self.angle_end * DEG2RAD bae = (ea + pi) % (2 * pi) # normalize angles between 0 and 2pi sa = (sa) % (2 * pi) ea = (ea) % (2 * pi) #angle bvetween two points connect_angle = angle_rad(self.coord_end, self.coord_start) ca_start = (connect_angle - sa) % (2 * pi) ca_end = (connect_angle - ea) % (2 * pi) #LOG.debug("ca: %f %f %f" %(, connect_angle , ca_start, ca_end)) #check both positive and negative radii valid = False signs = [(1, 1), (1, -1), (-1, 1), (-1, -1)] for s in signs: radius_start = abs(self.radius_start) * s[0] radius_end = abs(self.radius_end) * s[1] # Centers of circles through the points. c_start = (self.coord_start[0] + radius_start * sin(sa), self.coord_start[1] - radius_start * cos(sa)) c_end = (self.coord_end[0] + radius_end * sin(ea), self.coord_end[1] - radius_end * cos(ea)) #distance between centers dm = distance(c_start, c_end) if abs(radius_start - radius_end) > dm: # no valid solution possible continue # unit vector between circle centers mm = ((c_end[0] - c_start[0]) / dm, (c_end[1] - c_start[1]) / dm) # angle between normal to connector line and circle centers alpha = -acos((radius_start - radius_end) / dm) # unit vector from m to p. mp = (mm[0] * cos(alpha) + mm[1] * sin(alpha), -mm[0] * sin(alpha) + mm[1] * cos(alpha)) # Point at first circle. p0 = (c_start[0] + radius_start * mp[0], c_start[1] + radius_start * mp[1]) # Point at second circle. p1 = (c_end[0] + radius_end * mp[0], c_end[1] + radius_end * mp[1]) #LOG.debug("p0, p1:" %( p0, p1)) forward_angle = angle_rad(p1, p0) % (2 * pi) backward_angle = angle_rad(p0, p1) % (2 * pi) forward_turn = (forward_angle - sa + pi) % (2 * pi) - pi backward_turn = (backward_angle - bae + pi) % (2 * pi) - pi # LOG.debug("F: %f B:%f %f %f" % (s[0], s[1], forward_turn, backward_turn)) if (forward_turn * s[0] <= 0) and (backward_turn * s[1] >= 0): valid = True break if not valid: LOG.error("Can't connect two points with arc_line_arc") raise SystemExit #LOG.debug("angles: %f %f %f %f" %( angle_start, straight_angle*180/pi, angle_end, backward_angle*180/pi)) if forward_turn == 0.0: pts += [self.coord_start] else: pts += ShapeBendRelative(self.coord_start, abs(radius_start), sa * RAD2DEG, forward_turn * RAD2DEG, angle_step=self.angle_step) if backward_turn == 0.0: pts += [self.coord_end] else: bend2 = ShapeBendRelative(self.coord_end, abs(radius_end), bae * RAD2DEG, backward_turn * RAD2DEG, angle_step=self.angle_step) bend2.reverse() pts += bend2 return pts
def __str_structure_header__(self, item): LOG.info("STRUCTURE: " + item.name) return self.__str_object__(item)
def __scaleFluxplane(self, pFluxplane, pScalefactor): LOG.info("Scaling fluxplane with factor %f ...." % pScalefactor) pFluxplane.scale_dfts(pScalefactor) return None
def __loadFluxFromHDF5(self, pFluxplane, filename): LOG.debug( "Meep node %i -Loading initial values for fluxplane from HDF5 file %s..." % (self.node_nr, filename)) pFluxplane.load_hdf5(self.meep_fields, filename) return None
def __saveFluxToHDF5(self, pFluxplane, filename): LOG.debug("Meep node %i -Saving flux to HDF5 in file %s ..." % (self.node_nr, filename)) pFluxplane.save_hdf5(self.meep_fields, filename) return None
def __warn__(self, key): LOG.error( "Warning during export : no corresponding GDSII layer found for process %s and purpose %s" % (key.process, key.purpose))
def __filter_default__(self, item): if hasattr(item, "is_empty"): if item.is_empty(): LOG.debug("Emptyfilter is filtering out : %s" % item) return [] return [item]
def initialize(self): ## standard gratings 1550nm def STANDARD_GRATING_1550_TE(): from picazzo.fibcoup.uniform import UniformLineGrating as _ULG from ipkiss.plugins.photonics.wg.basic import WgElDefinition std1550_grating_trench = 0.315 std1550_grating_period = 0.630 std1550_grating_n_o_periods = 25 std_lin_grating_wg_def = WgElDefinition(wg_width=10.0) G = _ULG(name="std_grating_1550", origin=(0.0, 0.0), period=std1550_grating_period, line_width=std1550_grating_trench, n_o_periods=std1550_grating_n_o_periods, wg_definition=std_lin_grating_wg_def, process=TECH.PROCESS.FC) return G ## standard gratings 1550nm TM polarization def STANDARD_GRATING_1550_TM(): from picazzo.fibcoup.uniform import UniformLineGrating as _ULG from ipkiss.plugins.photonics.wg.basic import WgElDefinition std1550_grating_trench = 0.540 std1550_grating_period = 1.080 std1550_grating_n_o_periods = 16 std_lin_grating_wg_def = WgElDefinition(wg_width=10.0) G = _ULG(name="std_grating_1550_tm", origin=(0.0, 0.0), period=std1550_grating_period, line_width=std1550_grating_trench, n_o_periods=std1550_grating_n_o_periods, wg_definition=std_lin_grating_wg_def, process=TECH.PROCESS.FC) return G def STANDARD_2DGRATING_1550_TE(): from picazzo.fibcoup.uniform_2d import SymmetricUniformRect2dGrating as _UG2D from ipkiss.plugins.photonics.wg.basic import WgElDefinition std1550_2dgrating_period = 0.605 std1550_2dgrating_hole_diameter = 0.390 # desired after litho: 370 std1550_2dgrating_n_o_periods = 19 std1550_2dgrating_wg_def = WgElDefinition(wg_width=12.0) std1550_2dgrating_wg_length = 11 # length of trench before the taper starts std1550_2dgrating_trench_overlap = 4 # length of overlap between taper and fiber coupler trench std1550_2dgrating_dev_angle = 3.1 # angle deviation w/respect to 90 degrees. G = _UG2D(name="std_2dgrating_1550", period=std1550_2dgrating_period, hole_diameter=std1550_2dgrating_hole_diameter, n_o_periods=std1550_2dgrating_n_o_periods, wg_definition=std1550_2dgrating_wg_def, wg_length=std1550_2dgrating_wg_length, dev_angle=std1550_2dgrating_dev_angle, process=TECH.PROCESS.WG) return G self.DEFAULT_GRATING_TE = STANDARD_GRATING_1550_TE() self.DEFAULT_GRATING_TM = STANDARD_GRATING_1550_TM() self.DEFAULT_GRATING = self.DEFAULT_GRATING_TE try: self.DEFAULT_2D_GRATING = STANDARD_2DGRATING_1550_TE() except Exception, exc: LOG.warn("TECH.IO.FIBCOUP.DEFAULT_2D_GRATING will not be set : " + str(exc))
def define_points(self, pts): (s, R, A) = self.__original_shape_without_straight_angles__() if len(R) != len(s): raise AttributeError( "ShapeRoundAdiabaticSplineGeneric: length of radius vector should be identical to that of points in shape" ) if len(A) != len(s): raise AttributeError( "ShapeRoundAdiabaticSplineGeneric: length of adiabatic_angles vector should be identical to that of points in shape" ) if len(s) < 3: self.__points__ = s.points return margin = 0.5 / get_grids_per_unit() S = [] if not self.original_shape.closed: S.append(numpy.array([s.points[0]])) L1 = 0.0 for i in range(1, len(s) - 1): sh = AdiabaticSplineCircleSplineShape(start_point=s[i - 1], turn_point=s[i], end_point=s[i + 1], radius=R[i], adiabatic_angles=A[i], angle_step=self.angle_step) L0 = sh[0].distance(s[i]) if L0 + L1 - margin > s[i - 1].distance(s[i]): LOG.warning( "Insufficient space for spline rounding in (%f, %f)" % (s[i].x, s[i].y)) L1 = sh[-1].distance(s[i]) S.append(sh.points) if self.original_shape.closed: sh = AdiabaticSplineCircleSplineShape(start_point=s[-2], turn_point=s[-1], end_point=s[0], radius=R[-1], adiabatic_angles=A[-1], angle_step=self.angle_step) L0 = sh[0].distance(s[-1]) if L0 + L1 - margin > s[-2].distance(s[-1]): LOG.warning( "Insufficient space for spline rounding in (%f, %f)" % (s[-1].x, s[-1].y)) L1 = sh[-1].distance(s[-1]) S.append(sh.points) sh = AdiabaticSplineCircleSplineShape(start_point=s[-1], turn_point=s[0], end_point=s[1], radius=R[0], adiabatic_angles=A[0], angle_step=self.angle_step) L0 = sh[0].distance(s[0]) if L0 + L1 - margin > s[-1].distance(s[0]): LOG.warning( "Insufficient space for spline rounding in (%f, %f)" % (s[0].x, s[0].y)) L1 = sh[-1].distance(s[0]) S.append(sh.points) self.__closed__ = True else: # open curve S.append(numpy.array([s.points[-1]])) L0 = 0.0 if L0 + L1 - margin > s[-2].distance(s[-1]): LOG.warning( "Insufficient space for spline rounding in (%f, %f)" % (s[-1].x, s[-1].y)) L1 = sh[-1].distance(s[0]) self.__closed__ = False return numpy.vstack(S)
if self.dim == 2: try: self.material = MeepMaterial2DPolygons( landscape.simulation_volume, self.meepVol) except Exception, err: LOG.error( "MeepMaterial2DPolygons gives errors -> using MeepMaterial2DMatrix instead..." ) self.material = MeepMaterial2DMatrix( landscape.simulation_volume, self.meepVol) else: #dim == 3 self.material = MeepMaterial3DPolygons(landscape.simulation_volume, self.meepVol) Meep.set_EPS_Callback(self.material.__disown__()) LOG.debug("Meep node %i -Defining structure..." % (self.node_nr)) symmetry_object = Meep.identity() if (self.symmY): LOG.debug("Meep node %i -Using y symmetry!" % (self.node_nr)) symmetry_object = Meep.mirror(Meep.Y, self.meepVol) symmetry_object = symmetry_object * complex(1.0, 0.0) # When there is a certain PML direction, use that one. if isinstance(landscape.pml_direction, str): dirint = 'XYZ'.rfind(str.upper(landscape.pml_direction)) assert dirint <= 0, 'PML direction should be either X, Y or Z' if dirint == 0: direction = Meep.X if dirint == 1: direction = Meep.Y if dirint == 2: direction = Meep.Z pml = Meep.pml(landscape.pml_thickness, direction)
def define_points(self, pts): c = Shape(self.original_shape) if len(c) == 0: return if self.original_shape.is_closed(): if not c[0] == c[-1]: c.append(c[0]) #closed curve c.append(c[1]) else: # open curve pts.append(c[0]) c.remove_identicals() min_sw = self.stub_width for i in range(1, len(c) - 1): angle1 = angle_rad(c[i], c[i - 1]) angle2 = angle_rad(c[i + 1], c[i]) turn = (angle2 - angle1 + pi) % (2 * pi) - pi if turn == 0 or (abs(turn) <= (pi / 2.0) and self.only_sharp_angles): pts.append(c[i]) elif abs(turn == pi): LOG.error("Cannot stub shape with a 180 degree turn") else: d1 = distance(c[i], c[i - 1]) d2 = distance(c[i + 1], c[i]) L = self.stub_width * sin(turn / 2.0) / sin(turn) max_L = max([d1 / 2.0, d2 / 2.0]) if L > max_L: L = max_L sw = L * sin(turn) / sin(turn / 2.0) else: sw = self.stub_width if sw < min_sw: min_sw = sw theta_div2 = (pi - angle1 + angle2) % (2 * pi) / 2.0 s1 = Coord2(c[i][0] - L * cos(angle1), c[i][1] - L * sin(angle1)) s2 = (c[i][0] + L * cos(angle2), c[i][1] + L * sin(angle2)) B = -self.stub_height * sign(turn) delta = 0.5 * (self.stub_width - self.tip_width) s2 = (s1[0] + B * cos(angle1 + theta_div2) + delta * cos(angle1 + theta_div2 - pi / 2.0), s1[1] + B * sin(angle1 + theta_div2) + delta * sin(angle1 + theta_div2 - pi / 2.0)) s4 = Coord2(c[i][0] + L * cos(angle2), c[i][1] + L * sin(angle2)) s3 = (s4[0] + B * cos(angle2 + pi - theta_div2) + delta * cos(angle2 + pi - theta_div2 + pi / 2.0), s4[1] + B * sin(angle2 + pi - theta_div2) + delta * sin(angle2 + pi - theta_div2 + pi / 2.0)) pts.append(s1) pts.append(s2) pts.append(s3) pts.append(s4) if not self.original_shape.closed: # open curve pts.append(c[-1]) if min_sw < self.stub_width: LOG.warning("Stub width is reduced from " + str(self.stub_width) + " to " + str(min_sw) + "to stub shape.") return pts
def __warn__(self, key): from ipkiss.log import IPKISS_LOG as LOG LOG.error( "Warning during GDSII import : no corresponding process/purpose layer found for number = %i and datatype = %s" % (key.number, key.datatype))