diff options
Diffstat (limited to 'src/ngspicetoModelica/NgspicetoModelica.py')
-rw-r--r-- | src/ngspicetoModelica/NgspicetoModelica.py | 1123 |
1 files changed, 1123 insertions, 0 deletions
diff --git a/src/ngspicetoModelica/NgspicetoModelica.py b/src/ngspicetoModelica/NgspicetoModelica.py new file mode 100644 index 00000000..7b7e4527 --- /dev/null +++ b/src/ngspicetoModelica/NgspicetoModelica.py @@ -0,0 +1,1123 @@ +import sys +import os +import re +import json +from string import maketrans + +class NgMoConverter: + + + def __init__(self, map_json): + #Loading JSON file which hold the mapping information between ngspice and Modelica. + with open(map_json) as mappingFile: + self.mappingData = json.load(mappingFile) + + self.ifMOS = False + self.sourceDetail = [] + self.deviceDetail = [] + self.subCktDetail = [] + self.deviceList = ['d','D','j','J','q','Q','m','M'] + self.sourceList = ['v','V','i','I'] + + + + + + def readNetlist(self,filename): + """ + Read Ngspice Netlist + """ + netlist = [] + if os.path.exists(filename): + try: + f = open(filename) + except Exception as e: + print("Error in opening file") + print(str(e)) + sys.exit() + else: + print filename + " does not exist" + sys.exit() + + data = f.read() + data = data.splitlines() + f.close() + for eachline in data: + eachline=eachline.strip() + if len(eachline)>1: + if eachline[0]=='+': + netlist.append(netlist.pop()+eachline.replace('+',' ',1)) + else: + netlist.append(eachline) + + return netlist + + def separateNetlistInfo(self,netlist): + """ + Separate schematic data and option data + """ + optionInfo = [] + schematicInfo = [] + + + + for eachline in netlist: + + if len(eachline) > 1: + if eachline[0]=='*': + continue + elif eachline[0]=='.': + optionInfo.append(eachline) + #optionInfo.append(eachline.lower()) + elif eachline[0] in self.deviceList: + if eachline[0]=='m' or eachline[0]=='M': + self.ifMOS = True + schematicInfo.append(eachline) + self.deviceDetail.append(eachline) + elif eachline[0]=='x' or eachline[0]=='X': + schematicInfo.append(eachline) + self.subCktDetail.append(eachline) + elif eachline[0] in self.sourceList: + schematicInfo.append(eachline) + self.sourceDetail.append(eachline) + elif eachline[0]=='a' or eachline[0]=='A': + schematicInfo.append(eachline) + else: + schematicInfo.append(eachline) + ##No need of making it lower case as netlist is already converted to ngspice + #schematicInfo.append(eachline.lower()) + + + return optionInfo,schematicInfo + + def addModel(self,optionInfo): + """ + Add model parameters in the modelica file and create dictionary of model parameters + This function extract model and subckt information along with their parameters with the help of optionInfo + """ + modelName = [] + modelInfo = {} + subcktName = [] + paramInfo = [] + transInfo = {} + inbuiltModelDict = {} + + for eachline in optionInfo: + words = eachline.split() + if words[0] == '.include': + name = words[1].split('.') + if name[1] == 'lib': + modelName.append(name[0]) + if name[1] == 'sub': + subcktName.append(name[0]) + elif words[0] == '.param': + paramInfo.append(eachline) + elif words[0] == '.model': + model = words[1] + modelInfo[model] = {} + eachline = eachline.replace(' = ','=').replace('= ','=').replace(' =','=') + eachline = eachline.split('(') + templine = eachline[0].split() + trans = templine[1] + transInfo[trans] = [] + templine[2] = templine[2].lower() + if templine[2] in ['npn', 'pnp', 'pmos', 'nmos','njf','pjf']: + transInfo[trans] = templine[2] + else: + inbuiltModelDict[model]=templine[2] + eachline[1] = eachline[1].lower() + eachline = eachline[1].split() + for eachitem in eachline: + if len(eachitem) > 1: + eachitem = eachitem.replace(')','') + iteminfo = eachitem.split('=') + for each in iteminfo: + modelInfo[model][iteminfo[0]] = iteminfo[1] + + #Adding details of model(external) and subckt into modelInfo and subcktInfo + for eachmodel in modelName: + filename = eachmodel + '.lib' + if os.path.exists(filename): + try: + f = open(filename) + except: + print("Error in opening file") + sys.exit() + else: + print filename + " does not exist" + sys.exit() + data = f.read() + data = data.replace('+', '').replace('\n','').replace(' = ','=').replace('= ','=').replace(' =','=') + #data = data.lower() #Won't work if Reference model name is Upper Case + newdata = data.split('(') + templine_f = newdata[0].split() + trans_f = templine_f[1] + transInfo[trans_f] = [] + templine_f[2] = templine_f[2].lower() + if templine_f[2] in ['npn', 'pnp', 'pmos', 'nmos','njf','pjf']: + transInfo[trans_f] = templine_f[2] + + refModelName = trans_f + newdata[1] = newdata[1].lower() + modelParameter = newdata[1].split() + + modelInfo[refModelName] = {} + + for eachline in modelParameter: + if len(eachline) > 1: + eachline = eachline.replace(')','') + info = eachline.split('=') + for eachitem in info: + modelInfo[refModelName][info[0]] = info[1] + f.close() + + + + + return modelName, modelInfo, subcktName, paramInfo ,transInfo,inbuiltModelDict + + def processParam(self,paramInfo): + """ + Process parameter info and update in Modelica syntax + """ + modelicaParam = [] + for eachline in paramInfo: + eachline = eachline.split('.param') + #Include ',' in between parameter + #Removing leading and trailing space + line = eachline[1].strip() + line = line.split() + final_line = ','.join(line) + stat = 'parameter Real ' + final_line + ';' + stat = stat.translate(maketrans('{}', ' ')) + modelicaParam.append(stat) + return modelicaParam + + + def separatePlot(self,schematicInfo): + """ + separate print plot and component statements + """ + compInfo = [] + plotInfo = [] + for eachline in schematicInfo: + words = eachline.split() + if words[0] == 'run': + continue + elif words[0] == 'plot' or words[0] == 'print': + plotInfo.append(eachline) + else: + compInfo.append(eachline) + return compInfo, plotInfo + + def separateSource(self,compInfo): + """ + Find if dependent sources are present in the schematic and if so make a dictionary with source details + """ + sourceInfo = {} + source = [] + for eachline in compInfo: + words = eachline.split() ##This line need to be confirmed with Manas + if eachline[0] in ['f', 'h']: + source.append(words[3]) + if len(source) > 0: + for eachline in compInfo: + words_s = eachline.split() + if words_s[0] in source: + sourceInfo[words_s[0]] = words_s[1:3] + return sourceInfo + + def getUnitVal(self,compValue): + #regExp = re.compile("([0-9]+)([a-zA-Z]+)") + #Remove '(' and ')' if any + compValue = compValue.replace('(','').replace(')','') + compValue = compValue.lower() + #regExp = re.compile("([-])?([0-9]+)\.?([0-9]+)?([a-zA-Z])?") + regExp = re.compile("([-])?([0-9]+)\.?([0-9]+)?(\w+)?") + matchString = regExp.match(str(compValue)) #separating number and string + try: + signVal = matchString.group(1) + valBeforeDecimal = matchString.group(2) + valAfterDecimal = matchString.group(3) + unitValue = matchString.group(4) + modifiedcompValue = "" + if str(signVal)=='None': + pass + else: + modifiedcompValue += signVal + + modifiedcompValue += valBeforeDecimal + + if str(valAfterDecimal)=='None': + pass + else: + modifiedcompValue += '.'+valAfterDecimal + + if str(unitValue)=='None': + pass + else: + modifiedcompValue += self.mappingData["Units"][unitValue] + + return modifiedcompValue + except: + return compValue + + + def compInit(self,compInfo, node, modelInfo, subcktName,dir_name,transInfo,inbuiltModelDict): + """ + For each component in the netlist initialize it according to Modelica format + """ + #print "CompInfo inside compInit function : compInit------->",compInfo + #### initial processing to check if MOs is present. If so, library to be used is BondLib + modelicaCompInit = [] + numNodesSub = {} + mosInfo = {} + IfMOS = '0' + + for eachline in compInfo: + #words = eachline.split() + if eachline[0] == 'm': + IfMOS = '1' + break + if len(subcktName) > 0: + subOptionInfo = [] + subSchemInfo = [] + for eachsub in subcktName: + filename_tem = eachsub + '.sub' + filename_tem = os.path.join(dir_name, filename_tem) + data = self.readNetlist(filename_tem) + subOptionInfo, subSchemInfo = self.separateNetlistInfo(data) + + for eachline in subSchemInfo: + #words = eachline.split() + if eachline[0] == 'm': + IfMOS = '1' + break + + #Lets Start with Source details + for eachline in self.sourceDetail: + words = eachline.split() + #Preserve component name from lower case function + compName = words[0] + #Now Lower case all other + words = eachline.lower().split() + words[0] = compName + typ = words[3].split('(') + + sourceType = compName[0].lower() + + if sourceType == 'v': + if typ[0] == "pulse": + per = words[9].split(')') + stat = self.mappingData["Sources"][sourceType][typ[0]]+' '+compName+'(rising = '+self.getUnitVal(words[6])+', V = '+self.getUnitVal(words[4])\ + +', width = '+self.getUnitVal(words[8])+', period = '+self.getUnitVal(per[0])+', offset = '+self.getUnitVal(typ[1])+', startTime = '+self.getUnitVal(words[5])+', falling = '+self.getUnitVal(words[7])+');' + modelicaCompInit.append(stat) + if typ[0] == "sine": + theta = words[7].split(')') + stat = self.mappingData["Sources"][sourceType][typ[0]]+' '+compName+'(offset = '+self.getUnitVal(typ[1])+', V = '+self.getUnitVal(words[4])+', freqHz = '+self.getUnitVal(words[5])+', startTime = '+self.getUnitVal(words[6])+', phase = '+self.getUnitVal(theta[0])+');' + modelicaCompInit.append(stat) + if typ[0] == "pwl": + keyw = self.mappingData["Sources"][sourceType][typ[0]]+' ' + stat = keyw + compName + '(table = [' + self.getUnitVal(typ[1]) + ',' + self.getUnitVal(words[4]) + ';' + length = len(words); + for i in range(6,length,2): + if i == length-2: + w = words[i].split(')') + stat = stat + self.getUnitVal(words[i-1]) + ',' + self.getUnitVal(w[0]) + else: + stat = stat + self.getUnitVal(words[i-1]) + ',' + self.getUnitVal(words[i]) + ';' + stat = stat + ']);' + modelicaCompInit.append(stat) + if typ[0] == words[3] and typ[0] != "dc": + #It is DC constant but no dc keyword + val_temp = typ[0].split('v') + stat = self.mappingData["Sources"][sourceType]["dc"]+' ' + compName + '(V = ' + self.getUnitVal(val_temp[0]) + ');' + modelicaCompInit.append(stat) + elif typ[0] == words[3] and typ[0] == "dc": + stat = self.mappingData["Sources"][sourceType][typ[0]]+' ' + compName + '(V = ' + self.getUnitVal(words[4]) + ');' ### check this + modelicaCompInit.append(stat) + + elif sourceType=='i': + stat = self.mappingData["Sources"][sourceType]["dc"]+' '+compName+'(I='+self.getUnitVal(words[3])+');' + modelicaCompInit.append(stat) + + #Now empty the source list as it may be used by subcircuit + self.sourceDetail[:] = [] + + #print "Source Detail after processing-------->",self.sourceDetail + + #Lets start for device + for eachline in self.deviceDetail: + words=eachline.split() + deviceName = eachline[0].lower() + if deviceName=='d': + if len(words)>3: + if modelInfo[words[3]].has_key('n'): + n = float(modelInfo[words[3]]['n']) + else: + n = 1.0 + vt = str(float(0.025*n)) + #stat = self.mappingData["Devices"][deviceName]["import"]+' '+ words[0] + '(Ids = ' + modelInfo[words[3]]['is'] + ', Vt = ' + vt + ', R = 1e12' +');' + start = self.mappingData["Devices"][deviceName]["import"] + stat = start+" "+words[0]+"(" + tempstatList=[] + userDeviceParamList=[] + refName = words[-1] + for key in modelInfo[refName]: + #If parameter is not mapped then it will just pass + try: + actualModelicaParam = self.mappingData["Devices"][deviceName]["mapping"][key] + tempstatList.append(actualModelicaParam+"="+self.getUnitVal(modelInfo[refName][key])+" ") + userDeviceParamList.append(str(actualModelicaParam)) + except: + pass + #Adding Vt and R + userDeviceParamList.append("Vt") + tempstatList.append("Vt="+vt) + #Running loop over default parameter of OpenModelica + for default in self.mappingData["Devices"][deviceName]["default"]: + if default in userDeviceParamList: + continue + else: + defaultValue = self.mappingData["Devices"][deviceName]["default"][default] + tempstatList.append(default+"="+self.getUnitVal(defaultValue)+" ") + + stat += ",".join(str(item) for item in tempstatList)+");" + + else: + stat = self.mappingData["Devices"][deviceName]["import"]+" "+ words[0] +";" + modelicaCompInit.append(stat) + + elif deviceName=='q': + trans = transInfo[words[4]] + if trans == 'npn': + start = self.mappingData["Devices"][deviceName]["import"]+".NPN" + elif trans == 'pnp': + start = self.mappingData["Devices"][deviceName]["import"]+".PNP" + else: + print "Transistor "+str(trans)+" Not found" + sys.exit(1) + + stat = start+" "+words[0]+"(" + tempstatList=[] + userDeviceParamList=[] + refName = words[4] + for key in modelInfo[refName]: + #If parameter is not mapped then it will just pass + try: + if key=="vaf": + inv_vak = float(self.getUnitVal(modelInfo[refName][key])) + vak_temp = 1/inv_vak + vak = str(vak_temp) + tempstatList.append("Vak="+vak+" ") + userDeviceParamList.append(str("Vak")) + else: + actualModelicaParam = self.mappingData["Devices"][deviceName]["mapping"][key] + tempstatList.append(actualModelicaParam+"="+self.getUnitVal(modelInfo[refName][key])+" ") + userDeviceParamList.append(str(actualModelicaParam)) + except: + pass + #Running loop over default parameter of OpenModelica + for default in self.mappingData["Devices"][deviceName]["default"]: + if default in userDeviceParamList: + continue + else: + defaultValue = self.mappingData["Devices"][deviceName]["default"][default] + tempstatList.append(default+"="+self.getUnitVal(defaultValue)+" ") + + stat += ",".join(str(item) for item in tempstatList)+");" + modelicaCompInit.append(stat) + + elif deviceName=='m': + eachline = eachline.split(words[5]) + eachline = eachline[1] + eachline = eachline.strip() + eachline = eachline.replace(' = ', '=').replace('= ','=').replace(' =','=').replace(' * ', '*').replace(' + ', '+').replace(' { ', '').replace(' } ', '') + eachline = eachline.split() + mosInfo[words[0]] = {} + for each in eachline: + if len(each) > 1: + each = each.split('=') + mosInfo[words[0]][each[0]] = each[1] + trans = transInfo[words[5]] + + if trans == 'nmos': + start = self.mappingData["Devices"][deviceName]["import"]+".Mn" + elif trans=='pmos' : + start = self.mappingData["Devices"][deviceName]["import"]+".Mp" + else: + print "MOSFET "+str(trans)+" not found" + sys.exit(1) + + + stat = start+" "+words[0]+"(" + tempstatList=[] + userDeviceParamList=[] + refName = words[5] + + for key in modelInfo[refName]: + #If parameter is not mapped then it will just pass + try: + if key=="uo": + U0 = str(float(self.getUnitVal(modelInfo[refName][key]))*0.0001) + tempstatList.append("U0="+U0+" ") + userDeviceParamList.append(str("U0")) + else: + actualModelicaParam = self.mappingData["Devices"][deviceName]["mapping"][key] + tempstatList.append(actualModelicaParam+"="+self.getUnitVal(modelInfo[refName][key])+" ") + userDeviceParamList.append(str(actualModelicaParam)) + except Exception as err: + print str(err) + + #Running loop over default parameter of OpenModelica + for default in self.mappingData["Devices"][deviceName]["default"]: + if default in userDeviceParamList: + continue + else: + defaultValue = self.mappingData["Devices"][deviceName]["default"][default] + tempstatList.append(default+"="+self.getUnitVal(defaultValue)+" ") + + + #Adding LEVEL(This is constant not the device level) + tempstatList.append("Level=1"+" ") + + try: + l = mosInfo[words[0]]['l'] + tempstatList.append("L="+self.getUnitVal(l)+" ") + except KeyError: + tempstatList.append("L=1e-6"+" ") + try: + w = mosInfo[words[0]]['w'] + tempstatList.append("W="+self.getUnitVal(w)+" ") + except KeyError: + tempstatList.append("W=100e-6"+" ") + try: + As = mosInfo[words[0]]['as'] + ad = mosInfo[words[0]]['ad'] + tempstatList.append("AS="+self.getUnitVal(As)+" ") + tempstatList.append("AD="+self.getUnitVal(ad)+" ") + except KeyError: + tempstatList.append("AS=0"+" ") + tempstatList.append("AD=0"+" ") + try: + ps = mosInfo[words[0]]['ps'] + pd = mosInfo[words[0]]['pd'] + tempstatList.append("PS="+self.getUnitVal(ps)+" ") + tempstatList.append("PD="+self.getUnitVal(pd)+" ") + except KeyError: + tempstatList.append("PS=0"+" ") + tempstatList.append("PD=0"+" ") + + stat += ",".join(str(item) for item in tempstatList)+");" + modelicaCompInit.append(stat) + + elif deviceName=='j': + trans = transInfo[words[4]] + """ + if trans == 'njf': + start = self.mappingData["Devices"][deviceName]["import"]+".J_NJFJFET" + elif trans == 'pjf': + start = self.mappingData["Devices"][deviceName]["import"]+".J_PJFJFET" + else: + print "JFET "+str(trans)+" Not found" + sys.exit(1) + """ + start = self.mappingData["Devices"][deviceName]["import"] + + stat = start+" "+words[0]+"(modelcard(" + tempstatList=[] + userDeviceParamList=[] + refName = words[4] + for key in modelInfo[refName]: + #If parameter is not mapped then it will just pass + try: + actualModelicaParam = self.mappingData["Devices"][deviceName]["mapping"][key] + tempstatList.append(actualModelicaParam+"="+self.getUnitVal(modelInfo[refName][key])+" ") + userDeviceParamList.append(str(actualModelicaParam)) + except: + pass + #Running loop over default parameter of OpenModelica + for default in self.mappingData["Devices"][deviceName]["default"]: + if default in userDeviceParamList: + continue + else: + defaultValue = self.mappingData["Devices"][deviceName]["default"][default] + tempstatList.append(default+"="+self.getUnitVal(defaultValue)+" ") + + stat += ",".join(str(item) for item in tempstatList)+"));" + modelicaCompInit.append(stat) + + + + #Empty device details as well + self.deviceDetail[:]=[] + + #Lets start for Subcircuit + for eachline in self.subCktDetail: + global point + global subname + temp_line = eachline.split() + temp = temp_line[0].split('x') + index = temp[1] + for i in range(0,len(temp_line),1): + if temp_line[i] in subcktName: + subname = temp_line[i] + numNodesSub[subname] = i - 1 + point = i + if len(temp_line) > point + 1: + rem = temp_line[point+1:len(temp_line)] + rem_new = ','.join(rem) + stat = subname + ' ' + subname +'_instance' + index + '(' + rem_new + ');' + else: + stat = subname + ' ' + subname +'_instance' + index + ';' + modelicaCompInit.append(stat) + + #Empty Sub Circuit Detail + self.subCktDetail[:] = [] + + #Lets start for inbuilt model of ngspice + for eachline in compInfo: + words=eachline.split() + value = self.getUnitVal(words[-1]) + if eachline[0] == 'a' or eachline[0] == 'A': + userModelParamList = [] + refName = words[-1] + actualModelName = inbuiltModelDict[refName] + + start = self.mappingData["Models"][actualModelName]["import"] + stat = start +" "+ words[0]+"(" + tempstatList=[] + + for key in modelInfo[refName]: + #If parameter is not mapped then it will just pass + try: + actualModelicaParam = self.mappingData["Models"][actualModelName]["mapping"][key] + tempstatList.append(actualModelicaParam+"="+self.getUnitVal(modelInfo[refName][key])+" ") + userModelParamList.append(str(actualModelicaParam)) + except: + pass + + #Running loop over default parameter of OpenModelica + for default in self.mappingData["Models"][actualModelName]["default"]: + if default in userModelParamList: + continue + else: + defaultValue = self.mappingData["Models"][actualModelName]["default"][default] + tempstatList.append(default+"="+self.getUnitVal(defaultValue)+" ") + + stat += ",".join(str(item) for item in tempstatList)+");" + modelicaCompInit.append(stat) + + elif eachline[0] == 'r': + stat = 'Analog.Basic.Resistor ' + words[0] + '(R = ' + value + ');' + modelicaCompInit.append(stat) + elif eachline[0] == 'c': + stat = 'Analog.Basic.Capacitor ' + words[0] + '(C = ' + value + ');' + modelicaCompInit.append(stat) + elif eachline[0] == 'l': + stat = 'Analog.Basic.Inductor ' + words[0] + '(L = ' + value + ');' + modelicaCompInit.append(stat) + elif eachline[0] == 'e': + stat = 'Analog.Basic.VCV ' + words[0] + '(gain = ' + self.getUnitVal(words[5]) + ');' + modelicaCompInit.append(stat) + elif eachline[0] == 'g': + stat = 'Analog.Basic.VCC ' + words[0] + '(transConductance = ' + self.getUnitVal(words[5]) + ');' + modelicaCompInit.append(stat) + elif eachline[0] == 'f': + stat = 'Analog.Basic.CCC ' + words[0] + '(gain = ' + self.getUnitVal(words[4]) + ');' + modelicaCompInit.append(stat) + elif eachline[0] == 'h': + stat = 'Analog.Basic.CCV ' + words[0] + '(transResistance = ' + self.getUnitVal(words[4]) + ');' + modelicaCompInit.append(stat) + else: + continue + + + if '0' or 'gnd' in node: + modelicaCompInit.append('Analog.Basic.Ground g;') + return modelicaCompInit, numNodesSub + + def getSubInterface(self,subname,numNodesSub): + """ + Get the list of nodes for subcircuit in .subckt line + """ + subOptionInfo_p = [] + subSchemInfo_p = [] + filename_t = subname + '.sub' + data_p = self.readNetlist(filename_t) + subOptionInfo_p, subSchemInfo_p = self.separateNetlistInfo(data_p) + if len(subOptionInfo_p) > 0: + newline = subOptionInfo_p[0] + newline = newline.split('.subckt '+ subname) + intLine = newline[1].split() + newindex = numNodesSub[subname] + nodesInfoLine = intLine[0:newindex] + return nodesInfoLine + + def getSubParamLine(self,subname, numNodesSub, subParamInfo,dir_name): + """ + Take subcircuit name and give the info related to parameters in the first line and initialize it in + """ + #nodeSubInterface = [] + subOptionInfo_p = [] + subSchemInfo_p = [] + filename_t = subname + '.sub' + filename_t = os.path.join(dir_name, filename_t) + data_p = self.readNetlist(filename_t) + subOptionInfo_p, subSchemInfo_p = self.separateNetlistInfo(data_p) + + if len(subOptionInfo_p) > 0: + newline = subOptionInfo_p[0] + newline = newline.split('.subckt '+ subname) + intLine = newline[1].split() + newindex = numNodesSub[subname] + appen_line = intLine[newindex:len(intLine)] + appen_param = ','.join(appen_line) + paramLine = 'parameter Real ' + appen_param + ';' + paramLine = paramLine.translate(maketrans('{}', ' ')) + subParamInfo.append(paramLine) + return subParamInfo + + def nodeSeparate(self,compInfo, ifSub, subname, subcktName,numNodesSub): + """ + separate the node numbers and create nodes in modelica file; + the nodes in the subckt line should not be inside protected keyword. pinInit is the one that goes under protected keyword. + """ + node = [] + nodeTemp = [] + nodeDic = {} + pinInit = 'Modelica.Electrical.Analog.Interfaces.Pin ' + pinProtectedInit = 'Modelica.Electrical.Analog.Interfaces.Pin ' + protectedNode = [] + #print "CompInfo coming to nodeSeparate function: compInfo",compInfo + + #Removing '[' and ']' from compInfo for Digital node + for i in range(0,len(compInfo),1): + compInfo[i] = compInfo[i].replace("[","").replace("]","") + + + for eachline in compInfo: + words = eachline.split() + + if eachline[0] in ['m', 'e', 'g', 't','M','E','G','T']: + nodeTemp.append(words[1]) + nodeTemp.append(words[2]) + nodeTemp.append(words[3]) + nodeTemp.append(words[4]) + elif eachline[0] in ['q', 'j','J','Q']: + nodeTemp.append(words[1]) + nodeTemp.append(words[2]) + nodeTemp.append(words[3]) + elif eachline[0]=='x' or eachline[0]=='X': + templine = eachline.split() + for i in range(0,len(templine),1): + if templine[i] in subcktName: + point = i + #print "Added in node----->",words[1:point] + nodeTemp.extend(words[1:point]) + else: + nodeTemp.append(words[1]) + nodeTemp.append(words[2]) + + + + #Replace hyphen '-' from node + for i in nodeTemp: + if i not in node: + i = i.replace("-","") + node.append(i) + + + for i in range(0, len(node),1): + nodeDic[node[i]] = 'n' + node[i] + if ifSub == '0': + if i != len(node)-1: + pinInit = pinInit + nodeDic[node[i]] + ', ' + else: + pinInit = pinInit + nodeDic[node[i]] + else: + nonprotectedNode = self.getSubInterface(subname, numNodesSub) + if node[i] in nonprotectedNode: + continue + else: + protectedNode.append(node[i]) + if ifSub == '1': + if len(nonprotectedNode) > 0: + for i in range(0, len(nonprotectedNode),1): + if i != len(nonprotectedNode)-1: + pinProtectedInit = pinProtectedInit + nodeDic[nonprotectedNode[i]] + ',' + else: + pinProtectedInit = pinProtectedInit + nodeDic[nonprotectedNode[i]] + if len(protectedNode) > 0: + for i in range(0, len(protectedNode),1): + if i != len(protectedNode)-1: + pinInit = pinInit + nodeDic[protectedNode[i]] + ',' + else: + pinInit = pinInit + nodeDic[protectedNode[i]] + pinInit = pinInit + ';' + pinProtectedInit = pinProtectedInit + ';' + #print "Node---->",node + #print "nodeDic----->",nodeDic + #print "PinInit----->",pinInit + #print "pinProtectedinit--->",pinProtectedInit + return node, nodeDic, pinInit, pinProtectedInit + + + def connectInfo(self,compInfo, node, nodeDic, numNodesSub,subcktName): + """ + Make node connections in the modelica netlist + """ + connInfo = [] + sourcesInfo = self.separateSource(compInfo) + for eachline in compInfo: + words = eachline.split() + + #Remove '-' from compInfo + for i in range(0,len(words),1): + words[i] = words[i].replace("-","") + + if eachline[0]=='r' or eachline[0]=='R' or eachline[0]=='c' or eachline[0]=='C' or eachline[0]=='d' or eachline[0]=='D' \ + or eachline[0]=='l' or eachline[0]=='L' or eachline[0]=='v' or eachline[0]=='V' or eachline[0]=='i' or eachline[0]=='I': + conn = 'connect(' + words[0] + '.p,' + nodeDic[words[1]] + ');' + connInfo.append(conn) + conn = 'connect(' + words[0] + '.n,' + nodeDic[words[2]] + ');' + connInfo.append(conn) + elif eachline[0]=='q' or eachline[0]=='Q': + conn = 'connect(' + words[0] + '.C,' + nodeDic[words[1]] + ');' + connInfo.append(conn) + conn = 'connect(' + words[0] + '.B,' + nodeDic[words[2]] + ');' + connInfo.append(conn) + conn = 'connect(' + words[0] + '.E,' + nodeDic[words[3]] + ');' + connInfo.append(conn) + elif eachline[0]=='j' or eachline[0]=='J': + conn = 'connect('+words[0]+'.D,' + nodeDic[words[1]]+');' + connInfo.append(conn) + conn = 'connect('+words[0]+'.G,' + nodeDic[words[2]]+');' + connInfo.append(conn) + conn = 'connect('+words[0]+'.S,' + nodeDic[words[3]]+');' + connInfo.append(conn) + elif eachline[0]=='m' or eachline[0]=='M': + conn = 'connect(' + words[0] + '.D,' + nodeDic[words[1]] + ');' + connInfo.append(conn) + conn = 'connect(' + words[0] + '.G,' + nodeDic[words[2]] + ');' + connInfo.append(conn) + conn = 'connect(' + words[0] + '.S,' + nodeDic[words[3]] + ');' + connInfo.append(conn) + conn = 'connect(' + words[0] + '.B,' + nodeDic[words[4]] + ');' + connInfo.append(conn) + elif eachline[0] in ['f','h','F','H']: + vsource = words[3] + sourceNodes = sourcesInfo[vsource] + #print "Source Nodes------>",sourceNodes + #print "Source Info------->",sourcesInfo + #sourceNodes = sourceNodes.split() #No need to split as it is in the form of list + conn = 'connect(' + words[0] + '.p1,'+ nodeDic[sourceNodes[0]] + ');' + connInfo.append(conn) + conn = 'connect(' + words[0] + '.n1,'+ nodeDic[sourceNodes[1]] + ');' + connInfo.append(conn) + conn = 'connect(' + words[0] + '.p2,'+ nodeDic[words[1]] + ');' + connInfo.append(conn) + conn = 'connect(' + words[0] + '.n2,'+ nodeDic[words[2]] + ');' + connInfo.append(conn) + elif eachline[0] in ['g','e','G','E']: + conn = 'connect(' + words[0] + '.p1,'+ nodeDic[words[3]] + ');' + connInfo.append(conn) + conn = 'connect(' + words[0] + '.n1,'+ nodeDic[words[4]] + ');' + connInfo.append(conn) + conn = 'connect(' + words[0] + '.p2,'+ nodeDic[words[1]] + ');' + connInfo.append(conn) + conn = 'connect(' + words[0] + '.n2,'+ nodeDic[words[2]] + ');' + connInfo.append(conn) + elif eachline[0]=='x' or eachline[0]=='X': + templine = eachline.split() + temp = templine[0].split('x') + index = temp[1] + for i in range(0,len(templine),1): + if templine[i] in subcktName: + subname = templine[i] + nodeNumInfo = self.getSubInterface(subname, numNodesSub) + for i in range(0, numNodesSub[subname], 1): + conn = 'connect(' + subname + '_instance' + index + '.' + 'n'+ nodeNumInfo[i] + ',' + nodeDic[words[i+1]] + ');' + connInfo.append(conn) + else: + continue + if '0' in node: + conn = 'connect(g.p,n0);' + connInfo.append(conn) + elif 'gnd' in node: + conn = 'connect(g.p,ngnd);' + connInfo.append(conn) + + + + + return connInfo + + + def procesSubckt(self,subcktName,numNodesSub,dir_name): + + #Process the subcircuit file .sub in the project folder + + #subcktDic = {} + subOptionInfo = [] + subSchemInfo = [] + subModel = [] + subModelInfo = {} + subsubName = [] + subParamInfo = [] + nodeSubInterface = [] + nodeSub = [] + nodeDicSub = {} + pinInitsub = [] + connSubInfo = [] + if len(subcktName) > 0: + for eachsub in subcktName: + filename = eachsub + '.sub' + basename = filename + filename = os.path.join(dir_name, filename) + data = self.readNetlist(filename) + #print "Data-------------------->",data + subOptionInfo, subSchemInfo = self.separateNetlistInfo(data) + #print "SubOptionInfo------------------->",subOptionInfo + #print "SubSchemInfo-------------------->",subSchemInfo + if len(subOptionInfo) > 0: + newline = subOptionInfo[0] + subInitLine = newline + newline = newline.split('.subckt') + intLine = newline[1].split() + for i in range(0,len(intLine),1): + nodeSubInterface.append(intLine[i]) + + subModel, subModelInfo, subsubName, subParamInfo,subtransInfo,subInbuiltModelDict = self.addModel(subOptionInfo) + #print "Sub Model------------------------------------>",subModel + #print "SubModelInfo---------------------------------->",subModelInfo + #print "subsubName------------------------------------->",subsubName + #print "subParamInfo----------------------------------->",subParamInfo + #print "subtransInfo----------------------------------->",subtransInfo + #print "subInbuiltModel----------------------------------->",subInbuiltModelDict + + IfMOSsub = '0' + for eachline in subSchemInfo: + #words = eachline.split() + if eachline[0] == 'm': + IfMOSsub = '1' + break + subsubOptionInfo = [] + subsubSchemInfo = [] + if len(subsubName) > 0: + #subsubOptionInfo = [] + #subsubSchemInfo = [] + for eachsub in subsubName: + filename_st = eachsub + '.sub' + filename_stemp = os.path.join(dir_name, filename_st) + data = self.readNetlist(filename_stemp) + subsubOptionInfo, subsubSchemInfo = self.separateNetlistInfo(data) + for eachline in subsubSchemInfo: + #words = eachline.split() + if eachline[0] == 'm': + IfMOSsub = '1' + break + #print "subsubOptionInfo-------------------------->",subsubOptionInfo + #print "subsubSchemInfo-------------------------->",subsubSchemInfo + + modelicaSubParam = self.processParam(subParamInfo) + #print "modelicaSubParam------------------->",modelicaSubParam + nodeSub, nodeDicSub, pinInitSub, pinProtectedInitSub = self.nodeSeparate(subSchemInfo, '1', eachsub, subsubName,numNodesSub) + #print "NodeSub------------------------->",nodeSub + #print "NodeDicSub-------------------------->",nodeDicSub + #print "PinInitSub-------------------------->",pinInitSub + #print "PinProtectedInitSub------------------->",pinProtectedInitSub + modelicaSubCompInit, numNodesSubsub = self.compInit(subSchemInfo, nodeSub, subModelInfo, subsubName,dir_name,subtransInfo,subInbuiltModelDict) + #print "modelicaSubCompInit--------------------->",modelicaSubCompInit + #print "numNodesSubsub-------------------------->",numNodesSubsub + modelicaSubParamNew = self.getSubParamLine(eachsub, numNodesSub, modelicaSubParam,dir_name) ###Ask Manas + #print "modelicaSubParamNew----------------->",modelicaSubParamNew + connSubInfo = self.connectInfo(subSchemInfo, nodeSub, nodeDicSub, numNodesSubsub,subcktName) + #print "connSubInfo----------------->",connSubInfo + newname = basename.split('.') + newfilename = newname[0] + outfilename = newfilename+ ".mo" + outfilename = os.path.join(dir_name, outfilename) + out = open(outfilename,"w") + out.writelines('model ' + newfilename) + out.writelines('\n') + if IfMOSsub == '0': + out.writelines('import Modelica.Electrical.*;') + elif IfMOSsub == '1': + out.writelines('import BondLib.Electrical.*;') + out.writelines('\n') + for eachline in modelicaSubParamNew: + if len(subParamInfo) == 0: + continue + else: + out.writelines(eachline) + out.writelines('\n') + for eachline in modelicaSubCompInit: + if len(subSchemInfo) == 0: + continue + else: + out.writelines(eachline) + out.writelines('\n') + + out.writelines(pinProtectedInitSub) + out.writelines('\n') + if pinInitSub != 'Modelica.Electrical.Analog.Interfaces.Pin ;': + out.writelines('protected') + out.writelines('\n') + out.writelines(pinInitSub) + out.writelines('\n') + out.writelines('equation') + out.writelines('\n') + for eachline in connSubInfo: + if len(connSubInfo) == 0: + continue + else: + out.writelines(eachline) + out.writelines('\n') + out.writelines('end '+ newfilename + ';') + out.writelines('\n') + out.close() + + return data, subOptionInfo, subSchemInfo, subModel, subModelInfo, subsubName, \ + subParamInfo, modelicaSubCompInit, modelicaSubParam, nodeSubInterface, nodeSub, nodeDicSub, pinInitSub, connSubInfo + + + +def main(args): + """ + It is main function of module Ngspice to Modelica converter + """ + if len(sys.argv) == 3: + filename = sys.argv[1] + map_json = sys.argv[2] + else: + print "USAGE:" + print "python NgspicetoModelica.py <filename>" + sys.exit() + + dir_name = os.path.dirname(os.path.realpath(filename)) + file_basename = os.path.basename(filename) + + cwd = os.getcwd() + os.chdir(dir_name) + + obj_NgMoConverter = NgMoConverter(map_json) + + #Getting all the require information + lines = obj_NgMoConverter.readNetlist(filename) + #print "Complete Lines of Ngspice netlist :lines ---------------->",lines + optionInfo, schematicInfo = obj_NgMoConverter.separateNetlistInfo(lines) + #print "All option details like analysis,subckt,.ic,.model : OptionInfo------------------->",optionInfo + #print "Schematic connection info :schematicInfo",schematicInfo + modelName, modelInfo, subcktName, paramInfo,transInfo,inbuiltModelDict = obj_NgMoConverter.addModel(optionInfo) + #print "Name of Model : modelName-------------------->",modelName + #print "Model Information :modelInfo--------------------->",modelInfo + #print "Subcircuit Name :subcktName------------------------>",subcktName + #print "Parameter Information :paramInfo---------------------->",paramInfo + #print "InBuilt Model ---------------------->",inbuiltModelDict + + + + modelicaParamInit = obj_NgMoConverter.processParam(paramInfo) + #print "Make modelicaParamInit from paramInfo : processParamInit------------->",modelicaParamInit + compInfo, plotInfo = obj_NgMoConverter.separatePlot(schematicInfo) + #print "Plot info like plot,print etc :plotInfo",plotInfo + IfMOS = '0' + + for eachline in compInfo: + words = eachline.split() + if eachline[0] == 'm': + IfMOS = '1' + break + + subOptionInfo = [] + subSchemInfo = [] + if len(subcktName) > 0: + #subOptionInfo = [] + #subSchemInfo = [] + for eachsub in subcktName: + filename_temp = eachsub + '.sub' + data = obj_NgMoConverter.readNetlist(filename_temp) + #print "Data---------->",data + subOptionInfo, subSchemInfo = obj_NgMoConverter.separateNetlistInfo(data) + for eachline in subSchemInfo: + words = eachline.split() + if eachline[0] == 'm': + IfMOS = '1' + break + #print "Subcircuit OptionInfo : subOptionInfo------------------->",subOptionInfo + #print "Subcircuit Schematic Info :subSchemInfo-------------------->",subSchemInfo + + node, nodeDic, pinInit, pinProtectedInit = obj_NgMoConverter.nodeSeparate(compInfo, '0', [], subcktName,[]) + #print "All nodes in the netlist :node---------------->",node + #print "NodeDic which will be used for modelica : nodeDic------------->",nodeDic + #print "PinInit-------------->",pinInit + #print "pinProtectedInit----------->",pinProtectedInit + + modelicaCompInit, numNodesSub = obj_NgMoConverter.compInit(compInfo,node, modelInfo, subcktName,dir_name,transInfo,inbuiltModelDict) + #print "ModelicaComponents : modelicaCompInit----------->",modelicaCompInit + #print "SubcktNumNodes : numNodesSub---------------->",numNodesSub + + connInfo = obj_NgMoConverter.connectInfo(compInfo, node, nodeDic, numNodesSub,subcktName) + + #print "ConnInfo------------------>",connInfo + + + ###After Sub Ckt Func + if len(subcktName) > 0: + data, subOptionInfo, subSchemInfo, subModel, subModelInfo, subsubName,subParamInfo, modelicaSubCompInit, modelicaSubParam,\ + nodeSubInterface,nodeSub, nodeDicSub, pinInitSub, connSubInfo = obj_NgMoConverter.procesSubckt(subcktName,numNodesSub,dir_name) #Adding 'numNodesSub' by Fahim + + #Creating Final Output file + newfile = filename.split('.') + newfilename = newfile[0] + outfile = newfilename + ".mo" + out = open(outfile,"w") + out.writelines('model ' + os.path.basename(newfilename)) + out.writelines('\n') + if IfMOS == '0': + out.writelines('import Modelica.Electrical.*;') + elif IfMOS == '1': + out.writelines('import BondLib.Electrical.*;') + #out.writelines('import Modelica.Electrical.*;') + out.writelines('\n') + + for eachline in modelicaParamInit: + if len(paramInfo) == 0: + continue + else: + out.writelines(eachline) + out.writelines('\n') + for eachline in modelicaCompInit: + if len(compInfo) == 0: + continue + else: + out.writelines(eachline) + out.writelines('\n') + + out.writelines('protected') + out.writelines('\n') + out.writelines(pinInit) + out.writelines('\n') + out.writelines('equation') + out.writelines('\n') + + for eachline in connInfo: + if len(connInfo) == 0: + continue + else: + out.writelines(eachline) + out.writelines('\n') + + out.writelines('end '+ os.path.basename(newfilename) + ';') + out.writelines('\n') + + + out.close() + + os.chdir(cwd) + + +# Call main function +if __name__ == '__main__': + main(sys.argv) |