import gdsfactory as gf import math

#Start of the code

def CreateHalfPad(x, y, w, d):

  LeftPad = gf.components.rectangle(size = (x, y), layer = (1, 0))
  UpperEllipse = gf.components.ellipse(radii = (d, y-w/2), layer = (1, 0))
  HalfPad = gf.boolean(LeftPad, UpperEllipse, operation = "A-B", layer = (1, 0))
  return HalfPad

def CreatePad(pad):

  pads = gf.Component()
  UpPad = CreateHalfPad(pad[0], pad[1], pad[2], pad[3])
  DownPad = CreateHalfPad(pad[0], pad[1], pad[2], pad[3])
  AddedUpPad = pads.add_ref(UpPad)
  AddedDownPad = pads.add_ref(DownPad)
  AddedDownPad.mirror()
  AddedUpPad.rotate(180)
  AddedUpPad.move([0, pad[0] -50])
  TotalPad = gf.boolean(AddedUpPad, AddedDownPad, operation = "xor", layer = (1, 0))
  return TotalPad

def CreateSNSPD(Ww, Wp, S, Squares, Tr, SameSideConnector):

  snspd = gf.components.snspd(
      wire_width=Ww,
      wire_pitch=Wp,
      size=(S[0], S[1]),
      num_squares=Squares,
      turn_ratio=Tr, # Controls the shape of the 180-degree bends in the meander(Clojure/Clojurescript library).
      terminals_same_side=SameSideConnector,
      layer=(1, 0),
  )
  return snspd

def CreateNegativeStructure(Pad, SNSPD):

  Comp_SNSPD = gf.Component() #Temporary building blocks
  Comp_Pad1 = gf.Component() #Temporary building blocks
  Comp_Pad2 = gf.Component() #Temporary building blocks
  SNSPDObj = CreateSNSPD(SNSPD[0], SNSPD[1], SNSPD[2], SNSPD[3], SNSPD[4], SNSPD[5])
  SNSPDObjAdd = Comp_SNSPD.add_ref(SNSPDObj)
  SNSPDObjAdd.move([SNSPD[2][0]/2 + (200-SNSPD[2][0])/4 , Pad[1]])
  Pad1 = CreatePad(pad = Pad)
  Pad2 = CreatePad(pad = Pad)
  Pad1.move([50, 0])
  #Pad 2 correction calculation
  #if math.floor((SNSPD[2][0])/((SNSPD[1]*2))) % 2 == 0:
  if True == False:
      correction = (math.floor((SNSPD[2][1])/((SNSPD[1]*2))) + 1) * (SNSPD[1]*2)
  else:
      correction = (round( (SNSPD[2][1])/(SNSPD[1]*2) )) * (SNSPD[1]*2)
  if SNSPD[5] == False:
      Pad2.rotate(180)
      Pad2.move([50 + SNSPD[2][0], Pad[0] - 50 - correction])
  else:
      correction = (round( (SNSPD[2][1] - 1.3*SNSPD[1])/(SNSPD[1]*2 ))) * (SNSPD[1]*2) + SNSPD[1]
      Pad2.move([50, SNSPDObjAdd.ymin - SNSPDObjAdd.ymax + SNSPD[0]])
  Comp_SNSPD.add_ref(Pad1)
  Comp_SNSPD.add_ref(Pad2)
  #Comp_Pad2.connect("o1", SNSPDObjAdd.ports["e2"], allow_layer_mismatch = True)
  ConstructionTemp = gf.boolean(SNSPDObjAdd, Pad1, operation = "xor", layer = (1, 0))
  Construction = gf.boolean(ConstructionTemp, Pad2, operation = "xor", layer = (1, 0))
  Rect1 = gf.components.rectangle(size = [Pad[0] - Pad[3], 20], layer=(2, 0))
  Rect1C = Comp_Pad1.add_ref(Rect1)
  Rect1C.move([-Pad[0] + 50, -10])
  Rect2 = gf.components.rectangle(size = [Pad[0] - Pad[3], 20], layer=(2, 0))
  Rect2C = Comp_Pad1.add_ref(Rect2)
  Rect2C.move([-Pad[0] + 50, Pad[1] * 2 -10])
  Rect3 = gf.components.rectangle(size = [20, Pad[1] * 2], layer=(2, 0))
  Rect3C = Comp_Pad1.add_ref(Rect3)
  Rect3C.move([-Pad[0] + 50, 0])
  Rect4 = gf.components.rectangle(size = [20, 100], layer=(2, 0))
  Rect4C = Comp_Pad1.add_ref(Rect4)
  Rect4C.move([-110, -10])
  Rect5 = gf.components.rectangle(size = [20, 100], layer=(2, 0))
  Rect5C = Comp_Pad1.add_ref(Rect5)
  Rect5C.move([-110, 360])
  correct = SNSPDObjAdd.ymin - SNSPDObjAdd.ymax + SNSPD[0]
  SecondRect1 = gf.components.rectangle(size = [Pad[0] - Pad[3], 20], layer=(2, 0))
  SecondRect1C = Comp_Pad1.add_ref(SecondRect1)
  SecondRect1C.move([-Pad[0] + 50, -10 + correct])
  SecondRect2 = gf.components.rectangle(size = [Pad[0] - Pad[3], 20], layer=(2, 0))
  SecondRect2C = Comp_Pad1.add_ref(SecondRect2)
  SecondRect2C.move([-Pad[0] + 50, Pad[1] * 2 -10 + correct])
  SecondRect3 = gf.components.rectangle(size = [20, Pad[1] * 2], layer=(2, 0))
  SecondRect3C = Comp_Pad1.add_ref(SecondRect3)
  SecondRect3C.move([-Pad[0] + 50, correct])
  SecondRect4 = gf.components.rectangle(size = [20, 100], layer=(2, 0))
  SecondRect4C = Comp_Pad1.add_ref(SecondRect4)
  SecondRect4C.move([-110, -10 + correct])
  SecondRect5 = gf.components.rectangle(size = [20, 100], layer=(2, 0))
  SecondRect5C = Comp_Pad1.add_ref(SecondRect5)
  SecondRect5C.move([-110, 360 + correct])
  return Construction, Comp_Pad1

def CreatePositiveStructure(Pad, SNSPD):

  c = gf.Component() #Temporary building blocks
  SNSPDObj = CreateSNSPD(SNSPD[0], SNSPD[1], SNSPD[2], SNSPD[3], SNSPD[4], SNSPD[5])
  SNSPDObjAdd = c.add_ref(SNSPDObj)
  SNSPDObjAdd.move([SNSPD[2][0]/2 + (200-SNSPD[2][0])/4 , Pad[1]])
  Pad1 = CreatePad(pad = Pad)
  Pad2 = CreatePad(pad = Pad)
  Pad1.move([50, 0])
  #Pad 2 correction calculation
  #if math.floor((SNSPD[2][0])/((SNSPD[1]*2))) % 2 == 0:
  if True == False:
      correction = (math.floor((SNSPD[2][1])/((SNSPD[1]*2))) + 1) * (SNSPD[1]*2)
  else:
      correction = (round( (SNSPD[2][1])/(SNSPD[1]*2) )) * (SNSPD[1]*2)
  Pad2.rotate(180)
  Pad2.move([50 + SNSPD[2][0], Pad[0] - 50 - correction])
  c.add_ref(Pad1)
  c.add_ref(Pad2)
  ConstructionTemp = gf.boolean(SNSPDObjAdd, Pad1, operation = "xor", layer = (1, 0))
  Construction = gf.boolean(ConstructionTemp, Pad2, operation = "xor", layer = (1, 0))
  SNSPD_area = Construction.get_region(layer = (1, 0))
  SNSPD_outline = SNSPD_area.sized(200)
  Final_SNSPD = SNSPD_outline - SNSPD_area
  return Final_SNSPD

c2 = gf.Component()

WireWidth = [ 500, 1000, 2000, 4000, 10000 ]

DetectorSize = [1000, 1000]

FillingFactor = [0.3, 0.4, 0.5, 0.6, 0.7]

WirePitch = 3

TurnRatio = 4

Temp = gf.Component()

for i in range(len(WireWidth)):

  for j in range (len(FillingFactor)):
      SNSPD, Rect = (CreateNegativeStructure(Pad = [500, 225, WireWidth[i] / 1000, 150], SNSPD = [WireWidth[i] / 1000, WireWidth[i] * (1/FillingFactor[j]) / 1000, DetectorSize, None, 4, True]))
      SNSPD.name = (str(WireWidth[i]) + "nm width " + str(FillingFactor[j]) + " ff")
      print(SNSPD.name)
      RectC = Temp.add_ref(Rect)
      SNSPDNeg = c2.add_ref(SNSPD, name = (str(WireWidth[i]) + "nm width"))
      SNSPDNeg.move([i* 1600, j*1600])
      RectC.move([i* 1600, j*1600])

for i in range(5):

  t = gf.components.text(str( i+1 ) + " (" + str( FillingFactor[i] ) + "ff)", size = 50)
  text = Temp.add_ref(t)
  text.move([-800, i*1600 - 300])

Letters = [“A”, “B”, “C”, “D”, “E”, “F”]

for i in range(5):

  t = gf.components.text(str( Letters[i]) + " (" + str( WireWidth[i] ) + "nm)", size = 50)
  text = Temp.add_ref(t)
  text.move([i*1600 + 400,  - 1000])

for i in range(4):

  for j in range(4):
      t = gf.components.text(str( Letters[j+1]) + str(i+2), size = 50)
      text = Temp.add_ref(t)
      text.move([j*1600 + 2000,  i*1600 + 700])

TotalArea = c2.get_region(layer = (1,0)) TotalAreaOutline = TotalArea.sized(600)

OnlyOutline = TotalAreaOutline - TotalArea

Outline = Temp.add_polygon(OnlyOutline, layer = (1, 0))

Temp.show() Temp.plot() Temp.write_gds(“C:/Users/alexa/OneDrive/Documenten/MyLIfeIsThereforMyLifeThinks/SNSPD Layouts/SNSPD_Chip_Aragog/Chip_Aragog.gds”, with_metadata=False)