# Title:    FP3D Layout Generator
# Author:   Matthew Banham
# Released: 02 January 2001
#
# Copyright Photon Design 1992-2001
#
# This script creates a FIMMPROP-3D component from a given .mwg or .rwg template file.
# The component is layed out in X-Z configuration and uses the effective index method
# (X-Z). The number of modes, wavelength, mode profile resolution, evstart, evend, etc.
# are all taken from the template waveguide. The variable tfilename is the filename of
# the template waveguide. This can be set outside of the script If this is left "" then the script prompts you to enter a
# filename. A new directory is created for the FIMMPROP-3D project as a sub directory of
# the directory that contains the template waveguide. Any queries regarding this script
# can be directed to support@photond.com

#NOTE THAT FIMMWAVE MUST BE RUNNING ON _hostname USING PORT NUMBER _portNo FOR THIS SCRIPT
#TO WORK. TO CHANGE THESE SETTINGS, CHANGE THE LINE THAT READS f.ConnectToApp()
#ENSURING THAT YOU USE YOUR OWN HOST AND PORT NUMBER

#**********************************************************************************************************************************
#                       Parameter Block                                                                                          #*
#                   -----------------------                                                                                      #*
# Alterable parameters are given between this line and the next line that contains asterisks.                                    #*
# Parameters that can be altered are:-                                                                                           #*
#                                                                                                                                #*
#          optimisationLevel                                                                                                     #*
#          alwaysCreateNewProject                                                                                                #*
#          tfilename                                                                                                             #*
#          templaterefname                                                                                                       #*
#          compTol                                                                                                               #*
#          _portNo                                                                                                               #*
#          _hostname                                                                                                             #*
#                                                                                                                                #*
# Please read the comments after each variable definition to find out what each variable does.                                   #*
                                                                                                                                 #*

optimisationLevel = 0 # 0,1.                                                                                                     #*
                      # 0 gives optimisation with periodic elements and reuses waveguides                                        #*
                      # 1 reuses waveguides only                                                                                 #*
                                                                                                                                 #*
alwaysCreateNewProject = 0 #set this to 1 if you always want the generator to create a new project rather than altering one      #*
                           #that is open. Note that you _will_ observe strange effects if you have more than one component       #*
                           #in a project that has been generated by this script unless you set optimisationLevel to > 0. This    #*
                           #is because the script will delete components with the name "periodX" where 'X' is a number. However, #*
                           #the script cannot currently find out which components reference components with the name "periodX"   #*
                           #and so it just deletes them all!                                                                     #*
                                                                                                                                 #*
try:                                                                                                                             #*
    tfilename #might have been set outside of this script - NB: this variable gets deleted after script has finished             #*
except NameError:                                                                                                                #*
                                                                                                                                 #*
    #CHANGE THIS VARIABLE TO YOUR TEMPLATE WAVEGUIDE FILENAME!!!!!                                                               #*
    tfilename = ""                                                                                                               #*
                                                                                                                                 #*
try:                                                                                                                             #*
    templaterefname #might have been set outside of the script - NB: this variable gets deleted after script has finished        #*
except NameError:                                                                                                                #*
                                                                                                                                 #*
    #CHANGE THIS VARIABLE TO THE OBJECT NAME OF A CURRENTLY OPENED WAVEGUIDE IN FIMMWAVE                                         #*
    templaterefname = ""                                                                                                         #*
                                                                                                                                 #*
try:                                                                                                                             #*
    _hostname #might have been set outside of this script - NB: this variable gets deleted after script has finished             #*
except NameError:                                                                                                                #*
                                                                                                                                 #*
    #CHANGE THIS TO THE HOSTNAME/IP ADDRESS WHICH FIMMWAVE IS CURRENTLY SERVING ON                                               #*
    _hostname = "localhost"                                                                                                      #*
                                                                                                                                 #*
try:                                                                                                                             #*
    _portNo #might have been set outside of this script - NB: this variable gets deleted after script has finished               #*
except NameError:                                                                                                                #*
                                                                                                                                 #*
    #CHANGE THIS TO THE PORT NO. WHICH FIMMWAVE IS CURRENTLY SERVING ON                                                          #*
    _portNo = 5101                                                                                                                #*
                                                                                                                                 #*
#change this if you want to compare waveguide parms to a different tolerance                                                     #*
compTol = 1E-9                                                                                                                   #*
                                                                                                                                 #*
#**********************************************************************************************************************************

#run signal timer update function
import sys
uptime = 0
totalProcesses = -1
percentDoneStr = ""
def updatetimer(pnumber):
    global uptime
    global percentDoneStr
    global totalProcesses
    if totalProcesses!=-1:
        numdots = int(float(pnumber)/float(totalProcesses)*40.0)
        percDoneStrlen = len(percentDoneStr)
        if percDoneStrlen!=0:
            for blob in range(1,percDoneStrlen+1):
                sys.stdout.write("\b")
        percfrac = int(float(pnumber)/float(totalProcesses)*100.0)
        percentDoneStr = "\t" + repr(percfrac) + "%" + " " + "*"*numdots + "."*(40-numdots)
        sys.stdout.write(percentDoneStr)

print "\n"    
print "*************************************************"
print "* FIMMPROP-3D Layout Generator                  *"
print "* by Matthew Banham                             *"
print "* (c) Photon Design 1992-2001                   *"
print "*************************************************"
print ""

from pdPythonLib import *
sys.stdout.write("\nConnecting to FIMMWAVE....")
f = pdApp()
f.ConnectToApp(_hostname,_portNo)
sys.stdout.write("Connected!\n")

#waveguide references so that we don't have to use filenames
#also, Tom has decided that you _must_ supply a name when you open a waveguide file which means I have to
#change this script!!! (aaaaaarrrrgggh!)
wgrefname = "wg0"
wgrefctr = -1

#NB: THIS FUNCTION FLUSHES THE COMMAND BUFFER SO BE CAREFUL WITH YOUR ADDCMD CALLS
def wgrefnameInc():
    global wgrefname
    global wgrefctr
    global f
    while(1):
        wgrefctr = wgrefctr + 1
        wgrefname = "wg"+repr(wgrefctr)
        a = f.Exec(wgrefname)
        #print a
        #raw_input("1")
        if a==None: #check to see if waveguide is in use
            break

def FilenameToNodename(fnameConv):
    c=rfind(fnameConv,"\\")
    fnameConv1=fnameConv
    if c!=-1:
        fnameConv1=fnameConv[c+1:]
    c=rfind(fnameConv1,".")
    if c!=-1:
        fnameConv1=fnameConv1[:c] + "_" + fnameConv1[c+1:]
    return fnameConv1
        
if ((tfilename=="") and (templaterefname=="")):
    #First check to see if we have any valid waveguides open
    print "Waveguides that are currently open and valid for use:\n"
    flist = []
    flistctr = 1
    for a in range(0,10):
        b = f.Exec("app.subnodes[{a+1}].filename")
        if b!=None:
            if rfind(b,".rwg")!=-1 or rfind(b,".mwg")!=-1:
                c = rfind(b,"\n") #FIMMWAVE appends a \012 to the sequence
                if c!=-1:
                    b = b[0:c]
                nname=FilenameToNodename(b)
                f.AddCmd("Ref& wg{a}=app.subnodes[{a+1}]")
                flist.append("wg"+repr(a))
                print "\t"+repr(flistctr)+": "+b
                flistctr = flistctr+1
    print ""
    tfilename = raw_input("Please enter the template filename (including the .rwg or .mwg extension)\nor select a number from the above list\n\t==> ")
    print ""
    try:
        c = atoi(tfilename)
    except:
        tfilename = tfilename #just do something!!
    else:
        templaterefname = flist[c-1]
    del flistctr
    del flist

if templaterefname!="":
    tempvar = f.Exec(templaterefname+".filename")
    c=rfind(tempvar,"\n") #occasionally, FIMMWAVE appends a carriage return
    if c!=-1:
        tempvar=tempvar[:c]
    if tempvar!=None:
        tfilename = tempvar
        f.AddCmd(templaterefname+".savetofile({tfilename})")	
        f.Exec(templaterefname+".close()")
    del tempvar

from periodicity import *
import os

def IsEqualTo(a,b):
    global compTol
    c = abs(a-b)
    if c<=compTol:
        return 1
    return 0

class guideSlice:
    def __init__(self,_width,_nrx,_nry,_alphax,_alphay):
        self.width = _width
        self.nrx = _nrx
        self.nry = _nry
        self.alphax = _alphax
        self.alphay = _alphay
    def IsSameAs(self,gslice):
        if IsEqualTo(self.width,gslice.width)==0:
            return 0
        if IsEqualTo(self.nrx,gslice.nrx)==0:
            return 0
        if IsEqualTo(self.nry,gslice.nry)==0:
            return 0
        if IsEqualTo(self.alphax,gslice.alphax)==0:
            return 0
        if IsEqualTo(self.alphay,gslice.alphay)==0:
            return 0
        return 1
        

#guideSection: these are instantiated everytime a new waveguide is needed (i.e. one that is different from the last)
class guideSection:
    def __init__(self,_name,_file,_length):
        self.name = _name
        self.file = _file
        self.length = _length
        self.slices = []

    def IsXSectionSameAs(self,guide):
        #Now check if cross-section is the same        
        for i in range(0,len(self.slices)):
            if (self.slices[i].IsSameAs(guide.slices[i]))!=1:
                return 0
        return 1
        
    #returns 0 if different, returns 1 if same
    def IsSameAs(self,guide):
        #print 'len(self.slices) = ' + repr(len(self.slices)) + '\tlen(guide.slices) = ' + repr(len(guide.slices))
        #print 'self.length = '+repr(self.length) + '\tguide.length'+repr(guide.length)
        #raw_input('')
        #first check the lengths
        if IsEqualTo(self.length,guide.length)==0:
            return 0
        if len(self.slices)!=len(guide.slices):
            return 0
        #Now check if cross-section is the same
        if self.IsXSectionSameAs(guide)==0:
            return 0
        return 1

#*****************************************************************************************************************
# At this point, tfilename is (more or less) guaranteed to be the template filename
#*****************************************************************************************************************
            
#check to see if file exists
myfile = os.open(tfilename,os.O_RDONLY)
os.close(myfile) #will raise an exception if file does not exist

a = rfind(tfilename,"\\")
if a==-1:
    tdir = "."
elif a!=1:
    tdir = tfilename[0:a]
    f.Exec("app.setwdir({tdir})")
else:
    tdir = ""
    
tname = tfilename[a+1:len(tfilename)]
c = rfind(tname,".")
if c==-1:
    raise NameError,"Bad Input File Extension"

#NB: Tom _will_ be changing the API so that this command will break but given a template filename, there is no
#way of obtaining the reference name assuming that this template file is open in FIMMWAVE somewhere.
#f.AddCmd("Ref& {tname[0:c]}_{tname[c+1:]}=app.findnode({tname[0:c]}_{tname[c+1:]})")
#f.AddCmd("{tname[0:c]}_{tname[c+1:]}.save()")
#f.Exec("{tname[0:c]}_{tname[c+1:]}.close()")

projnamestem = tname[0:rfind(tname,".")]
templaterefname1 = "templateWG"

ismwg = 0
b = rfind(tname,"rwg")
if b==-1:
    b = rfind(tname,"mwg")
    if b==-1:
        raise NameError,"Bad Input Filename"
    #the file is a mwg, therefore convert to rwg first
    wgrefnameInc()
    f.AddCmd("app.openproject({tfilename},{wgrefname})")
    f.AddCmd("Ref& {wgrefname}=app.findnode({wgrefname})")
    f.AddCmd("Set tvar1={wgrefname}.generaterwg()")
    f.AddCmd("tvar1.copy()")
    f.AddCmd("app.paste(tvar1)")
    f.AddCmd("Ref& tvar11=app.findnode(tvar1)")
    f.AddCmd("tvar11.savetofile({projnamestem}.rwg)")
    f.AddCmd("tvar11.close()")
    #NB: note that the next exec MUST OBTAIN these parms
    f.AddCmd("{wgrefname}.topbc.type")
    f.AddCmd("{wgrefname}.topbc.impedance")
    f.AddCmd("{wgrefname}.topbc.pmlpar")
    f.AddCmd("{wgrefname}.botbc.type")
    f.AddCmd("{wgrefname}.botbc.impedance")
    [lhsbc_type,lhsbc_impedance,lhsbc_pmlpar,rhsbc_type,rhsbc_impedance,rhsbc_pmlpar] = f.Exec("{wgrefname}.botbc.pmlpar")
    tfilename = tfilename[0:rfind(tfilename,".")] + ".rwg"
    ismwg = 1

compname = projnamestem + "Comp"
guides = []
instr = ""

#now find out if a project is already open and if it contains a component with the same name as compname
def getDirStr(devstr): #devStr is a compound device or any object that has an eltlist and a nelts property
    global f
    i = 1
    btemp = f.Exec("{%}.nelts",[devstr])
    while (1):
        if i>btemp:
            return "ERROR"
        btemp1 = f.Exec("{%}.eltlist[{%}]",[devstr,i])
        a = find(btemp1,"FPWGsection")
        if a!=-1:
            dirstr = f.Exec("{%}.eltlist[{%}].wg.filename",[devstr,i])
            a = rfind(dirstr,"\\")
            if (a==-1) or (a==1):
                dirstr = "."
            else:
                dirstr = dirstr[0:a]
            return dirstr
        a = find(btemp1,"FPsimplePeriodic")
        if a!=-1:
            return getDirStr(devstr+".subsect")
        i = i+1 #this element is unsuitable
                
isAlreadyCreated = 0
os.chdir(tdir)
projdir = tdir + "\\" + projnamestem + "Project"
f.AddCmd("Ref& project=app.findnode(\"project\")")
f.AddCmd("Ref& {compname}=app.findnode(\"project/"+compname+"\")")
btemp = f.Exec(compname)
if (btemp!=None) and (alwaysCreateNewProject!=1):
    isAlreadyCreated = 1
    print "Validating project..."
    projdir = getDirStr(compname+".cdev")
    f.AddCmd("app.setwdir({projdir})")
    if projdir=="ERROR":
        raise RuntimeError,"Problem with projdir"
    #First we have to delete all the elements in compname
    btemp = f.Exec("{compname}.cdev.nelts")
    a = ""
    for i in range(1,btemp+1):
        f.AddCmd("{compname}.cdev.deletesubelt(1)")
    #Now we have to remove all the "period" components
    btemp = f.Exec("project.nsubnodes")
    for i in range(btemp,-1,-1):
        f.AddCmd("Ref& period{i}=app.findnode(\"project/"+compname+"/period{i}\")")
        f.AddCmd("period{i}.delete()") #have to do this in reverse order since periodic components may have
                                              #been created contatining other periodic components
    #Now (for now) remove any other subnodes of the component
    btemp=f.Exec("{compname}.nsubnodes")
    for i in range(1,btemp+1):
        f.AddCmd("{compname}.subnodes[1].delete()")
    
    f.Exec("project.nsubnodes")
else:
    print "Setting up Directories and Files...."
    f.Exec("project.close()")
    #test to see if projdir exists
    itemp = 0
    isprojdir = 0
    projdirstem = projdir
    while (isprojdir==0):
        projdir = projdirstem + repr(itemp)    
        try:
         	chdir(projdir)
         	chdir("..")
        except:
         	isprojdir=1
        itemp = itemp + 1
    os.mkdir(projdir)
    #NOTE that the script WILL break unless this project directory is a sub directory of the
    #template directory!!!!!
    print "The Project will be created in: \n\n\t" + projdir + "\n"
    f.AddCmd("app.setwdir({projdir})")
    f.AddCmd("app.addsubnode(fimmwave_prj,project)")
    f.AddCmd("Ref& project=app.findnode(project)")
    f.AddCmd("project.savetofile({projnamestem}XZ.prj)")

print "Creating or opening template waveguide...."

#wgrefnameInc()
f.AddCmd("app.openproject({tfilename},{templaterefname1})")
f.AddCmd("Ref& {templaterefname1}=app.findnode({templaterefname1})")
f.AddCmd("app.setwdir({projdir})")
#obtain the MOLAB parms from the template waveguide
if (ismwg!=1):
    #NB: if using an rwg as the master template, then the bcs of the final device are
    #taken from the top and bottom boundary conditions of the first slice of the rwg.
    f.AddCmd("{templaterefname1}.slices[1].topbc.type")
    f.AddCmd("{templaterefname1}.slices[1].topbc.impedance")
    f.AddCmd("{templaterefname1}.slices[1].topbc.pmlpar")
    f.AddCmd("{templaterefname1}.slices[1].botbc.type")
    f.AddCmd("{templaterefname1}.slices[1].botbc.impedance")
    [lhsbc_type,lhsbc_impedance,lhsbc_pmlpar,rhsbc_type,rhsbc_impedance,rhsbc_pmlpar]=f.Exec("{templaterefname1}.slices[1].botbc.pmlpar")
    #NB: if ismwg then these parms were set earlier!!!

print "Extracting parameters from template waveguide...."

#NB: for mwg templates, when generating the corresponding rwg, the MOLAB and the solver
#parms should automatically be copied over.
f.AddCmd("{templaterefname1}.evlist.mlp.mintefrac")
f.AddCmd("{templaterefname1}.evlist.mlp.maxtefrac")
f.AddCmd("{templaterefname1}.evlist.mlp.maxnmodes")
f.AddCmd("{templaterefname1}.evlist.mlp.evstart")
f.AddCmd("{templaterefname1}.evlist.mlp.evend")
f.AddCmd("{templaterefname1}.evlist.svp.lambda")
f.AddCmd("{templaterefname1}.evlist.mlp.ny") #note that on the transpose device, nx = original ny!!!

#first create the required rwgs
[mintefrac,maxtefrac,nmodes,evstart,evend,wavelength,nx,nslice] = f.Exec("{templaterefname1}.nslice")
f.AddCmd("project.addsubnode(FPdeviceNode,{compname})")
f.AddCmd("Ref& {compname}=app.findnode(\"project/"+compname+"\")")
#set component wavelength
f.AddCmd("{compname}.lambda={wavelength}")

print "Creating Component...."
print ""

totalProcesses = nslice
currSec = 0 
for i in range(1,nslice+1): #range objects are NOT inclusive!!
    updatetimer(i)
    #obtain the section length
    f.AddCmd("{templaterefname1}.slices[{i}].width")
    
    #obtain the number of slices to be used in this section of the final device
    [slength,nlayers] = f.Exec("{templaterefname1}.slices[{i}].nlayers")
    
    #Create next internal waveguide
    guidep = guideSection(repr(currSec),"",slength)

    #Now set up the layer structure
    for k in range(1,nlayers+1): #range objects are NOT inclusive!!!
        f.AddCmd("{templaterefname1}.slices[{i}].layers[{k}].size")
        f.AddCmd("{templaterefname1}.slices[{i}].layers[{k}].nr11")
        f.AddCmd("{templaterefname1}.slices[{i}].layers[{k}].nr22")
        f.AddCmd("{templaterefname1}.slices[{i}].layers[{k}].alpha11")
        [lsize,nrx,nry,alphax,alphay] = f.Exec("{templaterefname1}.slices[{i}].layers[{k}].alpha22")
        guidep.slices.append(guideSlice(lsize,nrx,nry,alphax,alphay))

    #check to see if we already have an identical guide in the list
    hasFound = 0
    hassamexsectionas = -1
    for k in range(0,len(guides)):
        if guidep.IsSameAs(guides[k]):
            hasFound = 1
            #add the found waveguide name to the creation instructions
            instr = instr + guides[k].name + ','
            break
        if guidep.IsXSectionSameAs(guides[k])==1:
            hassamexsectionas = k

    #CAN ONLY OPERATE ON ONE WAVEGUIDE AT A TIME!!!!!!! - IMPORTANT MUST OBEY THIS RULE!!!        
    #if it hasn't found it, then we need to create a new waveguide and add it to the list
    if (hasFound==0):
        if hassamexsectionas!=-1:
            guidep.fname = guides[hassamexsectionas].fname
            guides.append(guidep)
            currSec = currSec + 1
            instr = instr + guidep.name + ','
        else:
            nextrwgfname = projnamestem + repr(currSec) + ".rwg"
            rwgname = projnamestem + repr(currSec) + "_rwg"
            wgrefnameInc() #must remember to dec this again outside this if block so that wgrefname is in sync
            #CAN ONLY OPERATE ON ONE WAVEGUIDE AT A TIME!!!!!!!
            f.AddCmd("{compname}.addsubnode(rwguideNode,{wgrefname})")
            f.AddCmd("Ref& {wgrefname}=app.findnode(\"project/"+compname+"/"+wgrefname+"\")")
            guidep.fname = wgrefname
            guides.append(guidep)
            #Set The MOLAB and the solver options
            f.AddCmd("{wgrefname}.evlist.svp.lambda={wavelength}")
            f.AddCmd("{wgrefname}.evlist.svp.solvid=6")
            f.AddCmd("{wgrefname}.evlist.svp.buff=V2 30 0 1 300 1 15")
            f.AddCmd("{wgrefname}.evlist.mlp.nx={nx}")
            f.AddCmd("{wgrefname}.evlist.mlp.ny=1") #for quasi-2D X-Z sim you don't need finite ny!!!
            f.AddCmd("{wgrefname}.evlist.mlp.autorun=1")
            f.AddCmd("{wgrefname}.lhsbc.type={lhsbc_type}")
            f.AddCmd("{wgrefname}.lhsbc.impedance={lhsbc_impedance}")
            f.AddCmd("{wgrefname}.lhsbc.pmlpar={lhsbc_pmlpar}")
            f.AddCmd("{wgrefname}.rhsbc.type={rhsbc_type}")
            f.AddCmd("{wgrefname}.rhsbc.impedance={rhsbc_impedance}")
            f.AddCmd("{wgrefname}.rhsbc.pmlpar={rhsbc_pmlpar}")
            f.AddCmd("{wgrefname}.evlist.mlp.mintefrac={mintefrac}")
            f.AddCmd("{wgrefname}.evlist.mlp.maxtefrac={maxtefrac}")
            f.AddCmd("{wgrefname}.evlist.mlp.maxnmodes={nmodes}")
            f.AddCmd("{wgrefname}.evlist.mlp.evstart={evstart}")
            f.AddCmd("{wgrefname}.evlist.mlp.evend={evend}")
            #now set up the slice structure
            for k in range(0,len(guidep.slices)):
                slicename = projnamestem + repr(currSec) + "sliceNo" + repr(k+1)
                #f.AddCmd("{wgrefname}.newlocalswg({slicename})")
                f.AddCmd("{wgrefname}.insertslice({k+1})")
                #f.AddCmd("{wgrefname}.addsubnode(slabwgNode,{slicename})")
                #f.AddCmd("{wgrefname}.setslabfromnode({k+1},{slicename})")
                #f.AddCmd("{wgrefname}.slices[{k+1}].insertlayer(1)")
                f.AddCmd("{wgrefname}.slices[{k+1}].layers[1].size=0.00001")
                f.AddCmd("{wgrefname}.slices[{k+1}].layers[1].nr11={guidep.slices[k].nrx}")
                f.AddCmd("{wgrefname}.slices[{k+1}].layers[1].nr22={guidep.slices[k].nry}")
                f.AddCmd("{wgrefname}.slices[{k+1}].layers[1].alpha11={guidep.slices[k].alphax}")
                f.AddCmd("{wgrefname}.slices[{k+1}].layers[1].alpha22={guidep.slices[k].alphay}")
                f.AddCmd("{wgrefname}.slices[{k+1}].width={guidep.slices[k].width}")
            currSec = currSec + 1
            instr = instr + guidep.name + ','

#by now we should have a list of guides and an instruction string
#this will recognise the periodic bits in instr and group them properly
#last element in instr will be a ','
instr = instr[0:len(instr)-1]
comp = component()
comp.CreateComponent(instr)
if optimisationLevel<1:
    comp.MakePeriodic()

#we now have a structure which will allow us to create our component
#we now need a function to lay it out for us

pcompCounter = 0
def fp3dlayouter(compObj,_compname,fsender,rootNodeStr):
    global pcompCounter
    global guides
    secNo = 1
    for i in range(0,len(compObj.eltList)):
        etype = compObj.eltList[i].etype
        if etype==3: #the element is a periodic component
            fsender.AddCmd("{%}.cdev.newspsect({%})",[_compname,secNo])
            fsender.AddCmd("{%}.cdev.eltlist[{%}].joint_method=3",[_compname,secNo])
            fsender.AddCmd("{%}.cdev.eltlist[{%}].nperiod={%}",[_compname,secNo,compObj.eltList[i].nperiods])
            newname = 'period'+repr(pcompCounter)
            
            fsender.AddCmd("{%}.addsubnode(FPdeviceNode,{%})",[_compname,newname])
            fsender.AddCmd("Ref& {%}=app.findnode(\"project/"+_compname+"/"+newname+"\")",[newname])
            
            fsender.AddCmd("{%}.cdev.copy",[newname])
            fsender.AddCmd("{%}.cdev.eltlist[{%}].pastesubelt",[_compname,secNo])
            pcompCounter = pcompCounter+1
            secNo = secNo + 1
            #now layout the period
            fp3dlayouter(compObj.eltList[i],newname,fsender,rootNodeStr)
            fsender.AddCmd("{%}.updateviews()",[newname])
        else: #else assume that it is a simple element
            #first find the name of the waveguide
            name = compObj.eltList[i].obj
            #now look it up in the list of objects
            idx = 0
            while(1):
                if idx>=len(guides):
                    idx = -1
                    break
                if guides[idx].name==name:
                    break
                idx = idx+1
            if idx==-1:
                raise RuntimeError,'Error in fp3dlayouter'
            #now we need to insert a new section into _compname with the properties of
            #guides[idx]
            fsender.AddCmd("{%}.cdev.newwgsect({%})",[_compname,secNo])
            fsender.AddCmd("{%}.cdev.eltlist[{%}].setwg({%})",[_compname,secNo,rootNodeStr+"/"+guides[idx].fname])
            fsender.AddCmd("{%}.cdev.eltlist[{%}].length={%}",[_compname,secNo,guides[idx].length])
            secNo = secNo + 1

        #now add a joint if needed        
        if (i!=len(compObj.eltList)-1):
            fsender.AddCmd("{%}.cdev.newsjoint({%})",[_compname,secNo])
            fsender.AddCmd("{%}.cdev.eltlist[{%}].method=3",[_compname,secNo])
            secNo = secNo + 1

#layout our component
fp3dlayouter(comp,compname,f,"/project/"+compname)

#now clean up the waveguide references
for i in range(0,wgrefctr+1):
    f.AddCmd("Del wg{i}")

f.AddCmd("project.savetofile()")
f.Exec("{compname}.updateviews()")
#NB: MUST HAVE AT LEAST ONE EXEC COMMAND OUTSIDE THE LOOP SO AS TO FLUSH THE TCP/IP
#MESSAGE QUEUE!!!!

#if mwg then delete intermediate waveguide template
if (ismwg==1):
    f.Exec("{templaterefname1}.close()")
    os.chdir(tdir)
    os.remove(projnamestem+".rwg")
del f

#delete tfilename and templaterefname so that consecutive calls work (sort of) correctly
del tfilename
del templaterefname
del _portNo
del _hostname

#Now beep to let the user know that we are done
print "\a\a\a"


