diff --git a/AreaPlot.py b/AreaPlot.py index 8ec4c97..c1747f2 100644 --- a/AreaPlot.py +++ b/AreaPlot.py @@ -81,6 +81,9 @@ def ReadAreaFile(filename, nx, ny): #****************MAIN PROGRAM***************** +data = [0.77, 0.91, 0.005451, 0.01382, -1.284, [0.001796, 0.003346, 0.001127, 0.001273, 0.000985, 0.000571]] +dataij = [0, 0, 1, 1, 0, [4,2,5,4,5,8]] + # First, read the .cfg file run = 0 @@ -107,6 +110,7 @@ def ReadAreaFile(filename, nx, ny): yfit = [] xneg = [] yneg = [] +fullfile = open(outputfiledir+"/full_corr.txt","w") for i in range(Nx): for j in range(Ny): rsquared = float((i - NxCenter)**2 + (j - NyCenter)**2) @@ -119,18 +123,35 @@ def ReadAreaFile(filename, nx, ny): else: x.append(rsquared) y.append(yvalue) - if rsquared > 1.1 and rsquared < 10.1 and yvalue > 0: + if rsquared > 1.1 and abs(i - NxCenter) < 3 and abs(j - NyCenter) < 3 and yvalue > 0: + fullfile.write("i = %d, j = %d, C = %.6f\n"%(i-NxCenter,j-NxCenter,yvalue)) xfit.append(rsquared) yfit.append(yvalue) +xdata = [] +ydata = [] +for i,dat in enumerate(data): + if i != 5: + if dataij[i] == 0: + continue + else: + xdata.append(dataij[i]) + ydata.append(data[i]) + else: + for j,d in enumerate(dat): + xdata.append(dataij[i][j]) + ydata.append(data[i][j]) + figure() title("Covariance vs Distance: %d e-"%NumElec) xscale('log') yscale('log') xlim(0.8, 100.0) ylim(1E-5, 1E-1) -scatter(array(x), array(y)) -scatter(xneg, yneg, color = 'magenta', label = 'Negative Values') +scatter(xdata, ydata, marker = 'x', s = 50, color = 'green', label = 'Data') +scatter(array(x), array(y), color = 'blue', label = 'Sim') +#scatter(xfit, yfit, marker="x", color = 'black') +#scatter(xneg, yneg, color = 'magenta', label = 'Negative Values') from scipy import stats slope, intercept, r_value, p_value, std_err = stats.linregress(log10(xfit),log10(yfit)) @@ -142,16 +163,20 @@ def ReadAreaFile(filename, nx, ny): text(10.0, 0.002, "C01 = %.5g"%((area[NxCenter,NyCenter+1] - Area_0) / Area_0)) xlabel("$i^2 + j^2$") ylabel("$\delta$ Area / Area") +xlim(0.8,100) legend() -#savefig(outputfiledir+"/plots/Area_%d_%d.pdf"%(run, step)) -savefig("Area_%d_%d.pdf"%(run, step)) +savefig(outputfiledir+"/plots/Area_UnBiased_%d_%d.pdf"%(run, step)) +#savefig("Area_%d_%d.pdf"%(run, step)) -file = open("corr.txt","w") +file = open(outputfiledir+"/corr.txt","w") file.write("Slope = %.3f\n"%slope) file.write("C10 = %.5g\n"%((area[NxCenter+1,NyCenter] - Area_0) / Area_0)) file.write("C01 = %.5g\n"%((area[NxCenter,NyCenter+1] - Area_0) / Area_0)) +fullfile.write("Slope = %.3f\n"%slope) +fullfile.write("C10 = %.5g\n"%((area[NxCenter+1,NyCenter] - Area_0) / Area_0)) +fullfile.write("C01 = %.5g\n"%((area[NxCenter,NyCenter+1] - Area_0) / Area_0)) file.close() - +fullfile.close() figure() title("Pixel Area: %d e-"%NumElec) @@ -170,5 +195,5 @@ def ReadAreaFile(filename, nx, ny): ylim(10.0, 100.0) xlabel("X(microns)") ylabel("Y(microns)") -#savefig(outputfiledir+"/plots/PixelAreas_%d_%d.pdf"%(run, step)) -savefig("PixelAreas_%d_%d.pdf"%(run, step)) +savefig(outputfiledir+"/plots/PixelAreas_UnBiased_%d_%d.pdf"%(run, step)) +#savefig("PixelAreas_%d_%d.pdf"%(run, step)) diff --git a/AreaPlot_Corr.py b/AreaPlot_Corr.py new file mode 100644 index 0000000..17c9df8 --- /dev/null +++ b/AreaPlot_Corr.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python + +#Author: Craig Lage, NYU; +#Date: 16-Nov-15 + +#This program plots the pixel area plots from the Poisson CCD solver +import matplotlib +matplotlib.use("Agg") +from pylab import * +import sys, time, h5py + +#****************SUBROUTINES***************** + +def ReadConfigFile(filename): + # This reads the config file for the necessary settings + # and returns a dictionary with the values + file = open(filename,'r') + lines=file.readlines() + file.close() + ConfigData = {} + try: + for line in lines: + ThisLine=line.strip().split() + ThisLineLength=len(ThisLine) + if ThisLineLength < 3: + continue + if list(ThisLine[0])[0]=='#' or ThisLine[0]=='\n': + continue + try: + ParamName = ThisLine[0] + ThisLine.remove(ThisLine[0]) + for counter,item in enumerate(ThisLine): + if list(item)[0] == '#': + del ThisLine[counter:] # Strip the rest of the line as a comment + continue + if item == '=': + ThisLine.remove(item) + continue + if len(ThisLine) == 0: + continue + elif len(ThisLine) == 1: + ThisParam = ThisLine[0] + try: ConfigData[ParamName] = int(ThisParam) + except ValueError: + try: ConfigData[ParamName] = float(ThisParam) + except ValueError: + try: + ConfigData[ParamName] = ThisParam + except ValueError: + print "Error reading .cfg file" + else: + ThisParam = [] + for item in ThisLine: + try: ThisParam.append(int(item)) + except ValueError: + try: ThisParam.append(float(item)) + except ValueError: + ThisParam.append(item) + ConfigData[ParamName] = ThisParam + except: + continue + except: + print "Error reading .cfg file" + + return ConfigData + +def ReadAreaFile(filename, nx, ny): + area = zeros([nx, ny]) + file = open(filename, 'r') + lines = file.readlines() + file.close() + for line in lines: + items = line.split() + if items[0] == "Nx": + continue + i = int(items[0]) + j = int(items[1]) + area[i,j] = float(items[2]) + return area + + +#****************MAIN PROGRAM***************** + +data = [0.77, 0.91, 0.005943, 0.01227, -1.275, [0.001591, 0.002966, 0.000994, 0.000882, 0.000862, 0.000501]] +dataij = [0, 0, 1, 1, 0, [4,2,5,4,5,8]] + +# First, read the .cfg file +run = 0 + +configfile = sys.argv[1] +step = int(sys.argv[2]) +ConfigData = ReadConfigFile(configfile) +outputfilebase = ConfigData["outputfilebase"] +outputfiledir = ConfigData["outputfiledir"] +Nx = ConfigData["PixelBoundaryNx"] +Ny = ConfigData["PixelBoundaryNy"] +NxCenter = 4 +NyCenter = 4 +Area_0 = 100.0 + +filename = outputfiledir + '/' + outputfilebase +'_%d_Area'%step + +area = ReadAreaFile(filename, Nx, Ny) + +NumElec = step * 1000 + +x = [] +y = [] +xfit = [] +yfit = [] +xneg = [] +yneg = [] +fullfile = open(outputfiledir+"/full_corr.txt","w") +for i in range(Nx): + for j in range(Ny): + rsquared = float((i - NxCenter)**2 + (j - NyCenter)**2) + yvalue = (area[i,j] - Area_0) / Area_0 + if (i == NxCenter and j == NyCenter) or rsquared > 18.0: + continue + if yvalue < 0: + xneg.append(rsquared) + yneg.append(-yvalue) + else: + x.append(rsquared) + y.append(yvalue) + if rsquared > 1.1 and abs(i - NxCenter) < 3 and abs(j - NyCenter) < 3 and yvalue > 0: + fullfile.write("i = %d, j = %d, C = %.6f\n"%(i-NxCenter,j-NxCenter,yvalue)) + xfit.append(rsquared) + yfit.append(yvalue) + +xdata = [] +ydata = [] +for i,dat in enumerate(data): + if i != 5: + if dataij[i] == 0: + continue + else: + xdata.append(dataij[i]) + ydata.append(data[i]) + else: + for j,d in enumerate(dat): + xdata.append(dataij[i][j]) + ydata.append(data[i][j]) + +figure() +title("Covariance vs Distance: %d e-"%NumElec) +xscale('log') +yscale('log') +xlim(0.8, 100.0) +ylim(1E-5, 1E-1) +scatter(xdata, ydata, marker = 'x', s = 50, color = 'green', label = 'Data') +scatter(array(x), array(y), color = 'blue', label = 'Sim') +#scatter(xfit, yfit, marker="x", color = 'black') +#scatter(xneg, yneg, color = 'magenta', label = 'Negative Values') + +from scipy import stats +slope, intercept, r_value, p_value, std_err = stats.linregress(log10(xfit),log10(yfit)) +xplot=linspace(0.0, 2.0, 100) +yplot = slope * xplot + intercept +plot(10**xplot, 10**yplot, color='red', lw = 2, ls = '--') +text(10.0, 0.005, "Slope = %.3f"%slope) +text(10.0, 0.00316, "C10 = %.5g"%((area[NxCenter+1,NyCenter] - Area_0) / Area_0)) +text(10.0, 0.002, "C01 = %.5g"%((area[NxCenter,NyCenter+1] - Area_0) / Area_0)) +xlabel("$i^2 + j^2$") +ylabel("$\delta$ Area / Area") +xlim(0.8,100) +legend() +savefig(outputfiledir+"/plots/Area_UnBiased_Corr_%d_%d.pdf"%(run, step)) +#savefig("Area_%d_%d.pdf"%(run, step)) + +file = open(outputfiledir+"/corr.txt","w") +file.write("Slope = %.3f\n"%slope) +file.write("C10 = %.5g\n"%((area[NxCenter+1,NyCenter] - Area_0) / Area_0)) +file.write("C01 = %.5g\n"%((area[NxCenter,NyCenter+1] - Area_0) / Area_0)) +fullfile.write("Slope = %.3f\n"%slope) +fullfile.write("C10 = %.5g\n"%((area[NxCenter+1,NyCenter] - Area_0) / Area_0)) +fullfile.write("C01 = %.5g\n"%((area[NxCenter,NyCenter+1] - Area_0) / Area_0)) +file.close() +fullfile.close() +figure() +title("Pixel Area: %d e-"%NumElec) + +for i in range(Nx+1): + plot([10.0 + 10.0 * i, 10.0 + 10.0 * i], [10.0, 100.0], color = 'black') +for j in range(Ny+1): + plot([10.0, 100.0], [10.0 + 10.0 * j, 10.0 + 10.0 * j], color = 'black') +for i in range(Nx): + for j in range(Ny): + if i == NxCenter and j == NyCenter: + textcolor = 'red' + else: + textcolor = 'black' + text(11.0 + 10.0 * i, 14.0 + 10.0 * j, str(area[i,j]), color = textcolor, fontsize = 8, fontweight = 'bold') +xlim(10.0, 100.0) +ylim(10.0, 100.0) +xlabel("X(microns)") +ylabel("Y(microns)") +savefig(outputfiledir+"/plots/PixelAreas_UnBiased_Corr_%d_%d.pdf"%(run, step)) +#savefig("PixelAreas_%d_%d.pdf"%(run, step)) diff --git a/ChargeDistribution.py b/ChargeDistribution.py index 7299cbc..bbb5559 100644 --- a/ChargeDistribution.py +++ b/ChargeDistribution.py @@ -10,49 +10,6 @@ import sys, time, h5py #****************SUBROUTINES***************** -class Array3dHDF5(object): - def __init__(self, dir, filebase, LogEField): - phifile = dir+'/'+filebase+'_phi' - rhofile = dir+'/'+filebase+'_rho' - hdfphi = h5py.File(phifile,'r') - Dimension = hdfphi[hdfphi.items()[0][0]].attrs[u'Dimension'] - self.nx=Dimension[0] - self.ny=Dimension[1] - self.nz=Dimension[2] - - Lower_Left = hdfphi[hdfphi.items()[0][0]].attrs[u'Lower_Left'] - self.xmin=Lower_Left[0] - self.ymin=Lower_Left[1] - self.zmin=Lower_Left[2] - - Upper_Right = hdfphi[hdfphi.items()[0][0]].attrs[u'Upper_Right'] - self.xmax=Upper_Right[0] - self.ymax=Upper_Right[1] - self.zmax=Upper_Right[2] - - self.dx=(self.xmax-self.xmin)/self.nx - self.dy=(self.ymax-self.ymin)/self.ny - self.dz=(self.zmax-self.zmin)/self.nz - self.volume = self.dx * self.dy * self.dz - - self.x=linspace(self.xmin+self.dx/2,self.xmax-self.dx/2,self.nx) - self.y=linspace(self.ymin+self.dy/2,self.ymax-self.dy/2,self.ny) - self.z=linspace(self.zmin+self.dz/2,self.zmax-self.dz/2,self.nz) - - self.phi=array(hdfphi[hdfphi.items()[0][0]]) - hdfrho = h5py.File(rhofile,'r') - self.rho=array(hdfrho[hdfrho.items()[0][0]]) - if LogEField == 1: - Exfile = dir+'/'+filebase+'_Ex' - Eyfile = dir+'/'+filebase+'_Ey' - Ezfile = dir+'/'+filebase+'_Ez' - hdfEx = h5py.File(Exfile,'r') - self.Ex=array(hdfEx[hdfEx.items()[0][0]]) - hdfEy = h5py.File(Eyfile,'r') - self.Ey=array(hdfEy[hdfEy.items()[0][0]]) - hdfEz = h5py.File(Ezfile,'r') - self.Ez=array(hdfEz[hdfEz.items()[0][0]]) - class Array3dHDF5Elec(object): def __init__(self, dir, filebase, n): elecfile = dir+'/'+filebase+'_'+str(n)+'_Elec' @@ -70,16 +27,49 @@ def __init__(self, dir, filebase, n): Upper_Right = hdfelec[hdfelec.items()[0][0]].attrs[u'Upper_Right'] self.xmax=Upper_Right[0] self.ymax=Upper_Right[1] - self.zmax=Upper_Right[2] + self.zmax=100.0 self.dx=(self.xmax-self.xmin)/self.nx self.dy=(self.ymax-self.ymin)/self.ny - self.dz=(self.zmax-self.zmin)/self.nz - self.volume = self.dx * self.dy * self.dz + self.dzp=(self.zmax-self.zmin)/(ConfigData["Nx"] * ConfigData["ScaleFactor"] + 1) self.x=linspace(self.xmin+self.dx/2,self.xmax-self.dx/2,self.nx) self.y=linspace(self.ymin+self.dy/2,self.ymax-self.dy/2,self.ny) - self.z=linspace(self.zmin+self.dz/2,self.zmax-self.dz/2,self.nz) + self.zp=linspace(self.zmin+self.dzp/2,self.zmax-self.dzp/2,(ConfigData["Nx"] * ConfigData["ScaleFactor"] + 1))[0:16*ConfigData["ScaleFactor"]] + self.z=linspace(self.zmin+self.dzp/2,self.zmax-self.dzp/2,(ConfigData["Nx"] * ConfigData["ScaleFactor"] + 1))[0:16*ConfigData["ScaleFactor"]] + + def ZP(z): + n = 10.0 + return - 100.0 * (n - 1.0) * pow(z / 100.0, (n + 1.0)/n) + n * z + + def DZPDz(z): + n = 10.0 + return - (n - 1.0) * (n + 1.0) / n * pow(z / 100.0, 1.0 / n) + n + + def Z(zp): + # Inverts ZP(z) using Newton's method + i = 0 + error = 1.0 + lastroot = zp + while (error>1e-12): + newroot = lastroot - (ZP(lastroot) - zp) / DZPDz(lastroot) + error = fabs((newroot - lastroot) / lastroot) + lastroot=newroot + i=i+1 + if (i > 100): + print "Iterations exceeded in Z(zprime). Quitting." + return newroot + return newroot + + def ZIndex(z): + return max(0,min(self.nz-1,int((ZP(z) - self.zmin) / self.dzp))) + + for k in range(self.nz): + self.z[k] = Z(self.zp[k]) + + EPSILON_SI = 11.7 + EPSILON_OX = 4.3 + self.Channelkmin = ZIndex(ConfigData["GateOxide"] * EPSILON_SI / EPSILON_OX) self.elec=array(hdfelec[hdfelec.items()[0][0]]) @@ -147,11 +137,11 @@ def ReadConfigFile(filename): outputfilebase = ConfigData["outputfilebase"] outputfiledir = ConfigData["outputfiledir"] - # This holds all of the data ScaleFactor = ConfigData["ScaleFactor"] GridsPerPixel = ConfigData["GridsPerPixel"] dat = Array3dHDF5Elec(outputfiledir, outputfilebase, run) + nxx = dat.nx - 1 nyy = dat.ny - 1 nzz = dat.nz - 1 @@ -163,11 +153,33 @@ def ReadConfigFile(filename): nymin = nycenter - (NumPixelsPlotted * ScaleFactor * GridsPerPixel)/2 nymax = nymin + (NumPixelsPlotted * ScaleFactor * GridsPerPixel) levels = linspace(-3.0, 7.0, 101) +file = open(outputfiledir+"/charge.txt","w") + Total_elec = dat.elec.sum() -print "Total Electrons = ",Total_elec +file.write("Total Electrons = %.1f\n"%Total_elec) + +Below_kmin = dat.elec[:,:,0:dat.Channelkmin].sum() + +print "Total electrons = %d, Below kmin = %d"%(Total_elec, Below_kmin) + +nzxmin = nxcenter - (ScaleFactor * GridsPerPixel)/2 +nzxmax = nzxmin + (ScaleFactor * GridsPerPixel) +nzymin = nycenter - (ScaleFactor * GridsPerPixel)/2 +nzymax = nzymin + (ScaleFactor * GridsPerPixel) +ncenter = 0.0 +nzcenter = 0.0 + +for nx in range(nzxmin, nzxmax): + for ny in range(nzymin, nzymax): + for nz in range(nzz): + ncenter += dat.elec[nx,ny,nz] + nzcenter += dat.z[nz] * dat.elec[nx,ny,nz] +meanz = nzcenter / ncenter +file.write("Electrons in center Pixel = %.1f, Mean z = %.3f microns\n"%(ncenter, meanz)) +file.close() fig = figure(figsize = (12,12)) suptitle("Well Filling with Two Collecting Phases", fontsize = 36) @@ -196,8 +208,9 @@ def ReadConfigFile(filename): ax2.set_xticks([]) ax2.set_yticks([]) plotarray = sum(dat.elec[nxmin:nxmax,:,0:20],axis = 1)+0.1 -for nx in range(0,nxmax-nxmin): - plotarray[nx,0] = 0.001 +for nx in [0, 1, 2, nxmax-nxmin-3, nxmax-nxmin-2, nxmax-nxmin-1]: + #for nz in range(0,dat.Channelkmin): + plotarray[nx,dat.Channelkmin] = 0.001 ax2.imshow(log10(transpose(fliplr(plotarray))), interpolation = 'nearest') @@ -206,8 +219,11 @@ def ReadConfigFile(filename): ax3.set_xticks([]) ax3.set_yticks([]) plotarray = sum(dat.elec[:,nymin:nymax,0:20],axis = 0)+0.1 -for ny in range(0,nymax-nymin): - plotarray[ny,0] = 0.001 +for ny in [0, 1, 2, nymax-nymin-3, nymax-nymin-2, nymax-nymin-1]: + #for nz in range(0,dat.Channelkmin): + plotarray[ny,dat.Channelkmin] = 0.001 + #for nz in range(0,dat.Channelkmin): + # plotarray[ny,nz] += 0.001 ax3.imshow(log10(fliplr(plotarray)), interpolation = 'nearest') savefig(outputfiledir+"/plots/ChargeDistribution_%d.pdf"%run) diff --git a/ChargeDistribution_XYZDist.py b/ChargeDistribution_XYZDist.py new file mode 100644 index 0000000..b6fb851 --- /dev/null +++ b/ChargeDistribution_XYZDist.py @@ -0,0 +1,265 @@ +#!/usr/bin/env python + +#Author: Craig Lage, NYU; +#Date: 26-Jan-15 + +#This program plots the Poisson equation solutions from the C++ Poisson solver +import matplotlib +matplotlib.use("PDF") +from pylab import * +import sys, time, h5py + +#****************SUBROUTINES***************** +class Array3dHDF5Elec(object): + def __init__(self, dir, filebase, n): + elecfile = dir+'/'+filebase+'_'+str(n)+'_Elec' + hdfelec = h5py.File(elecfile,'r') + Dimension = hdfelec[hdfelec.items()[0][0]].attrs[u'Dimension'] + self.nx=Dimension[0] + self.ny=Dimension[1] + self.nz=Dimension[2] + + Lower_Left = hdfelec[hdfelec.items()[0][0]].attrs[u'Lower_Left'] + self.xmin=Lower_Left[0] + self.ymin=Lower_Left[1] + self.zmin=Lower_Left[2] + + Upper_Right = hdfelec[hdfelec.items()[0][0]].attrs[u'Upper_Right'] + self.xmax=Upper_Right[0] + self.ymax=Upper_Right[1] + self.zmax=100.0 + + self.dx=(self.xmax-self.xmin)/self.nx + self.dy=(self.ymax-self.ymin)/self.ny + self.dzp=(self.zmax-self.zmin)/(ConfigData["Nx"] * ConfigData["ScaleFactor"] + 1) + + self.x=linspace(self.xmin+self.dx/2,self.xmax-self.dx/2,self.nx) + self.y=linspace(self.ymin+self.dy/2,self.ymax-self.dy/2,self.ny) + self.zp=linspace(self.zmin+self.dzp/2,self.zmax-self.dzp/2,(ConfigData["Nx"] * ConfigData["ScaleFactor"] + 1))[0:16*ConfigData["ScaleFactor"]] + self.z=linspace(self.zmin+self.dzp/2,self.zmax-self.dzp/2,(ConfigData["Nx"] * ConfigData["ScaleFactor"] + 1))[0:16*ConfigData["ScaleFactor"]] + + def ZP(z): + n = 10.0 + return - 100.0 * (n - 1.0) * pow(z / 100.0, (n + 1.0)/n) + n * z + + def DZPDz(z): + n = 10.0 + return - (n - 1.0) * (n + 1.0) / n * pow(z / 100.0, 1.0 / n) + n + + def Z(zp): + # Inverts ZP(z) using Newton's method + i = 0 + error = 1.0 + lastroot = zp + while (error>1e-12): + newroot = lastroot - (ZP(lastroot) - zp) / DZPDz(lastroot) + error = fabs((newroot - lastroot) / lastroot) + lastroot=newroot + i=i+1 + if (i > 100): + print "Iterations exceeded in Z(zprime). Quitting." + return newroot + return newroot + + def ZIndex(z): + return max(0,min(self.nz-1,int((ZP(z) - self.zmin) / self.dzp))) + + for k in range(self.nz): + self.z[k] = Z(self.zp[k]) + + EPSILON_SI = 11.7 + EPSILON_OX = 4.3 + self.Channelkmin = ZIndex(ConfigData["GateOxide"] * EPSILON_SI / EPSILON_OX) + + self.elec=array(hdfelec[hdfelec.items()[0][0]]) + +def ReadConfigFile(filename): + # This reads the config file for the necessary settings + # and returns a dictionary with the values + file = open(filename,'r') + lines=file.readlines() + file.close() + ConfigData = {} + try: + for line in lines: + ThisLine=line.strip().split() + ThisLineLength=len(ThisLine) + if ThisLineLength < 3: + continue + if list(ThisLine[0])[0]=='#' or ThisLine[0]=='\n': + continue + try: + ParamName = ThisLine[0] + ThisLine.remove(ThisLine[0]) + for counter,item in enumerate(ThisLine): + if list(item)[0] == '#': + del ThisLine[counter:] # Strip the rest of the line as a comment + continue + if item == '=': + ThisLine.remove(item) + continue + if len(ThisLine) == 0: + continue + elif len(ThisLine) == 1: + ThisParam = ThisLine[0] + try: ConfigData[ParamName] = int(ThisParam) + except ValueError: + try: ConfigData[ParamName] = float(ThisParam) + except ValueError: + try: + ConfigData[ParamName] = ThisParam + except ValueError: + print "Error reading .cfg file" + else: + ThisParam = [] + for item in ThisLine: + try: ThisParam.append(int(item)) + except ValueError: + try: ThisParam.append(float(item)) + except ValueError: + ThisParam.append(item) + ConfigData[ParamName] = ThisParam + except: + continue + except: + print "Error reading .cfg file" + + return ConfigData + +#****************MAIN PROGRAM***************** + +# First, read the .cfg file + +configfile = sys.argv[1] +run = int(sys.argv[2]) + +ConfigData = ReadConfigFile(configfile) +outputfilebase = ConfigData["outputfilebase"] +outputfiledir = ConfigData["outputfiledir"] + +# This holds all of the data +ScaleFactor = ConfigData["ScaleFactor"] +GridsPerPixel = ConfigData["GridsPerPixel"] +dat = Array3dHDF5Elec(outputfiledir, outputfilebase, run) + +nxx = dat.nx - 1 +nyy = dat.ny - 1 +nzz = dat.nz - 1 +NumPixelsPlotted = 3 +nxcenter = nxx/2 +nycenter = nyy/2 +nxmin = nxcenter - (NumPixelsPlotted * ScaleFactor * GridsPerPixel)/2 +nxmax = nxmin + (NumPixelsPlotted * ScaleFactor * GridsPerPixel) +nymin = nycenter - (NumPixelsPlotted * ScaleFactor * GridsPerPixel)/2 +nymax = nymin + (NumPixelsPlotted * ScaleFactor * GridsPerPixel) +levels = linspace(-3.0, 7.0, 101) +file = open(outputfiledir+"/charge.txt","w") + + +Total_elec = dat.elec.sum() + +file.write("Total Electrons = %.1f\n"%Total_elec) + +Below_kmin = dat.elec[:,:,0:dat.Channelkmin].sum() + +print "Total electrons = %d, Below kmin = %d"%(Total_elec, Below_kmin) + +nzxmin = nxcenter - (ScaleFactor * GridsPerPixel)/2 +nzxmax = nzxmin + (ScaleFactor * GridsPerPixel) +nzymin = nycenter - (ScaleFactor * GridsPerPixel)/2 +nzymax = nzymin + (ScaleFactor * GridsPerPixel) +ncenter = 0.0 +nzcenter = 0.0 + +for nx in range(nzxmin, nzxmax): + for ny in range(nzymin, nzymax): + for nz in range(nzz): + ncenter += dat.elec[nx,ny,nz] + nzcenter += dat.z[nz] * dat.elec[nx,ny,nz] + +meanz = nzcenter / ncenter +file.write("Electrons in center Pixel = %.1f, Mean z = %.3f microns\n"%(ncenter, meanz)) +file.close() +fig = figure(figsize = (12,12)) +suptitle("Well Filling with Two Collecting Phases", fontsize = 36) + +ax1=axes([0.10,0.40,0.50,0.50],aspect=1) +ax1.set_title("X-Y Slice") +ax1.set_xticks([]) +ax1.set_yticks([]) +plotarray = sum(dat.elec[nxmin:nxmax,nymin:nymax,:],axis = 2)+0.1 +for nx in range(ScaleFactor*GridsPerPixel,nxmax-nxmin,ScaleFactor*GridsPerPixel): + for ny in range(0,nymax-nymin): + plotarray[nx,ny] = 0.001 +for ny in range(ScaleFactor*GridsPerPixel,nymax-nymin,ScaleFactor*GridsPerPixel): + for nx in range(0,nxmax-nxmin): + plotarray[nx,ny] = 0.001 +for nx in range(ScaleFactor*GridsPerPixel-1,nxmax-nxmin,ScaleFactor*GridsPerPixel): + for ny in range(0,nymax-nymin): + plotarray[nx,ny] = 0.001 +for ny in range(ScaleFactor*GridsPerPixel-1,nymax-nymin,ScaleFactor*GridsPerPixel): + for nx in range(0,nxmax-nxmin): + plotarray[nx,ny] = 0.001 + +ax1.imshow(log10(transpose(plotarray)), interpolation = 'nearest') + +ax2=axes([0.10,0.20,0.50,0.20]) +ax2.set_title("X-Z Slice") +ax2.set_xticks([]) +ax2.set_yticks([]) +plotarray = sum(dat.elec[nxmin:nxmax,:,0:20],axis = 1)+0.1 +for nx in [0, 1, 2, nxmax-nxmin-3, nxmax-nxmin-2, nxmax-nxmin-1]: + #for nz in range(0,dat.Channelkmin): + plotarray[nx,dat.Channelkmin] = 0.001 + +ax2.imshow(log10(transpose(fliplr(plotarray))), interpolation = 'nearest') + +ax3=axes([0.10,0.10,0.50,0.10]) +ax3.set_title("X-Z Slice") +plotarray = sum(dat.elec[nxmin:nxmax,nycenter,0:20],axis = 1) +ax3.plot(dat.x[nxmin:nxmax],plotarray) +ax3.set_xlabel("X ( Microns)") +ax3.set_ylabel("Charge Density") + + +ax4=axes([0.60,0.40,0.20,0.50]) +ax4.set_title("Y-Z Slice") +ax4.set_xticks([]) +ax4.set_yticks([]) +plotarray = sum(dat.elec[:,nymin:nymax,0:20],axis = 0)+0.1 +for ny in [0, 1, 2, nymax-nymin-3, nymax-nymin-2, nymax-nymin-1]: + #for nz in range(0,dat.Channelkmin): + plotarray[ny,dat.Channelkmin] = 0.001 + #for nz in range(0,dat.Channelkmin): + # plotarray[ny,nz] += 0.001 + +ax4.imshow(log10(fliplr(plotarray)), interpolation = 'nearest') + +ax5=axes([0.80,0.40,0.10,0.50]) +ax5.set_title("Y-Z Slice") +plotarray = sum(dat.elec[nxcenter,nymin:nymax,0:20],axis = 1) +ax5.plot(plotarray,dat.y[nymin:nymax]) +ax5.set_xlim(ax5.get_xlim()[::-1]) +ax5.yaxis.tick_right() +ax5.yaxis.set_label_position("right") +for tick in ax5.get_xticklabels(): + tick.set_rotation(90) +ax5.set_ylabel("Y ( Microns)") +ax5.set_xlabel("Charge Density") + +ax6=axes([0.65,0.25,0.10,0.10]) +ax6.set_title("X-Z Slice") +plotarray = dat.elec[nxcenter,nycenter,:] +ax6.plot(dat.z[:],plotarray) +ax6.set_xlim(ax6.get_xlim()[::-1]) +ax6.set_xticks([0.0,0.5,1.0,1.5,2.0]) +ax6.set_xlabel("Z ( Microns)") +ax6.set_ylabel("Charge Density") +savefig(outputfiledir+"/plots/ChargeDistribution_XYZ_%d.pdf"%run) +close(fig) + + + + + + diff --git a/ChargeDistribution_XYZDist_N.py b/ChargeDistribution_XYZDist_N.py new file mode 100644 index 0000000..312dc86 --- /dev/null +++ b/ChargeDistribution_XYZDist_N.py @@ -0,0 +1,284 @@ +#!/usr/bin/env python + +#Author: Craig Lage, NYU; +#Date: 26-Jan-15 + +#This program plots the Poisson equation solutions from the C++ Poisson solver +import matplotlib +matplotlib.use("PDF") +from pylab import * +import sys, time, h5py + +#****************SUBROUTINES***************** +class Array3dHDF5Elec(object): + def __init__(self, dir, filebase, n): + elecfile = dir+'/'+filebase+'_'+str(n)+'_Elec' + hdfelec = h5py.File(elecfile,'r') + holefile = dir+'/'+filebase+'_'+str(n)+'_Hole' + hdfhole = h5py.File(holefile,'r') + Dimension = hdfelec[hdfelec.items()[0][0]].attrs[u'Dimension'] + self.nx=Dimension[0] + self.ny=Dimension[1] + self.nz=Dimension[2] + + Lower_Left = hdfelec[hdfelec.items()[0][0]].attrs[u'Lower_Left'] + self.xmin=Lower_Left[0] + self.ymin=Lower_Left[1] + self.zmin=Lower_Left[2] + + Upper_Right = hdfelec[hdfelec.items()[0][0]].attrs[u'Upper_Right'] + self.xmax=Upper_Right[0] + self.ymax=Upper_Right[1] + self.zmax=100.0 + + self.dx=(self.xmax-self.xmin)/self.nx + self.dy=(self.ymax-self.ymin)/self.ny + self.dzp=(self.zmax-self.zmin)/(ConfigData["Nx"] * ConfigData["ScaleFactor"] + 1) + + self.x=linspace(self.xmin+self.dx/2,self.xmax-self.dx/2,self.nx) + self.y=linspace(self.ymin+self.dy/2,self.ymax-self.dy/2,self.ny) + self.zp=linspace(self.zmin+self.dzp/2,self.zmax-self.dzp/2,(ConfigData["Nx"] * ConfigData["ScaleFactor"] + 1))[0:32*ConfigData["ScaleFactor"]] + self.z=linspace(self.zmin+self.dzp/2,self.zmax-self.dzp/2,(ConfigData["Nx"] * ConfigData["ScaleFactor"] + 1))[0:32*ConfigData["ScaleFactor"]] + + def ZP(z): + n = 10.0 + return - 100.0 * (n - 1.0) * pow(z / 100.0, (n + 1.0)/n) + n * z + + def DZPDz(z): + n = 10.0 + return - (n - 1.0) * (n + 1.0) / n * pow(z / 100.0, 1.0 / n) + n + + def Z(zp): + # Inverts ZP(z) using Newton's method + i = 0 + error = 1.0 + lastroot = zp + while (error>1e-12): + newroot = lastroot - (ZP(lastroot) - zp) / DZPDz(lastroot) + error = fabs((newroot - lastroot) / lastroot) + lastroot=newroot + i=i+1 + if (i > 100): + print "Iterations exceeded in Z(zprime). Quitting." + return newroot + return newroot + + def ZIndex(z): + return max(0,min(self.nz-1,int((ZP(z) - self.zmin) / self.dzp))) + + for k in range(self.nz): + self.z[k] = Z(self.zp[k]) + + EPSILON_SI = 11.7 + EPSILON_OX = 4.3 + self.Channelkmin = ZIndex(ConfigData["GateOxide"] * EPSILON_SI / EPSILON_OX) + + self.elec=array(hdfelec[hdfelec.items()[0][0]]) + self.hole=array(hdfhole[hdfhole.items()[0][0]]) + +def ReadConfigFile(filename): + # This reads the config file for the necessary settings + # and returns a dictionary with the values + file = open(filename,'r') + lines=file.readlines() + file.close() + ConfigData = {} + try: + for line in lines: + ThisLine=line.strip().split() + ThisLineLength=len(ThisLine) + if ThisLineLength < 3: + continue + if list(ThisLine[0])[0]=='#' or ThisLine[0]=='\n': + continue + try: + ParamName = ThisLine[0] + ThisLine.remove(ThisLine[0]) + for counter,item in enumerate(ThisLine): + if list(item)[0] == '#': + del ThisLine[counter:] # Strip the rest of the line as a comment + continue + if item == '=': + ThisLine.remove(item) + continue + if len(ThisLine) == 0: + continue + elif len(ThisLine) == 1: + ThisParam = ThisLine[0] + try: ConfigData[ParamName] = int(ThisParam) + except ValueError: + try: ConfigData[ParamName] = float(ThisParam) + except ValueError: + try: + ConfigData[ParamName] = ThisParam + except ValueError: + print "Error reading .cfg file" + else: + ThisParam = [] + for item in ThisLine: + try: ThisParam.append(int(item)) + except ValueError: + try: ThisParam.append(float(item)) + except ValueError: + ThisParam.append(item) + ConfigData[ParamName] = ThisParam + except: + continue + except: + print "Error reading .cfg file" + + return ConfigData + +#****************MAIN PROGRAM***************** + +# First, read the .cfg file + +configfile = sys.argv[1] +run = int(sys.argv[2]) + +ConfigData = ReadConfigFile(configfile) +outputfilebase = ConfigData["outputfilebase"] +outputfiledir = ConfigData["outputfiledir"] + +# This holds all of the data +ScaleFactor = ConfigData["ScaleFactor"] +GridsPerPixel = ConfigData["GridsPerPixel"] +dat = Array3dHDF5Elec(outputfiledir, outputfilebase, run) + +nxx = dat.nx - 1 +nyy = dat.ny - 1 +nzz = dat.nz - 1 +NumPixelsPlotted = int(sys.argv[3]) +nxcenter = nxx/2 +nycenter = nyy/2 +nxmin = nxcenter - (NumPixelsPlotted * ScaleFactor * GridsPerPixel)/2 +nxmax = nxmin + (NumPixelsPlotted * ScaleFactor * GridsPerPixel) +nymin = nycenter - (NumPixelsPlotted * ScaleFactor * GridsPerPixel)/2 +nymax = nymin + (NumPixelsPlotted * ScaleFactor * GridsPerPixel) +levels = linspace(-3.0, 7.0, 101) +file = open(outputfiledir+"/charge.txt","w") + +nzxmin = nxcenter - (ScaleFactor * GridsPerPixel)/2 +nzxmax = nzxmin + (ScaleFactor * GridsPerPixel) +nzymin = nycenter - (ScaleFactor * GridsPerPixel)/2 +nzymax = nzymin + (ScaleFactor * GridsPerPixel) +ncenter = 0.0 +nzcenter = 0.0 + +Total_elec = 0.0 +Below_kmin = 0.0 +for nx in range(nzxmin, nzxmax): + for ny in range(nzymin, nzymax): + for nz in range(nzz): + if dat.elec[nx,ny,nz] > 0.0: + ncenter += dat.elec[nx,ny,nz] + nzcenter += dat.z[nz] * dat.elec[nx,ny,nz] +meanz = nzcenter / ncenter +print "Electrons in center Pixel = %.1f, Mean z = %.3f microns\n"%(ncenter, meanz) + +file.write("Electrons in center Pixel = %.1f, Mean z = %.3f microns\n"%(ncenter, meanz)) +file.close() + +carriers = ['Electron', 'Hole'] +plotdatas = [dat.elec, dat.hole] + +for i, plotdata in enumerate(plotdatas): + + if i == 1: + nxcenter += ScaleFactor * GridsPerPixel / 2 + nycenter += ScaleFactor * GridsPerPixel / 2 + + fig = figure(figsize = (12,12)) + suptitle("%s Charge Distribution"%carriers[i], fontsize = 36) + + ax1=axes([0.10,0.40,0.50,0.50],aspect=1) + ax1.set_title("X-Y Slice") + ax1.set_xticks([]) + ax1.set_yticks([]) + plotarray = sum(plotdata[nxmin:nxmax,nymin:nymax,:],axis = 2)+0.1 + if i == 0: + for nx in range(ScaleFactor*GridsPerPixel,nxmax-nxmin,ScaleFactor*GridsPerPixel): + for ny in range(0,nymax-nymin): + plotarray[nx,ny] = 0.001 + for ny in range(ScaleFactor*GridsPerPixel,nymax-nymin,ScaleFactor*GridsPerPixel): + for nx in range(0,nxmax-nxmin): + plotarray[nx,ny] = 0.001 + for nx in range(ScaleFactor*GridsPerPixel-1,nxmax-nxmin,ScaleFactor*GridsPerPixel): + for ny in range(0,nymax-nymin): + plotarray[nx,ny] = 0.001 + for ny in range(ScaleFactor*GridsPerPixel-1,nymax-nymin,ScaleFactor*GridsPerPixel): + for nx in range(0,nxmax-nxmin): + plotarray[nx,ny] = 0.001 + + ax1.imshow(log10(transpose(plotarray)), interpolation = 'nearest') + + ax2=axes([0.10,0.20,0.50,0.20]) + ax2.set_title("X-Z Slice") + ax2.set_xticks([]) + ax2.set_yticks([]) + plotarray = sum(plotdata[nxmin:nxmax,:,:],axis = 1)+0.1 + + for nx in [0, 1, 2, nxmax-nxmin-3, nxmax-nxmin-2, nxmax-nxmin-1]: + #for nz in range(0,dat.Channelkmin): + plotarray[nx,dat.Channelkmin] = 0.001 + + ax2.imshow(log10(transpose(fliplr(plotarray))), interpolation = 'nearest') + + ax3=axes([0.10,0.10,0.50,0.10]) + ax3.set_title("X-Cut, Y = %.2f"%dat.y[nycenter]) + plotarray = sum(plotdata[nxmin:nxmax,nycenter,:],axis = 1) + ax3.plot(dat.x[nxmin:nxmax],plotarray) + ax3.set_xlabel("X ( Microns)") + ax3.set_ylabel("Charge Density") + + + ax4=axes([0.60,0.40,0.20,0.50]) + ax4.set_title("Y-Z Slice") + ax4.set_xticks([]) + ax4.set_yticks([]) + plotarray = sum(plotdata[:,nymin:nymax,:],axis = 0)+0.1 + + for ny in [0, 1, 2, nymax-nymin-3, nymax-nymin-2, nymax-nymin-1]: + #for nz in range(0,dat.Channelkmin): + plotarray[ny,dat.Channelkmin] = 0.001 + #for nz in range(0,dat.Channelkmin): + # plotarray[ny,nz] += 0.001 + + ax4.imshow(log10(fliplr(plotarray)), interpolation = 'nearest') + + ax5=axes([0.80,0.40,0.10,0.50]) + ax5.set_title("Y-Cut, X = %.2f"%dat.x[nxcenter]) + plotarray = sum(plotdata[nxcenter,nymin:nymax,0:20],axis = 1) + ax5.plot(plotarray,dat.y[nymin:nymax]) + ax5.set_xlim(ax5.get_xlim()[::-1]) + ax5.yaxis.tick_right() + ax5.yaxis.set_label_position("right") + for tick in ax5.get_xticklabels(): + tick.set_rotation(90) + ax5.set_ylabel("Y ( Microns)") + ax5.set_xlabel("Charge Density") + + ax6=axes([0.65,0.25,0.10,0.10]) + ax6.set_title("Z-Cut") + if i == 0: + plotarray = log10(plotdata[nxcenter,nycenter,:]+0.01) + ax6.plot(dat.z[:],plotarray, label = '(X,Y) = (%.2f,%.2f)'%(dat.x[nxcenter],dat.y[nycenter])) + if i == 1: + plotarray = log10(plotdata[nxcenter,nycenter,:]+0.01) + ax6.plot(dat.z[:],plotarray, label = '(X,Y) = (%.2f,%.2f)'%(dat.x[nxcenter],dat.y[nycenter])) + nycenter -= ScaleFactor * GridsPerPixel / 2 + plotarray = log10(plotdata[nxcenter,nycenter,:]+0.01) + ax6.plot(dat.z[:],plotarray, label = '(X,Y) = (%.2f,%.2f)'%(dat.x[nxcenter],dat.y[nycenter])) + legend(bbox_to_anchor=(1.05, 0.5), loc=2, fontsize = 9) + ax6.set_ylabel("Log Charge Density") + ax6.set_xlim(ax6.get_xlim()[::-1]) + ax6.set_xticks([0.0,1.0,2.0]) + ax6.set_xlabel("Z ( Microns)") + savefig(outputfiledir+"/plots/%sDistribution_XYZ_%d.pdf"%(carriers[i],run)) + close(fig) + + + + + + diff --git a/Poisson_Plots.py b/Poisson_Plots.py index b071a18..5e92fc1 100644 --- a/Poisson_Plots.py +++ b/Poisson_Plots.py @@ -37,7 +37,35 @@ def __init__(self, dir, filebase, LogEField, run): self.x=linspace(self.xmin+self.dx/2,self.xmax-self.dx/2,self.nx) self.y=linspace(self.ymin+self.dy/2,self.ymax-self.dy/2,self.ny) - self.z=linspace(self.zmin+self.dz/2,self.zmax-self.dz/2,self.nz) + self.zp=linspace(self.zmin+self.dz/2,self.zmax-self.dz/2,self.nz) + self.z=linspace(self.zmin+self.dz/2,self.zmax-self.dz/2,self.nz) + + + def ZP(z): + n = 10.0 + return - 100.0 * (n - 1.0) * pow(z / 100.0, (n + 1.0)/n) + n * z + + def DZPDz(z): + n = 10.0 + return - (n - 1.0) * (n + 1.0) / n * pow(z / 100.0, 1.0 / n) + n + + def Z(zp): + # Inverts ZP(z) using Newton's method + i = 0 + error = 1.0 + lastroot = zp + while (error>1e-12): + newroot = lastroot - (ZP(lastroot) - zp) / DZPDz(lastroot) + error = fabs((newroot - lastroot) / lastroot) + lastroot=newroot + i=i+1 + if (i > 100): + print "Iterations exceeded in Z(zprime). Quitting." + return newroot + return newroot + + for k in range(self.nz): + self.z[k] = Z(self.zp[k]) self.phi=array(hdfphi[hdfphi.items()[0][0]]) hdfrho = h5py.File(rhofile,'r') @@ -149,7 +177,7 @@ def ReadConfigFile(filename): nxmax = nxcenter + (NumPixelsPlotted * ScaleFactor * GridsPerPixel)/2 nzmin = 0 -nzmax = 8 * ScaleFactor +nzmax = 16 * ScaleFactor rcParams['contour.negative_linestyle'] = 'solid' rcParams.update({'font.size': 6}) @@ -199,16 +227,17 @@ def ReadConfigFile(filename): suptitle("1D Potential and Charge Density Slices. Grid = %d*%d*%d."%(nxx,nyy,nzz),fontsize = 18) plotcounter = 1 subplots_adjust(hspace=0.3, wspace=0.3) -numzs = 20 -deltaz = dat.dz / 2.0 - 0.01 +phinumzs = 100 +numzs = 100 + subplot(2,3,1) title("Phi-Collect Gate") -plot(dat.z[0:20],(dat.phi[nxcenter2,nycenter2,0:20]+dat.phi[nxcenter2-1,nycenter2,0:20]+dat.phi[nxcenter2,nycenter2-1,0:20]+dat.phi[nxcenter2-1,nycenter2-1,0:20])/4.0, label = "x = %.2f, y = %.2f"%((dat.x[nxcenter2]+dat.x[nxcenter2-1])/2.0,(dat.y[nycenter2]+dat.y[nycenter2-1])/2.0)) +plot(dat.z[0:phinumzs],(dat.phi[nxcenter2,nycenter2,0:phinumzs]+dat.phi[nxcenter2-1,nycenter2,0:phinumzs]+dat.phi[nxcenter2,nycenter2-1,0:phinumzs]+dat.phi[nxcenter2-1,nycenter2-1,0:phinumzs])/4.0, label = "x = %.2f, y = %.2f"%((dat.x[nxcenter2]+dat.x[nxcenter2-1])/2.0,(dat.y[nycenter2]+dat.y[nycenter2-1])/2.0)) nxcenter3 = nxcenter2 + 4 * GridsPerPixel*ScaleFactor -plot(dat.z[0:20],(dat.phi[nxcenter3,nycenter2,0:20]+dat.phi[nxcenter3-1,nycenter2,0:20]+dat.phi[nxcenter3,nycenter2-1,0:20]+dat.phi[nxcenter3-1,nycenter2-1,0:20])/4.0, label = "x = %.2f, y = %.2f"%((dat.x[nxcenter3]+dat.x[nxcenter3-1])/2.0,(dat.y[nycenter2]+dat.y[nycenter2-1])/2.0)) +plot(dat.z[0:phinumzs],(dat.phi[nxcenter3,nycenter2,0:phinumzs]+dat.phi[nxcenter3-1,nycenter2,0:phinumzs]+dat.phi[nxcenter3,nycenter2-1,0:phinumzs]+dat.phi[nxcenter3-1,nycenter2-1,0:phinumzs])/4.0, label = "x = %.2f, y = %.2f"%((dat.x[nxcenter3]+dat.x[nxcenter3-1])/2.0,(dat.y[nycenter2]+dat.y[nycenter2-1])/2.0)) legend(loc = "lower left") xlabel("Z-Dimension (microns)") ylim(-10.0, 15.0) @@ -218,18 +247,18 @@ def ReadConfigFile(filename): title("Rho-Collect Gate") zs = [] rhos = [] -for i in range(numzs): +for i in range(1,numzs): for m in [-1,0,1]: - zs.append(dat.z[i] + m * deltaz) + zs.append(dat.z[i] - 0.4 * (dat.z[i] - dat.z[i+m])) rhos.append((dat.rho[nxcenter2,nycenter2,i]+dat.rho[nxcenter2-1,nycenter2,i]+dat.rho[nxcenter2,nycenter2-1,i]+dat.rho[nxcenter2-1,nycenter2-1,i])/4.0) plot(zs, rhos, label = "x = %.2f, y = %.2f"%((dat.x[nxcenter2]+dat.x[nxcenter2-1])/2.0,(dat.y[nycenter2]+dat.y[nycenter2-1])/2.0)) zs = [] rhos = [] -for i in range(numzs): +for i in range(1,numzs): for m in [-1,0,1]: - zs.append(dat.z[i] + m * deltaz) + zs.append(dat.z[i] - 0.4 * (dat.z[i] - dat.z[i+m])) rhos.append((dat.rho[nxcenter3,nycenter2,i]+dat.rho[nxcenter3-1,nycenter2,i]+dat.rho[nxcenter3,nycenter2-1,i]+dat.rho[nxcenter3-1,nycenter2-1,i])/4.0) plot(zs, rhos, label = "x = %.2f, y = %.2f"%((dat.x[nxcenter3]+dat.x[nxcenter3-1])/2.0,(dat.y[nycenter2]+dat.y[nycenter2-1])/2.0)) @@ -239,30 +268,56 @@ def ReadConfigFile(filename): xlim(0.0,4.0) nxcenter3 = nxcenter2 + 3 * GridsPerPixel * ScaleFactor / 2 nycenter3 = nycenter2 +nycenter4 = nycenter2 + GridsPerPixel * ScaleFactor / 2 subplot(2,3,2) -title("Phi-ChanStop, x = %.2f, y = %.2f"%(((dat.x[nxcenter3]+dat.x[nxcenter3-1])/2.0),((dat.y[nycenter3]+dat.y[nycenter3-1])/2.0))) -plot(dat.z[0:20],(dat.phi[nxcenter3,nycenter3,0:20]+dat.phi[nxcenter3-1,nycenter3,0:20]+dat.phi[nxcenter3,nycenter3-1,0:20]+dat.phi[nxcenter3-1,nycenter3-1,0:20])/4.0) +title("Phi-ChanStop") +plot(dat.z[0:phinumzs],(dat.phi[nxcenter3,nycenter3,0:phinumzs]+dat.phi[nxcenter3-1,nycenter3,0:phinumzs]+dat.phi[nxcenter3,nycenter3-1,0:phinumzs]+dat.phi[nxcenter3-1,nycenter3-1,0:phinumzs])/4.0, label = "x = %.2f, y = %.2f"%((dat.x[nxcenter3]+dat.x[nxcenter3-1])/2.0,(dat.y[nycenter3]+dat.y[nycenter3-1])/2.0)) +plot(dat.z[0:phinumzs],(dat.phi[nxcenter3,nycenter4,0:phinumzs]+dat.phi[nxcenter3-1,nycenter4,0:phinumzs]+dat.phi[nxcenter3,nycenter4-1,0:phinumzs]+dat.phi[nxcenter3-1,nycenter4-1,0:phinumzs])/4.0, label = "x = %.2f, y = %.2f"%((dat.x[nxcenter3]+dat.x[nxcenter3-1])/2.0,(dat.y[nycenter4]+dat.y[nycenter4-1])/2.0)) +legend(loc = "lower left") xlabel("Z-Dimension (microns)") ylim(-20.0, 15.0) -xlim(0.0,4.0) +xlim(0.0,10.0) subplot(2,3,5) -title("Rho-ChanStop, x = %.2f, y = %.2f"%(((dat.x[nxcenter3]+dat.x[nxcenter3-1])/2.0),((dat.y[nycenter3]+dat.y[nycenter3-1])/2.0))) +title("Rho-ChanStop") zs = [] rhos = [] -for i in range(numzs): +for i in range(1,numzs): for m in [-1,0,1]: - zs.append(dat.z[i] + m * deltaz) + zs.append(dat.z[i] - 0.4 * (dat.z[i] - dat.z[i+m])) rhos.append((dat.rho[nxcenter3,nycenter3,i]+dat.rho[nxcenter3-1,nycenter3,i]+dat.rho[nxcenter3,nycenter3-1,i]+dat.rho[nxcenter3-1,nycenter3-1,i])/4.0) +plot(zs, rhos, label = "x = %.2f, y = %.2f"%((dat.x[nxcenter3]+dat.x[nxcenter3-1])/2.0,(dat.y[nycenter3]+dat.y[nycenter3-1])/2.0)) -plot(zs, rhos) +#print "1" +#print dat.rho[nxcenter3, nycenter3,0:phinumzs] +#print dat.phi[nxcenter3, nycenter3,0:phinumzs] +#print dat.rho[nxcenter3-GridsPerPixel:nxcenter3+GridsPerPixel,nycenter3,5] +#print dat.rho[nxcenter3-GridsPerPixel:nxcenter3+GridsPerPixel,nycenter3,2] +#print dat.phi[nxcenter3-GridsPerPixel:nxcenter3+GridsPerPixel,nycenter3,5] + +zs = [] +rhos = [] +for i in range(1,numzs): + for m in [-1,0,1]: + zs.append(dat.z[i] - 0.4 * (dat.z[i] - dat.z[i+m])) + rhos.append((dat.rho[nxcenter3,nycenter4,i]+dat.rho[nxcenter3-1,nycenter4,i]+dat.rho[nxcenter3,nycenter4-1,i]+dat.rho[nxcenter3-1,nycenter4-1,i])/4.0) + +plot(zs, rhos, label = "x = %.2f, y = %.2f"%((dat.x[nxcenter3]+dat.x[nxcenter3-1])/2.0,(dat.y[nycenter4]+dat.y[nycenter4-1])/2.0)) + +#print "2" +#print dat.rho[nxcenter3, nycenter4,0:phinumzs] +#print dat.phi[nxcenter3, nycenter3,0:phinumzs] + + +legend(loc = "lower left") xlabel("Z-Dimension (microns)") -ylim(-40.0, 40.0) -xlim(0.0,4.0) +ylim(-200.0, 200.0) +xlim(0.0,10.0) + nxcenter3 = nxcenter2 nycenter3 = nycenter2 + GridsPerPixel * ScaleFactor / 2 subplot(2,3,3) title("Phi-Barrier Gate, x = %.2f, y = %.2f"%(((dat.x[nxcenter3]+dat.x[nxcenter3-1])/2.0),((dat.y[nycenter3]+dat.y[nycenter3-1])/2.0))) -plot(dat.z[0:20],(dat.phi[nxcenter3,nycenter3,0:20]+dat.phi[nxcenter3-1,nycenter3,0:20]+dat.phi[nxcenter3,nycenter3-1,0:20]+dat.phi[nxcenter3-1,nycenter3-1,0:20])/4.0) +plot(dat.z[0:phinumzs],(dat.phi[nxcenter3,nycenter3,0:phinumzs]+dat.phi[nxcenter3-1,nycenter3,0:phinumzs]+dat.phi[nxcenter3,nycenter3-1,0:phinumzs]+dat.phi[nxcenter3-1,nycenter3-1,0:phinumzs])/4.0) xlabel("Z-Dimension (microns)") ylim(-20.0, 15.0) xlim(0.0,4.0) @@ -270,9 +325,9 @@ def ReadConfigFile(filename): title("Rho-Barrier Gate, x = %.2f, y = %.2f"%(((dat.x[nxcenter3]+dat.x[nxcenter3-1])/2.0),((dat.y[nycenter3]+dat.y[nycenter3-1])/2.0))) zs = [] rhos = [] -for i in range(numzs): +for i in range(1,numzs): for m in [-1,0,1]: - zs.append(dat.z[i] + m * deltaz) + zs.append(dat.z[i] - 0.4 * (dat.z[i] - dat.z[i+m])) rhos.append((dat.rho[nxcenter3,nycenter3,i]+dat.rho[nxcenter3-1,nycenter3,i]+dat.rho[nxcenter3,nycenter3-1,i]+dat.rho[nxcenter3-1,nycenter3-1,i])/4.0) plot(zs, rhos) @@ -281,6 +336,66 @@ def ReadConfigFile(filename): xlim(0.0,4.0) savefig(outputfiledir+"/plots/"+outputfilebase+"_1D_Potentials.pdf") +print "Making 1D potential Plots #2 \n" +figure() + +suptitle("1D Potentials in Storage Region. Grid = %d*%d*%d."%(nxx,nyy,nzz),fontsize = 18) +subplots_adjust(hspace=0.3, wspace=0.3) +slicez = 16 * ScaleFactor +subplot(1,2,1, aspect = 1) +title("Phi, z = %.2f"%dat.z[slicez]) +levels = linspace(-20.0, 20.0, 21) +[yy,xx] = meshgrid(dat.y[nymin:nymax],dat.x[nxmin:nxmax]) +contour(xx,yy,dat.phi[nxmin:nxmax,nymin:nymax,slicez],levels,lw=0.1) +contourf(xx,yy,dat.phi[nxmin:nxmax,nymin:nymax,slicez],levels) +xlabel("X-Dimension (microns)") +ylabel("Y-Dimension (microns)") +plot([dat.x[nxmin+1],dat.x[nxmax-1]],[dat.y[nycenter2],dat.y[nycenter2]],ls = "-", color="k") +plot([dat.x[nxcenter2],dat.x[nxcenter2]],[dat.y[nymin+1],dat.y[nymax-1]],ls = "-", color="k") +#colorbar() + +subplot(1,2,2) +title("Phi-Collect Gate, z = %.2f"%dat.z[slicez]) +plot(dat.x[nxmin:nxmax],dat.phi[nxmin:nxmax, nycenter2, slicez], label = "XSlice, y = %.2f"%dat.y[nycenter2]) +plot(dat.y[nymin:nymax],dat.phi[nxcenter2,nymin:nymax, slicez], label = "YSlice, x = %.2f"%dat.x[nxcenter2]) +ylim(-10.0, 20.0) +xlim(dat.x[nxmin],dat.x[nxmax]) +xlabel("X,Y-Dimension (microns)") +ylabel("Potential(Volts)") +legend() +savefig(outputfiledir+"/plots/"+outputfilebase+"_1D_Potentials_2.pdf") + +print "Making 1D potential Plots #3 \n" +figure() + +suptitle("1D Potentials in Isolation Regions. Grid = %d*%d*%d."%(nxx,nyy,nzz),fontsize = 18) +subplots_adjust(hspace=0.3, wspace=0.3) +slicez = 16 * ScaleFactor +nxcenter3 = nxcenter2 + GridsPerPixel * ScaleFactor / 2 +nycenter3 = nycenter2 + GridsPerPixel * ScaleFactor / 2 +subplot(1,2,1, aspect = 1) +title("Phi, z = %.2f"%dat.z[slicez]) +levels = linspace(-20.0, 20.0, 21) +[yy,xx] = meshgrid(dat.y[nymin:nymax],dat.x[nxmin:nxmax]) +contour(xx,yy,dat.phi[nxmin:nxmax,nymin:nymax,slicez],levels,lw=0.1) +contourf(xx,yy,dat.phi[nxmin:nxmax,nymin:nymax,slicez],levels) +xlabel("X-Dimension (microns)") +ylabel("Y-Dimension (microns)") +plot([dat.x[nxmin+1],dat.x[nxmax-1]],[dat.y[nycenter3],dat.y[nycenter3]],ls = "-", color="k") +plot([dat.x[nxcenter3],dat.x[nxcenter3]],[dat.y[nymin+1],dat.y[nymax-1]],ls = "-", color="k") +#colorbar() + +subplot(1,2,2) +title("Phi-Collect Gate, z = %.2f"%dat.z[slicez]) +plot(dat.x[nxmin:nxmax],dat.phi[nxmin:nxmax, nycenter3, slicez], label = "XSlice, y = %.2f"%dat.y[nycenter3]) +plot(dat.y[nymin:nymax],dat.phi[nxcenter3,nymin:nymax, slicez], label = "YSlice, x = %.2f"%dat.x[nxcenter3]) +ylim(-10.0, 10.0) +xlim(dat.x[nxmin],dat.x[nxmax]) +xlabel("X,Y-Dimension (microns)") +ylabel("Potential(Volts)") +legend() +savefig(outputfiledir+"/plots/"+outputfilebase+"_1D_Potentials_3.pdf") + print "Making summary plots\n" figure() @@ -308,16 +423,16 @@ def ReadConfigFile(filename): nymin2 = nymin - 9 * GridsPerPixel * ScaleFactor / 2 rho0 = dat.rho[nxmin2,nymin2,slicez+1] -title("Log Abs Rho, z = %.2f - %.2f"%(dat.z[nzmin],dat.z[nzmax])) -levels = linspace(-1.0,1.0,21) -plotarray = array(log10(abs(dat.rho[nxmin:nxmax,nymin:nymax,nzmin:nzmax].sum(axis=2)/(nzmax-nzmin)))) +title("Rho, z = %.2f - %.2f"%(dat.z[nzmin],dat.z[nzmax])) +levels = linspace(-10.0,10.0,41) +plotarray = array(dat.rho[nxmin:nxmax,nymin:nymax,nzmin:nzmax].sum(axis=2)/(nzmax-nzmin)) contour(xx,yy,plotarray, levels, lw=0.1) contourf(xx,yy,plotarray, levels) xlabel("X-Dimension (microns)") ylabel("Y-Dimension (microns)") colorbar() -slicez = 1 * ScaleFactor +slicez = 8 * ScaleFactor subplot(2,2,3, aspect = 1) title("Phi, z = %.2f"%dat.z[slicez]) if EdgePlot: @@ -332,7 +447,7 @@ def ReadConfigFile(filename): plot([dat.x[nxcenter2],dat.x[nxcenter2]],[dat.y[nymin+1],dat.y[nymax-1]],ls = "-", color="k") colorbar() -slicez = 4 * ScaleFactor +slicez = 16 * ScaleFactor subplot(2,2,4, aspect = 1) title("Phi, z = %.2f"%dat.z[slicez]) contour(xx,yy,dat.phi[nxmin:nxmax,nymin:nymax,slicez],levels,lw=0.1) @@ -427,9 +542,13 @@ def ReadConfigFile(filename): xout = float(values[3]) yout = float(values[4]) if isnan(xout) or isnan(yout): + print "xin = %.3f, yin = %.3f is a nan" continue pixxout = int(xout/10.0) - pixyout = int(yout/10.0) + pixyout = int(yout/10.0) + + if xin>19.5 and xin < 20.5 and yin >19.5 and yin<20.5: + print xin, yin, pixxout, pixyout, plottedxin, plottedyin if (xin > plottedxin - .001) and (xin < plottedxin + .001) and \ (yin > plottedyin - .001) and (yin < plottedyin + .001): diff --git a/Run_BF_Multi.py b/Run_BF_Multi.py deleted file mode 100644 index aafa607..0000000 --- a/Run_BF_Multi.py +++ /dev/null @@ -1,332 +0,0 @@ -#!/usr/bin/env python - -#Author: Craig Lage, NYU; -#Date: 14-Sep-15 - -#This program manages the running of multiple Poisson spots -import matplotlib -matplotlib.use("Agg") -from pylab import * -import sys, time, subprocess,h5py -from scipy.special import erf -from scipy.optimize import fmin_powell -from scipy import stats -sys.path.append('/global/homes/c/cslage/Software/forward_model_varying_i') -import forward -from mpi4py import MPI - -#****************SUBROUTINES***************** - -class Array2dSet: - def __init__(self,xmin,xmax,nx,ymin,ymax,ny,nstamps): - # This packages up a set of nstamps postage stamp images, - # each image of which is nx * ny pixels - self.nx=nx - self.ny=ny - self.nstamps=nstamps - - self.xmin=xmin - self.ymin=ymin - - self.xmax=xmax - self.ymax=ymax - - self.dx=(xmax-xmin)/nx - self.dy=(ymax-ymin)/ny - - self.x=linspace(xmin+self.dx/2,xmax-self.dx/2,nx) - self.y=linspace(ymin+self.dy/2,ymax-self.dy/2,ny) - - self.data=zeros([nx,ny,nstamps]) - self.xoffset=zeros([nstamps]) - self.yoffset=zeros([nstamps]) - self.imax=zeros([nstamps]) - -class Array3dHDF5Elec(object): - def __init__(self, dir, filebase, n): - elecfile = dir+'/'+filebase+'_'+str(n)+'_Elec' - hdfelec = h5py.File(elecfile,'r') - Dimension = hdfelec[hdfelec.items()[0][0]].attrs[u'Dimension'] - self.nx=Dimension[0] - self.ny=Dimension[1] - self.nz=Dimension[2] - - Lower_Left = hdfelec[hdfelec.items()[0][0]].attrs[u'Lower_Left'] - self.xmin=Lower_Left[0] - self.ymin=Lower_Left[1] - self.zmin=Lower_Left[2] - - Upper_Right = hdfelec[hdfelec.items()[0][0]].attrs[u'Upper_Right'] - self.xmax=Upper_Right[0] - self.ymax=Upper_Right[1] - self.zmax=Upper_Right[2] - - self.dx=(self.xmax-self.xmin)/self.nx - self.dy=(self.ymax-self.ymin)/self.ny - self.dz=(self.zmax-self.zmin)/self.nz - self.volume = self.dx * self.dy * self.dz - - self.x=linspace(self.xmin+self.dx/2,self.xmax-self.dx/2,self.nx) - self.y=linspace(self.ymin+self.dy/2,self.ymax-self.dy/2,self.ny) - self.z=linspace(self.zmin+self.dz/2,self.zmax-self.dz/2,self.nz) - - self.elec=array(hdfelec[hdfelec.items()[0][0]]) - -def Area(xl, xh, yl, yh, sigmax, sigmay, Imax): - # Calculates how much of a 2D Gaussian falls within a rectangular box - ssigx = sqrt(2) * sigmax - ssigy = sqrt(2) * sigmay - I = (erf(xh/ssigx)-erf(xl/ssigx))*(erf(yh/ssigy)-erf(yl/ssigy)) - return Imax * I / 4.0 - -def FOM(params): - global spotlist - [sigmax, sigmay] = params - result = forward.forward(spotlist,sigmax,sigmay) - return result - -def ReadConfigFile(filename): - # This reads the config file for the necessary settings - # and returns a dictionary with the values - file = open(filename,'r') - lines=file.readlines() - file.close() - ConfigData = {} - try: - for line in lines: - ThisLine=line.strip().split() - ThisLineLength=len(ThisLine) - if ThisLineLength < 3: - continue - if list(ThisLine[0])[0]=='#' or ThisLine[0]=='\n': - continue - try: - ParamName = ThisLine[0] - ThisLine.remove(ThisLine[0]) - for counter,item in enumerate(ThisLine): - if list(item)[0] == '#': - del ThisLine[counter:] # Strip the rest of the line as a comment - continue - if item == '=': - ThisLine.remove(item) - continue - if len(ThisLine) == 0: - continue - elif len(ThisLine) == 1: - ThisParam = ThisLine[0] - try: ConfigData[ParamName] = int(ThisParam) - except ValueError: - try: ConfigData[ParamName] = float(ThisParam) - except ValueError: - try: - ConfigData[ParamName] = ThisParam - except ValueError: - print "Error reading .cfg file" - else: - ThisParam = [] - for item in ThisLine: - try: ThisParam.append(int(item)) - except ValueError: - try: ThisParam.append(float(item)) - except ValueError: - ThisParam.append(item) - ConfigData[ParamName] = ThisParam - except: - continue - except: - print "Error reading .cfg file" - - return ConfigData - -def New_Cfg_File(incfgfile, outcfgfile, newrun): - # This increments the run number to start a new spot - # and assigns a random offset value within the central pixel - ConfigData = ReadConfigFile(incfgfile) - lines = OpenFile(incfgfile) - - dirbase = ConfigData['outputfiledir'].split('run') - - xoff = -5.0 + 10.0 * rand() - yoff = -5.0 + 10.0 * rand() - lines[110] = 'Xoffset = '+str(xoff)+'\n' - lines[111] = 'Yoffset = '+str(yoff)+'\n' - lines[133] = 'outputfiledir = '+dirbase[0]+'run'+newrun+'\n' - newcfgfile = open(outcfgfile, 'w') - for line in lines: - newcfgfile.write(line) - newcfgfile.close() - - return - - -def OpenFile(filename): - Numtries = 10 - tries = 0 - lines = [] - while tries < Numtries: - try: - file = open(filename, 'r') - lines = file.readlines() - file.close() - break - except: - time.sleep(1.0) - tries += 1 - - return lines - - -def FillSpotlist(run, Numspots): - global spotlist - # Note sigmas and offset are in pixels, not microns. - incfgfile = datadir+startdir+'bf.cfg' - InConfigData = ReadConfigFile(incfgfile) - # Postage Stamp size - nx = InConfigData['PixelBoundaryNx'] - ny = InConfigData['PixelBoundaryNy'] - - outputfiledir = InConfigData['outputfiledir'] - outputfilebase = InConfigData['outputfilebase'] - GridsPerPixel = InConfigData['GridsPerPixel'] * InConfigData['ScaleFactor'] - stampxmin = -(int(nx/2)+0.5) - stampxmax = -stampxmin - stampymin = -(int(ny/2)+0.5) - stampymax = -stampymin - - spotlist = Array2dSet(stampxmin,stampxmax,nx,stampymin,stampymax,ny,Numspots) - - dirbase = outputfiledir.split('bfrun') - - for spot in range(1,Numspots): # Don't include run 0 because it's different - dat = Array3dHDF5Elec(dirbase[0]+'bfrun_%d'%spot, outputfilebase, run) - cfgfile = dirbase[0]+'bfrun_%d'%spot+'/bf.cfg' - ConfigData = ReadConfigFile(cfgfile) - - spotlist.xoffset[spot] = ConfigData['Xoffset'] / ConfigData['PixelSize'] - spotlist.yoffset[spot] = ConfigData['Yoffset'] / ConfigData['PixelSize'] - - for i in range(nx): - nxmin = ((ConfigData['PixelBoundaryLowerLeft'][0] - dat.xmin) / dat.dx) + GridsPerPixel * i - nxmax = nxmin + GridsPerPixel - for j in range(ny): - nymin = ((ConfigData['PixelBoundaryLowerLeft'][1] - dat.ymin) / dat.dy) + GridsPerPixel * j - nymax = nymin + GridsPerPixel - electrons_in_pixel = dat.elec[nxmin:nxmax,nymin:nymax,:].sum() - #print "i = %d, j = %d, nxmin = %d, nymin = %d, electron = %d"%(i,j,nxmin,nymin,electrons_in_pixel) - spotlist.data[i,j,spot] = electrons_in_pixel - - param0 = [1.00, 1.00] - args = () - Result = fmin_powell(FOM, param0, args) - - imax = spotlist.imax.mean() - ADU_correction = Area(-0.5,0.5,-0.5,0.5,Result[0],Result[1],1.0) - - spotdata = [run, Result[0], Result[1], imax * ADU_correction] - print spotdata - comm.send(spotdata, dest = (Numspots - 1), tag = run) - return - - -def PlotSpotlist(Numruns, Numspots, imaxs, sigmaxs, sigmayx): - global spotlist - incfgfile = datadir+startdir+'bf.cfg' - InConfigData = ReadConfigFile(incfgfile) - # Postage Stamp size - nx = InConfigData['PixelBoundaryNx'] - ny = InConfigData['PixelBoundaryNy'] - figure() - title("Baseline - Sigmax = Sigmay = 1.0, Offsets=random, With Diffusion") - scatter(imaxs, sigmaxs, color = 'green', lw = 2, label = 'Sigma-x') - scatter(imaxs, sigmays, color = 'red', lw = 2, label = 'Sigma-y') - - slope, intercept, r_value, p_value, std_err = stats.linregress(imaxs[2:7],sigmaxs[2:7]) - xplot=linspace(0.0,150000.0,100) - yplot = slope * xplot + intercept - plot(xplot, yplot, color='blue', lw = 2, ls = '--') - tslope = slope * 100.0 * 50000.0 - text(10000.0,0.98,"X Slope = %.2f %% per 50K e-, Intercept = %.3f"%(tslope,intercept)) - - slope, intercept, r_value, p_value, std_err = stats.linregress(imaxs[2:7],sigmays[2:7]) - xplot=linspace(0.0,150000.0,100) - yplot = slope * xplot + intercept - plot(xplot, yplot, color='black', lw = 2, ls = '--') - tslope = slope * 100.0 * 50000.0 - text(10000.0,0.97,"Y Slope = %.2f %% per 50K e-, Intercept = %.3f"%(tslope,intercept)) - - text(10000.0,0.99,"%d Simulated spots"%Numspots) - xlabel('Central Peak(electrons)') - ylabel('Sigma (Pixels)') - legend(loc= 'lower right') - ylim(0.95, 1.10) - xlim(0.0,150000.0) - xticks([0.0,50000,100000]) - - savefig(datadir+startdir+"plots/BF_Sim_%d_%d.png"%(Numruns,Numspots)) - return - -#****************MAIN PROGRAM***************** -global spotlist -datadir = 'data/' -startdir = 'bfrun1/' - -comm = MPI.COMM_WORLD -rank = comm.Get_rank() -Numspots = comm.Get_size() - -comm.Barrier() # Wait until everybody gets here - -runname = '_%d'%rank -nextdir = datadir+'bfrun'+runname+'/' -newdir = subprocess.Popen('mkdir -p '+nextdir, shell=True) -subprocess.Popen.wait(newdir) -incfgfile = datadir+startdir+'bf.cfg' -outcfgfile = nextdir+'bf.cfg' -ConfigData = ReadConfigFile(incfgfile) -Numruns = ConfigData['NumSteps'] -SaveData = ConfigData['SaveData'] - -New_Cfg_File(incfgfile, outcfgfile, runname) - -if rank == 0: # Use run0 for the area shift with all of the charge in the central pixel. - newdir = subprocess.Popen('cp data/bfrun1/bf0.cfg '+nextdir+'bf.cfg', shell=True) - subprocess.Popen.wait(newdir) - - -cmd = '~/Software/Poisson_CCD22/src/Poisson '+outcfgfile -cpp_job = subprocess.Popen(cmd, shell=True) -subprocess.Popen.wait(cpp_job) -time.sleep(1.0) - -comm.Barrier() # Wait until everybody gets here - - -NumPts = Numruns/SaveData - -if rank == Numspots - 1: # Use the last processor to gather the data and plot it - imaxs = zeros([NumPts]) - sigmaxs = zeros([NumPts]) - sigmays = zeros([NumPts]) - - for point in range(NumPts): - run = point * SaveData - src = run % (Numspots - 1) - spotdata = comm.recv(source=src, tag = run) - if run != spotdata[0]: - print "Communication error! Run = %d, tag = %d"%(run, spotdata[0]) - continue - else: - print "Received data for run = %d"%run - sigmaxs[point] = spotdata[1] - sigmays[point] = spotdata[2] - imaxs[point] = spotdata[3] - - PlotSpotlist(Numruns, Numspots, imaxs, sigmaxs, sigmays) - -else: # Everybody else analyzes one or more runs with all of the spots. - for point in range(NumPts): - run = point * SaveData - if run % (Numspots - 1) == rank: - FillSpotlist(run, Numspots) - - diff --git a/data/run1/bf.cfg b/data/run1/bf.cfg index cc45762..af711dc 100644 --- a/data/run1/bf.cfg +++ b/data/run1/bf.cfg @@ -12,14 +12,14 @@ # Poisson solver constants # These control the numerics of the Poisson solver # They should not need to be changed -w = 1.9 # Successive Over-Relaxation factor -ncycle = 128 # Number of smoothing cycles at finest resolution +w = 1.8 # Successive Over-Relaxation factor +ncycle = 32 # Number of smoothing cycles at finest resolution iterations = 1 # Number of VCycles # ------------------------------------------------------------------------------ # Overall setup - these control the size and scale of the simulated volume -ScaleFactor = 2 # Power of 2 that sets the grid size +ScaleFactor = 1 # Power of 2 that sets the grid size # ScaleFactor = 1 means grid size is 0.625 micron, 160 grids in the z-direction # ScaleFactor = 2 cuts grid size by a actor of 2 # ScaleFactor = 4 cuts grid size by a actor of 4, etc. @@ -36,25 +36,24 @@ SimulationRegionLowerLeft = 5.0 5.0 # Allows adjustment of X, Y coordinates # The value of (5.0, 5.0) centers the PixelBoundaryRegion # in the SimulationRegion # ------------------------------------------------------------------------------ -# Voltages and Charges - these should be self-explanatory +# Voltages and Charges - these should be self-explanatory Vbb = -60.0 # Back bias Vparallel_lo = -8.0 # Parallel Low Voltage Vparallel_hi = 4.0 # Parallel High Voltage Vserial_lo = -4.0 # Serial Low Voltage Vserial_hi = 6.0 # Serial High Voltage Vscupper = 19.0 # Scupper voltage -GateOxide = 0.15 # Gate Oxide thickness in microns +GateOxide = 0.14 # Gate Oxide thickness in microns CollectingPhases = 2 # 1=One Parallel gate High, 2=Two Parallel gates High - BackgroundDoping = -1.0E12 # Background doping in cm^-3 ChannelStopDoping = -2.0E12 # Channel Stop doping in cm^-2 -ChannelStopProfile = 0 # 0 = Square profile, 1 = Gaussian profile -ChannelStopDepth = 2.0 # Channel stop depth in microns +ChannelStopProfile = 1 # 0 = Square profile, 1 = Gaussian profile +ChannelStopDepth = 1.2 # Channel stop depth in microns ChannelStopWidth = 2.0 # ChannelStop width in microns -ChannelDoping = 0.8E12 # Channel doping in cm^-2 -ChannelProfile = 0 # 0 = Square profile, 1 = Gaussian profile -ChannelDepth = 1.0 # Channel depth in microns +ChannelDoping = 1.0E12 # Channel doping in cm^-2 +ChannelProfile = 1 # 0 = Square profile, 1 = Gaussian profile +ChannelDepth = 0.18 # Channel depth in microns UndepletedChannelStop = 0 # 0 = No undepleted Region, 1 = undepleted Region Vchannelstop = 0.0 # Voltage in undepleted channel stop @@ -67,15 +66,15 @@ NumberofPixelRegions = 1 # 1 PixelRegionLowerLeft_0 = 0.0 0.0 # PixelRegionUpperRight_0 = 110.0 110.0 # NumberofFilledWells_0 = 1 # -CollectedCharge_0_0 = 200000 # Collected charge in e- +CollectedCharge_0_0 = 100000 # Collected charge in e- FilledPixelCoords_0_0 = 55.0 55.0 # (x,y) coords of pixel center -CollectedChargeZmin = 0.65 # These parameters allow you to set the location of the initial collected charge -CollectedChargeZmax = 0.90 # -CollectedChargeXmin = 1.2 # -CollectedChargeXmax = 8.8 # -CollectedChargeYmin = 1.66 # -CollectedChargeYmax = 8.34 # +CollectedChargeZmin = 0.48 # These parameters allow you to set the location of the initial collected charge +CollectedChargeZmax = 0.52 # +CollectedChargeXmin = 3.0 # +CollectedChargeXmax = 7.0 # +CollectedChargeYmin = 2.4 # +CollectedChargeYmax = 7.6 # # ------------------------------------------------------------------------------ # Constant Voltage Regions - this allows a number of regions of fixed surface potential # Each Constant Voltage region will need its extents defined @@ -87,10 +86,10 @@ NumberofFixedRegions = 0 ElectronZ0Area = 95.0 # Starting z value of electron for Area/Vertex plots. 100.0 is at the incident light # surface. LogEField = 1 # 0 - don't calculate E-Field, 1 - Calculate and store E-Field -LogPixels = 0 # 0 - don't calculate boundaries, 1 - calculate and store boundaries +LogPixels = 1 # 0 - don't calculate boundaries, 1 - calculate and store boundaries LogPixelPaths = 0 # 0 - only the final (z~0) point is logged, 1 - Entire path is logged PixelAreas = -1 # -1 - Don't calculate areas, N - calculate areas every nth step -NumVertices = 8 # Number of vertices per side for the pixel area calculation. +NumVertices = 32 # Number of vertices per side for the pixel area calculation. # Since there are also 4 corners, there will be: # (4 * NumVertices + 4) vertices in each pixel @@ -136,3 +135,4 @@ outputfilebase = BF_256_9x9 EdgePlot = 0 # Tells plot program whether it is the edge of the array PlotEField = 0 # Tells plot program whether or not to plot E-field in Summary plot. SaveData = 1 # 0 - Save only Pts data, N - Save all data every Nth step +SaveElec = 1 # 0 - Save only Pts data, N - Save Elec data every Nth step diff --git a/data/run1/plots/BF_256_9x9_1D_Potentials.pdf b/data/run1/plots/BF_256_9x9_1D_Potentials.pdf index 66b55c8..f488538 100644 Binary files a/data/run1/plots/BF_256_9x9_1D_Potentials.pdf and b/data/run1/plots/BF_256_9x9_1D_Potentials.pdf differ diff --git a/data/run1/plots/BF_256_9x9_1D_Potentials_2.pdf b/data/run1/plots/BF_256_9x9_1D_Potentials_2.pdf new file mode 100644 index 0000000..24dd274 Binary files /dev/null and b/data/run1/plots/BF_256_9x9_1D_Potentials_2.pdf differ diff --git a/data/run1/plots/BF_256_9x9_1D_Potentials_3.pdf b/data/run1/plots/BF_256_9x9_1D_Potentials_3.pdf new file mode 100644 index 0000000..47bfa32 Binary files /dev/null and b/data/run1/plots/BF_256_9x9_1D_Potentials_3.pdf differ diff --git a/data/run1/plots/BF_256_9x9_Edge_Potentials.pdf b/data/run1/plots/BF_256_9x9_Edge_Potentials.pdf index 37b8881..a4c8f97 100644 Binary files a/data/run1/plots/BF_256_9x9_Edge_Potentials.pdf and b/data/run1/plots/BF_256_9x9_Edge_Potentials.pdf differ diff --git a/data/run1/plots/BF_256_9x9_Summary_1.pdf b/data/run1/plots/BF_256_9x9_Summary_1.pdf index 17c86a3..0b50992 100644 Binary files a/data/run1/plots/BF_256_9x9_Summary_1.pdf and b/data/run1/plots/BF_256_9x9_Summary_1.pdf differ diff --git a/data/run1/plots/BF_256_9x9_Summary_2.pdf b/data/run1/plots/BF_256_9x9_Summary_2.pdf index 6cac1dd..a9eba5b 100644 Binary files a/data/run1/plots/BF_256_9x9_Summary_2.pdf and b/data/run1/plots/BF_256_9x9_Summary_2.pdf differ diff --git a/data/run2/bf.cfg b/data/run2/bf.cfg index 8b009c8..470043c 100644 --- a/data/run2/bf.cfg +++ b/data/run2/bf.cfg @@ -12,8 +12,8 @@ # Poisson solver constants # These control the numerics of the Poisson solver # They should not need to be changed -w = 1.9 # Successive Over-Relaxation factor -ncycle = 128 # Number of smoothing cycles at finest resolution +w = 1.8 # Successive Over-Relaxation factor +ncycle = 32 # Number of smoothing cycles at finest resolution iterations = 1 # Number of VCycles # ------------------------------------------------------------------------------ @@ -36,25 +36,24 @@ SimulationRegionLowerLeft = 5.0 5.0 # Allows adjustment of X, Y coordinates # The value of (5.0, 5.0) centers the PixelBoundaryRegion # in the SimulationRegion # ------------------------------------------------------------------------------ -# Voltages and Charges - these should be self-explanatory +# Voltages and Charges - these should be self-explanatory Vbb = -60.0 # Back bias Vparallel_lo = -8.0 # Parallel Low Voltage Vparallel_hi = 4.0 # Parallel High Voltage Vserial_lo = -4.0 # Serial Low Voltage Vserial_hi = 6.0 # Serial High Voltage Vscupper = 19.0 # Scupper voltage -GateOxide = 0.15 # Gate Oxide thickness in microns +GateOxide = 0.14 # Gate Oxide thickness in microns CollectingPhases = 2 # 1=One Parallel gate High, 2=Two Parallel gates High - BackgroundDoping = -1.0E12 # Background doping in cm^-3 ChannelStopDoping = -2.0E12 # Channel Stop doping in cm^-2 -ChannelStopProfile = 0 # 0 = Square profile, 1 = Gaussian profile -ChannelStopDepth = 2.0 # Channel stop depth in microns +ChannelStopProfile = 1 # 0 = Square profile, 1 = Gaussian profile +ChannelStopDepth = 1.2 # Channel stop depth in microns ChannelStopWidth = 2.0 # ChannelStop width in microns -ChannelDoping = 0.8E12 # Channel doping in cm^-2 -ChannelProfile = 0 # 0 = Square profile, 1 = Gaussian profile -ChannelDepth = 1.0 # Channel depth in microns +ChannelDoping = 1.0E12 # Channel doping in cm^-2 +ChannelProfile = 1 # 0 = Square profile, 1 = Gaussian profile +ChannelDepth = 0.18 # Channel depth in microns UndepletedChannelStop = 0 # 0 = No undepleted Region, 1 = undepleted Region Vchannelstop = 0.0 # Voltage in undepleted channel stop @@ -67,15 +66,15 @@ NumberofPixelRegions = 1 # 1 PixelRegionLowerLeft_0 = 0.0 0.0 # PixelRegionUpperRight_0 = 110.0 110.0 # NumberofFilledWells_0 = 1 # -CollectedCharge_0_0 = 200000 # Collected charge in e- +CollectedCharge_0_0 = 100000 # Collected charge in e- FilledPixelCoords_0_0 = 55.0 55.0 # (x,y) coords of pixel center -CollectedChargeZmin = 0.65 # These parameters allow you to set the location of the initial collected charge -CollectedChargeZmax = 0.90 # -CollectedChargeXmin = 1.2 # -CollectedChargeXmax = 8.8 # -CollectedChargeYmin = 1.66 # -CollectedChargeYmax = 8.34 # +CollectedChargeZmin = 0.48 # These parameters allow you to set the location of the initial collected charge +CollectedChargeZmax = 0.52 # +CollectedChargeXmin = 3.0 # +CollectedChargeXmax = 7.0 # +CollectedChargeYmin = 2.4 # +CollectedChargeYmax = 7.6 # # ------------------------------------------------------------------------------ # Constant Voltage Regions - this allows a number of regions of fixed surface potential # Each Constant Voltage region will need its extents defined @@ -88,20 +87,20 @@ ElectronZ0Area = 95.0 # Starting z value of electron for Area/Ve # surface. LogEField = 1 # 0 - don't calculate E-Field, 1 - Calculate and store E-Field LogPixels = 1 # 0 - don't calculate boundaries, 1 - calculate and store boundaries -LogPixelPaths = 1 # 0 - only the final (z~0) point is logged, 1 - Entire path is logged +LogPixelPaths = 0 # 0 - only the final (z~0) point is logged, 1 - Entire path is logged PixelAreas = -1 # -1 - Don't calculate areas, N - calculate areas every nth step -NumVertices = 8 # Number of vertices per side for the pixel area calculation. +NumVertices = 32 # Number of vertices per side for the pixel area calculation. # Since there are also 4 corners, there will be: # (4 * NumVertices + 4) vertices in each pixel -PixelBoundaryTestType = 0 # 0 - Run a grid of equally spaced electrons, +PixelBoundaryTestType = 1 # 0 - Run a grid of equally spaced electrons, # 1 - Run a random set of electrons with a Gaussian pattern # 2 - Run a random set of electrons inside PixelBoundary # ------------------------------------------------------------------------------ # This defines the parameters for the Random Gaussian which fills the wells ElectronZ0Fill = 95.0 # Starting z value of electron for filling. 100.0 is at the incident light -PixelBoundaryLowerLeft = 40.0 40.0 -PixelBoundaryUpperRight = 70.0 70.0 +PixelBoundaryLowerLeft = 10.0 10.0 +PixelBoundaryUpperRight = 100.0 100.0 PixelBoundaryNx = 9 # Number of pixels in postage stamp PixelBoundaryNy = 9 # Number of pixels in postage stamp @@ -118,7 +117,7 @@ NumSteps = 1 # Number of steps, each one adding NumElec electrons CCDTemperature = 173.0 # Temp in Degrees K. Used to calculate diffusion steps. -DiffMultiplier = 0.0 # Used to adjust the amount of diffusion. +DiffMultiplier = 1.0 # Used to adjust the amount of diffusion. # A value of 1.0 gives the theoretical amount of diffusion # A value of 0.0 turns off diffusion completely @@ -136,3 +135,4 @@ outputfilebase = BF_256_9x9 EdgePlot = 0 # Tells plot program whether it is the edge of the array PlotEField = 0 # Tells plot program whether or not to plot E-field in Summary plot. SaveData = 1 # 0 - Save only Pts data, N - Save all data every Nth step +SaveElec = 1 # 0 - Save only Pts data, N - Save Elec data every Nth step diff --git a/data/run5/edge.cfg b/data/run5/edge.cfg deleted file mode 100644 index 2dbc90c..0000000 --- a/data/run5/edge.cfg +++ /dev/null @@ -1,198 +0,0 @@ -# -# ------------------------------------------------------------------------------ -# Author: Craig Lage, UC Davis -# Date: Sep 3, 2015 -# -# Standalone cpp Poisson solver -# -# -# Poisson Solver configuration file - - -# Poisson solver constants -# These control the numerics of the Poisson solver -# They should not need to be changed -w = 1.9 # Successive Over-Relaxation factor -ncycle = 128 # Number of smoothing cycles at finest resolution -iterations = 1 # Number of VCycles - -# ------------------------------------------------------------------------------ -# Overall setup - these control the size and scale of the simulated volume - -ScaleFactor = 2 # Power of 2 that sets the grid size -# ScaleFactor = 1 means grid size is 0.625 micron, 160 grids in the z-direction -# ScaleFactor = 2 cuts grid size by a actor of 2 -# ScaleFactor = 4 cuts grid size by a actor of 4, etc. - -PixelSize = 10.0 # Pixel size in microns -GridsPerPixel = 16 # Number of grids per pixel at ScaleFactor = 1 -Nx = 160 # Number of grids in x at ScaleFactor = 1 (Must be a multiple of 32) -Ny = 672 # Number of grids in y at ScaleFactor = 1 (Must be a multiple of 32) - -XBCType = 1 # Set X direction boundary conditions: 0 - Free (Eperp = 0), 1 - Periodic -YBCType = 0 # Set Y direction boundary conditions: 0 - Free (Eperp = 0), 1 - Periodic - -SimulationRegionLowerLeft = 5.0 5.0 # Allows adjustment of X, Y coordinates - # The value of (5.0, 5.0) centers the PixelBoundaryRegion - # in the SimulationRegion -# ------------------------------------------------------------------------------ -# Voltages and Charges - these should be self-explanatory - -Vbb = -60.0 # Back bias -Vparallel_lo = -8.0 # Parallel Low Voltage -Vparallel_hi = 4.0 # Parallel High Voltage -Vserial_lo = -4.0 # Serial Low Voltage -Vserial_hi = 6.0 # Serial High Voltage -Vscupper = 19.0 # Scupper voltage -GateOxide = 0.15 # Gate Oxide thickness in microns -CollectingPhases = 2 # 1=One Parallel gate High, 2=Two Parallel gates High - -BackgroundDoping = -1.0E12 # Background doping in cm^-3 -ChannelStopDoping = -2.0E12 # Channel Stop doping in cm^-2 -ChannelStopProfile = 0 # 0 = Square profile, 1 = Gaussian profile -ChannelStopDepth = 2.0 # Channel stop depth in microns -ChannelStopWidth = 2.0 # ChannelStop width in microns -ChannelDoping = 0.8E12 # Channel doping in cm^-2 -ChannelProfile = 0 # 0 = Square profile, 1 = Gaussian profile -ChannelDepth = 1.0 # Channel depth in microns -UndepletedChannelStop = 0 # 0 = No undepleted Region, 1 = undepleted Region -Vchannelstop = 0.0 # Voltage in undepleted channel stop - -# ------------------------------------------------------------------------------ -# Pixel Regions - This is set up for a 9x9 "postage stamp" -# These allow one to set up one or more regions of regularly spaced pixels. -# Each pixel region will need its extents defined -# Within each pixel region, one can fill multiple collecting wells with arbitrary amounts of charge -NumberofPixelRegions = 1 # 1 -PixelRegionLowerLeft_0 = 0.0 0.0 # -PixelRegionUpperRight_0 = 110.0 150.0 # -NumberofFilledWells_0 = 1 # -CollectedCharge_0_0 = 0 # Collected charge in e- -FilledPixelCoords_0_0 = 55.0 55.0 # (x,y) coords of pixel center - -CollectedChargeZmin = 0.65 # These parameters allow you to set the location of the initial collected charge -CollectedChargeZmax = 0.90 # -CollectedChargeXmin = 1.2 # -CollectedChargeXmax = 8.8 # -CollectedChargeYmin = 1.66 # -CollectedChargeYmax = 8.34 # -# ------------------------------------------------------------------------------ -# Constant Voltage Regions - this allows a number of regions of fixed surface potential -# Each Constant Voltage region will need its extents defined -NumberofFixedRegions = 10 -FixedRegionLowerLeft_0 = 0.0 367.0 # -FixedRegionUpperRight_0 = 110.0 420.0 # -FixedRegionVoltage_0 = -60.0 # -FixedRegionDoping_0 = 0.0 # Fixed region doping in cm^-2 -FixedRegionChargeDepth_0 = 0.0 # -FixedRegionBCType_0 = 0 # -FixedRegionLowerLeft_1 = 0.0 357.0 # -FixedRegionUpperRight_1 = 110.0 367.0 # -FixedRegionVoltage_1 = -44.0 # -FixedRegionDoping_1 = 0.0 # Fixed region doping in cm^-2 -FixedRegionChargeDepth_1 = 0.0 # -FixedRegionBCType_1 = 0 # -FixedRegionLowerLeft_2 = 0.0 352.0 # -FixedRegionUpperRight_2 = 110.0 357.0 # -FixedRegionVoltage_2 = -28.0 # -FixedRegionDoping_2 = 0.0 # Fixed region doping in cm^-2 -FixedRegionChargeDepth_2 = 0.0 # -FixedRegionBCType_2 = 0 # -FixedRegionLowerLeft_3 = 0.0 342.0 # -FixedRegionUpperRight_3 = 110.0 352.0 # -FixedRegionVoltage_3 = -12.0 # -FixedRegionDoping_3 = 0.0 # Fixed region doping in cm^-2 -FixedRegionChargeDepth_3 = 0.0 # -FixedRegionBCType_3 = 0 # -FixedRegionLowerLeft_4 = 0.0 337.0 # -FixedRegionUpperRight_4 = 110.0 342.0 # -FixedRegionVoltage_4 = 4.5 # -FixedRegionDoping_4 = 0.0 # Fixed region doping in cm^-2 -FixedRegionChargeDepth_4 = 0.0 # -FixedRegionBCType_4 = 0 # -FixedRegionLowerLeft_5 = 0.0 322.0 # -FixedRegionUpperRight_5 = 110.0 337.0 # -FixedRegionVoltage_5 = 19.0 # -FixedRegionDoping_5 = 0.0 # Fixed region doping in cm^-2 -FixedRegionChargeDepth_5 = 0.0 # -FixedRegionBCType_5 = 0 # -FixedRegionLowerLeft_6 = 0.0 197.0 # -FixedRegionUpperRight_6 = 110.0 322.0 # -FixedRegionVoltage_6 = 0.0 # -FixedRegionDoping_6 = 0.0 # Fixed region doping in cm^-2 -FixedRegionChargeDepth_6 = 0.0 # -FixedRegionBCType_6 = 1 # Free BC in this region -FixedRegionLowerLeft_7 = 0.0 174.0 # -FixedRegionUpperRight_7 = 110.0 197.0 # -FixedRegionVoltage_7 = -2.0 # -FixedRegionDoping_7 = 0.0 # Fixed region doping in cm^-2 -FixedRegionChargeDepth_7 = 0.0 # -FixedRegionBCType_7 = 0 # -FixedRegionLowerLeft_8 = 0.0 170.0 # -FixedRegionUpperRight_8 = 110.0 174.0 # -FixedRegionVoltage_8 = 0.0 # -FixedRegionDoping_8 = 0.0 # Fixed region doping in cm^-2 -FixedRegionChargeDepth_8 = 0.0 # -FixedRegionBCType_8 = 0 # -FixedRegionLowerLeft_9 = 0.0 150.0 # -FixedRegionUpperRight_9 = 110.0 170.0 # -FixedRegionVoltage_9 = -2.0 # -FixedRegionDoping_9 = 0.0 # Fixed region doping in cm^-2 -FixedRegionChargeDepth_9 = 0.0 # -FixedRegionBCType_9 = 0 # - -# ------------------------------------------------------------------------------ -# Pixel Boundary Tests - This allows tracing the pixel boundaries and electron paths - -ElectronZ0Area = 95.0 # Starting z value of electron for Area/Vertex plots. 100.0 is at the incident light - # surface. -LogEField = 1 # 0 - don't calculate E-Field, 1 - Calculate and store E-Field -LogPixels = 1 # 0 - don't calculate boundaries, 1 - calculate and store boundaries -LogPixelPaths = 1 # 0 - only the final (z~0) point is logged, 1 - Entire path is logged -PixelAreas = -1 # -1 - Don't calculate areas, N - calculate areas every nth step -NumVertices = 8 # Number of vertices per side for the pixel area calculation. - # Since there are also 4 corners, there will be: - # (4 * NumVertices + 4) vertices in each pixel - -PixelBoundaryTestType = 0 # 0 - Run a grid of equally spaced electrons, - # 1 - Run a random set of electrons with a Gaussian pattern - # 2 - Run a random set of electrons inside PixelBoundary -# ------------------------------------------------------------------------------ -# This defines the parameters for the Random Gaussian which fills the wells -ElectronZ0Fill = 95.0 # Starting z value of electron for filling. 100.0 is at the incident light -PixelBoundaryLowerLeft = 40.0 10.0 -PixelBoundaryUpperRight = 70.0 150.0 - -PixelBoundaryNx = 9 # Number of pixels in postage stamp -PixelBoundaryNy = 9 # Number of pixels in postage stamp - -Sigmax = 10.0 # Sigma of incoming light profile -Sigmay = 10.0 # Sigma of incoming light profile -Xoffset = 0.0 # Center offset of incoming light profile -Yoffset = 0.0 # Center offset of incoming light profile - -NumElec = 0 # Number of electrons to be traced between field recalculation - # Also used if PixelBoundaryTestType = 2 -NumSteps = 1 # Number of steps, each one adding NumElec electrons - - -CCDTemperature = 173.0 # Temp in Degrees K. Used to calculate diffusion steps. - -DiffMultiplier = 0.0 # Used to adjust the amount of diffusion. - # A value of 1.0 gives the theoretical amount of diffusion - # A value of 0.0 turns off diffusion completely - -NumDiffSteps = 1 # A speed/accuracy trade-off. A value of 1 uses the theoretical diffusion - # step. A higher value takes larger steps. I have done a few tests - # but I recommend using a value of 1 unless you test larger values. -SaturationModel = 0 # Saturation Model 1=On, 0=Off; Experimental! -# The parameters below would be used if PixelBoundaryTestType = 0 -PixelBoundaryStepSize = 0.5 0.5 - -# ------------------------------------------------------------------------------ -# These control the location and naming of the output -outputfiledir = data/run5 -outputfilebase = Edge_256 -EdgePlot = 1 # Tells plot program whether it is the edge of the array -PlotEField = 0 # Tells plot program whether or not to plot E-field in Summary plot. -SaveData = 1 # 0 - Save only Pts data, N - Save all data every Nth step diff --git a/docs/REVISIONS b/docs/REVISIONS new file mode 100644 index 0000000..4ca1ed6 --- /dev/null +++ b/docs/REVISIONS @@ -0,0 +1,180 @@ +Craig Lage - 24-Nov-14 +This note documents the evolution of the evolution of the Poisson solver I am writing to simulate charge transfer in the LSST CCDs. The solver uses the method of Successive OverRelaxation (SOR) coupled with the concept of V-Cycles of successively smaller grids, which dramatically speeds up the convergence. + +The outer grid cells (0 and N) hold the boundary conditions, so iteration only takes place from cells 1 -> N-2. The size of the inner array must be a multiple of 2 for the V-Cycles to work properly, so the arrays are of size 2**n + 2 - i.e (6, 10, 18, 34, 66...) + +Poisson_py - This was a Python version to develop the algorithms, test out the concept, and gauge the speed. A 128^3 converged after about 5 V-Cycles, and took about 1600 seconds for 10 V-Cycles. Assuming a 100X speed up in C/C++, this means a 256^3 should take only about 2 minutes, which should be adequate. + +Poisson_cpp - This was a conversion of the above code to C++, getting the algorithms working and verifying >100X speed-up. + +Poisson_cpy* - These are a series of codes using a Python wrapper calling a C++ .so library. + +Poisson_rho_cpy* - These added the charge density calculation. Started to really work with Poisson_cpy5. Poisson_rho_cpy7 is pretty good. + +Poisson_pixels* - These added the CCD gate potentials, and started calcualting and plotting the E-Field. Poisson_pixels2 was good enough to make some plots to send to Tony for a grant proposal. + +Poisson_grid* - Starting to add the channel stop charge and beginning to calculate the electron path and develop grid maps. + +Poisson_grid1* - With channel stop charge. + +Poisson_grid2* - These have the array edge, with the serial grids and scupper voltages, and some attempts to calculate the electron path. These still aren't working very well. + +Poisson_grid3* - This has a fairly major re-write. I realized things weren't converging as well as I thought, since the BCs weren't being transferred to the coarser grids properly. I re-wrote the Restriction and Prolongation routines so that the coarser arrays are centered on the same points as the finer arrays. This allows the BCs to be transferred directly. For this reason, I also went to 12 grid points per pixel, because then everything is divisible by 4 so things transfer down at least to 2 coarser grids without losing the pattern. I also added while statements in the VCycle so that the iterations continue at each resolution until they have converged to some value. This is also working OK now. The electron path calculation is still not working, but that is for another day (26-Nov-14). + +Something is still not right. Returning the Prolongated full array before doing any SOR on it shows that the data is somehow shifted. This is why it is taking so many iterations. I have to get to the bottom of this. + +Next step: Modify grid3B to allow me to return the 64x64x64 array as well as the 128x128x128, and then plot them in Python. + +2-Dec-14: The above problems are all fixed now. It isn't necessary to iterate at the finest scale until machine precision is reached. A fixed number of iterations at each scale (say 100) is sufficient, because the solution from the coarser grid is almost correct. I have also modified the BC so that they are fixed BC on the top and bottom, but free BC (first derivative of phi = 0) on the sides. This is more realistic. I have also added a small background charge (~ 1E12 cm-3) to the problem. I've also sped up the inner loops significantly - it only takes 200 seconds for 256^3, and about 2400 seconds for 512^3 (why not 8X?). The latest revisions are in Poisson_grid2C and Poisson_grid3D. The C++ code is identical in these two folders. grid3D is a square cross section with pixels, and grid2C is a rectangular (256x128x128, say) region with the array edge. I've also changed to basic setup to have 12 grid points per 10 micron pixel, so the thickness is 128 * (10/12) = 106.67 micron - close enough. + + +9-Dec-14: + +Latest version is now Poisson_cpp4. This has the following improvements: +(1) Standalone C++ program driven from a config file that writes HDF5 output. Separate Python plot program. +(2) Took error calculation out of SOR to speed it up. Now a separate routine run once. +(3) Tried running Red/Black instead of SOR as per Numerical Recipes, but it is definitely faster with SOR. +(4) Split up Rho and Phi to prepare for calculating E and doing electron path calculations. +(5) Charges now validated and calculated from first principles. + +Things to do: + +(1) Think more about front side potentials. Is there a significant voltage drop across the oxide? What about when a charge is present? + +(2) Move more of the calculations to C++ - E-field calculations, electron path calculations. + +19-Jan-15 + +E-Field, pixel boundaries, and electron paths now in C++ code. Have also made it flexible enough to accomodate edges and such in the .cfg file. Current Status: + +(1) Poisson_cpp4 has the pixel boundaries as distorted by stored charge in the well. Both a uniform charge and a point charge are simulated. +(2) Poisson_cpp5 has the ability to log and plot the electron paths, which look reasonable. +(3) I'm adding the capability to add dipoles in Poisson_cpp6, so I can do comparisons. + +Python plotting summary: + +(1) Poisson.py - plots a summary of the simulation in cross-section, rho, E, ... +(2) Pixels.py - plot the pixel boundaries +(3) Pixels_Multiple.py - plots a comparison of pixel boundaries from different sims. +(4) Pixel_Paths.py - plots the electron paths. + +18-Feb-15 + +Latest version is now Poisson_cpp7. I've created a file (Poisson) which has the latest version suitable for posting, including two example .cfg files, an INSTALL file, a README file, and a docs folder. + +Poisson_CCD is a clean version for posting on github. + +Python plotting summary: + +(1) Poisson_Plots.py - Now builds all of the plots and reads the .cfg file to get the necessary info. + +7-Sep-15 + +Made quite a few improvements. Here is a summary: + +Poisson_CCD4 - Poisson_CCD6: Are a variety of changes, tests, and improvements, culminating in Poisson_CCD7. The changes include: + +(1) Added code to run Brighter-Fatter spots. TraceGrid is the old code for tracing a grid of starting electrons. TraceSpot traces a Gaussian spot with random electron starting locations. +(2) Added code to include electron diffusion. This includes several options, one to add a multiplier, and one to take a larger step to make it run faster. +(3) Added an option for periodic boundary conditions on the sides. +(4) Moved the vertical location of the CollectedCharge from being at one grid point above the top of the channel charge to being in the center of the channel charge. This reduced the slope of the B-F curves from ~ 2% to ~ 1%, in better agreement with the measurements. See Poisson_CCD7/run1 and run1A and Poisson_CCD7_BF and Poisson_CCD7A_BF. +(5) Sped things up by iterating much more for small values of z than large values of z. Base code now does the following: + (A) Iterates every cycle for z < zmax/8 + (B) Iterates every 4th cycle for z < zmax/4 + (C) Iterates every 16th cycle for z < zmax/2 + (D) Iterates every 64th cycle and at the end for all z's. + + Resulting speedup ~ 64T vs 64(T/8) + 16(T/4) + 4(T/2) + 2T ~ 4X + +17-Sep-15 + +Poisson_CCD8 is a clean version of Poisson_CCD7 for posting on github. + +Found the source of the "warping" in the edge plots. There was a one grid cell error in the periodic boundary conditions. + +Poisson_CCD9 - Verification of periodic BC fix. Lateral E-Field at z=75 < 1.0E-8 now. Fix has been propagated back into CCD7 and CCD8. CCD7 with fix has been run with 256 spots on NERSC Edison, and strange behavior with Sigma-X > Sigma-Y at low intesities is gone, even without the Zmax hack. + +Poisson_CCD10 - This is an attempt to re-write things with an even number of grid cells, which might run better in the long run. Not working yet. May have uncovered a problem with the charge normalization that needs to be looked into. No, this is OK. + +Poisson_CCD11 - This is an improvement on CCD10. It is working now, but shows no improvement over CCD7/8, and I'm not sure why. Need to come back to this. + +Poisson_CCD12, 12A, 13 - This is the latest clean code - it eliminates the Trace vs TracePaths, so I can keep these in sync. Poisson_CCD12A adds a variable Gate Oxide thickness, and Poisson_CCD13 does the most correct electron tracking, with mu being calculated at every point, and the electron iterating for 1000 steps after it reaches the bottom, in order to achieve some level of equilibrium. + +Poisson_CCD14 - This is in preparation for keeping the full location information of the electron as it reaches a well. Run1 places 10,000 electrons, and run2 50,000 electrons. They are concentrated at the pixel center. + +Poisson_CCD15 - This does the full loop, keeping the electron location information and re-calculating the field every NumElec electrons. + +Poisson_CCD15_Spot - Same as Poisson_CCD15, but replaces rejection sampling of the initial photon locations with the Box-Muller algorithm, which is faster because no random numbers are discarded. + +Poisson_CCD16 - Clean version of Poisson_CCD15 for posting on github. + +Poisson_CCD17 - Implementation of electron loss at interface. + +Poisson_CCD18 - CCD17 + several changes: + (1) Added code to calculate pixel areas as a polygon with 256 vertices. Slow, but accurate. + (2) Made 'PixelAreas' and 'SaveData' integer inputs to allow you to do these calculations of save the data every N steps. + +Poisson_CCD18A - Mod of CCD18 to force electrons into central spot. Not important + +Poisson_CCD18B - Clone of CCD18 to better calculate pixel areas and vertices. I've realized that this is key to implementing in PhoSim, so warrants more attention. New algorithm to find the corners, and then will add code with N points along the edges. + +Poisson_CCD19 - 18Dec15 - Better Pixel Areas - Binary search to find corners, and then NumVertices vertices per edge. + +Poisson_CCD20 - 2Feb16 - Added Gaussian profiles for Channel and ChannelStop. Added random grid of electrons for characterizing diffusion near pixel edges + - 10Feb16 - Tests with CCD20 show areas different from CCD18 and/or CCD19. What has caused the change? Need to back-track and make sure the area/vertex algorithm is correct. + - 12Feb16 - Problem was that I specified ElectronZ0 = 10.0 in order to keep all electrons in the central pixel when doing the area plots. This same value was used in the + vertex finding, which screwed up the area calculation. I split the ElectronZ0 into ElectronZ0Area and ElectronZ0Fill to allow these to be different. Fixed and re-running. +29-Feb-16 + +Poisson_CCD22 - Clean version of Poisson_CCD20 for posting on github. Six example files have been created and tested. + +1-Mar-16 + +Poisson_CCD23 - CCD22 + modification to allow adjustment of depth of channel implant + Also split up SaveData and SaveElec + +Poisson_CCD24 - CCD23 + forces z-location of collected electrons to Channelkmin + +Poisson_CCD25 - Playing with non-linear z-axis (zeta = sqrt(z)). + +29-Apr-16 + +Poisson_CCD_Stretch - Workhorse with non-linear z-axis working. Used for many runs. + +Poisson_CCD_Stretch_Test - Tried using TraceRegion instead of small TraceSpot to fill one pixel. Didn't really work. + +Poisson_CCD_Stretch_Test2 - Added an electron redistribution step. Didn't really work. + +Poisson_CCD_Stretch_Test3 - Added bottomsteps as a parameter to Trace. Good idea, but dropped to pursue Test4. + +Poisson_CCD_Stretch_Test4 - Workhorse. Instead of putting each e- in the average location of 1000 diffusion steps, placed 0.001 e- in each location. I think this is physically much more reasonable. + +Poisson_CCD_Stretch_Test5 - Experiment to shift Channel Stop deeper into silicon, adding a shift between Channelkmin and ChannelStopkmin. No real impact. + +Poisson_CCD_Stretch_Test6 - Going to work harder to get redistribution step working so I can put electrons in many pixels, then move them to equilibrium positions. After several trials, still not working. Giving up on this approach + +Poisson_CCD_Stretch_Test7 - Added a TraceMultipleSpots to add charge to many spots and simulate a flat. Reworked the Trace routines so a single Trace serves them all. To fill all of the spots, I changes the extent from (5,5)-(115,115) to (10,10)-(110,110). The even number of spots means one less level of grid reduction, so I reduced this parameter by 1 in the code. This means the number of grid cells only needs to be divisible by 16, not 32. This seems to have virtually no impact on speed or accuracy. In the final analysis, this made very little difference. + +Poisson_CCD_Stretch_Test8 - Preliminary version of adding free holes to the mobile charges. + +Poisson_CCD_Stretch_Test9 - First workhorse version of adding free holes to the mobile charges. This appears to be the key to getting everything to match. More work needed to find a faster and more physicaly accurate way of adding the free holes. Poisson_CCD_Stretch_BS10 gave reasonably good results. + +Ran a number of tests aimed at adding free holes to the simulation: + +Poisson_CCD_Stretch_Test11 - Test run to verify that I am correctly calculating the surface charge to bring phi(ChannelStopkmin) = Vchannelstop. Looks good - incorporated into Hole2. + +Poisson_CCD_Hole1 - Basically a version similar to Test9, but adding a separate hole array instead of putting the holes in the elec array. + +Poisson_CCD_Hole2 - Same as Hole1, but added a thicker FieldOxide. This didn't work out very well. Not currently pursuing it. + +Poisson_CCD_Hole3 - Added a boolean hole_clamp array to allow me to clamp the potential to <= Vchannelstop wherever hole_clamp = true. Poisson_CCD_Hole3_BF1 gave good correlation results. + +Poisson_CCD_Hole4 - Same as Hole3, but added an AdjustHoleClamp routine that tries to fix the discontinuities in the E-Field at the boundary of the hole_clamp region. + +Poisson_CCD_Hole5 - Extension of Hole1/2, eliminating the thicker field oxide, and using the insights in how to set the initial hole concentrations and adjust only the edges. + +Poisson_CCD_Hole6 - Extension of Hole5, with a better method of identifying the edges. This worked, and gave results very similar to Hole1/2, but was rapidly growing in complexity, so I am going back to the Hole1/2 scheme of adjusting the hole desnity everywhere in the CS region. + +Poisson_CCD_Hole7 - Back to the scheme of Hole 1/2, with some of the enhancements from Hole6. With 20 iterations before starting, this seems to work reasonably well. Launched Poisson_CCD_Hole7_BF1 (0.09 um GOX) and Poisson_CCD_Hole7_BF2 (0.14 um Gox). This code is now giving the best fits yet in terms of simultaneously fitting the spot size slopes (with two different values of VBB) and the correlation measurements. + +Poisson_CCD_Hole8 - Attempting to put the AdjustHoles routine deeper into the multi-grid flow, so it can be done at lower resolutions and propagated up. \ No newline at end of file diff --git a/pythonmpi.sl b/pythonmpi.sl deleted file mode 100644 index b1c9c8c..0000000 --- a/pythonmpi.sl +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -l -#SBATCH -p regular -#SBATCH -N 2 -#SBATCH -t 06:00:00 -#SBATCH -J my_job - -module load python -module load mpi4py -module load boost/1.55 -module load szip/2.1 -export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/syscom/nsg/lib:/global/homes/c/cslage/Software/hdf5-1.8.14/lib - -srun -n 64 python-mpi Run_BF_Multi.py \ No newline at end of file diff --git a/src/array3d.cpp b/src/array3d.cpp index 4b87a0e..f3b9b21 100755 --- a/src/array3d.cpp +++ b/src/array3d.cpp @@ -14,17 +14,28 @@ Array3D::Array3D(double Xmin, double Xmax, int Nx, double Ymin, double Ymax, int Ny, double Zmin, double Zmax, int Nz) { int i, j, k; + nkz = 10000; nx = Nx; ny = Ny; nz = Nz; xmin = Xmin; xmax = Xmax; ymin = Ymin; ymax = Ymax; zmin = Zmin; zmax = Zmax; dx = (xmax - xmin) / (double) nx; dy = (ymax - ymin) / (double) ny; - dz = (zmax - zmin) / (double) nz; - volume = dx * dy * dz; - x = new double[nx]; y = new double[ny]; z = new double[nz]; + dzp = (zmax - zmin) / (double) nz; + volume = dx * dy * dzp; + x = new double[nx]; y = new double[ny]; z = new double[nz], zp = new double[nz], zplus = new double[nz], zminus = new double[nz]; dzpdz = new double[nz]; kz = new int[nkz]; zpint = new double[nkz]; data = new double[nx * ny * nz]; for (k=0; k1e-12) + { + newroot = lastroot - (ZP(lastroot) - zp) / DZPDz(lastroot); + error = fabs((newroot - lastroot) / lastroot); + lastroot=newroot; + i=i+1; + if (i > 100) + { + printf("Iterations exceeded in Z(zprime). Quitting\n"); + return newroot; + } + } + return newroot; +} + +double Array3D::ZPlus(double z) +{ + return dx * dx / (dzp * dzp) * (pow(DZPDz(z), 2.0) + dzp / 2.0 * D2ZPDz2(z)); +} + +double Array3D::ZMinus(double z) +{ + return dx * dx / (dzp * dzp) * (pow(DZPDz(z), 2.0) - dzp / 2.0 * D2ZPDz2(z)); +} + + int Array3D::XIndex(double x) { return (int)((x - xmin) / dx); @@ -111,6 +184,6 @@ int Array3D::YIndex(double y) int Array3D::ZIndex(double z) { - return (int)((z - zmin) / dz); + return max(0,min(nz-1,(int)((ZP(z) - zmin) / dzp))); } diff --git a/src/array3d.h b/src/array3d.h index 3b5029f..e5e909e 100755 --- a/src/array3d.h +++ b/src/array3d.h @@ -19,8 +19,8 @@ class Array3D //This packages the 3D data sets { public: - int nx, ny, nz; - double xmin, xmax, ymin, ymax, zmin, zmax, dx, dy, dz, volume, *x, *y, *z, *data; + int nx, ny, nz, nkz, *kz; + double xmin, xmax, ymin, ymax, zmin, zmax, dx, dy, dzp, volume, *x, *y, *z, *zp, *zplus, *zminus, *dzpdz, *zpint, *data; Array3D() {}; Array3D(double, double, int, double, double, int, double, double, int); ~Array3D(); @@ -29,5 +29,11 @@ class Array3D //This packages the 3D data sets int XIndex(double); int YIndex(double); int ZIndex(double); - + double ZP(double); + double ZPInt(double); + double DZPDz(double); + double D2ZPDz2(double); + double Z(double); + double ZPlus(double); + double ZMinus(double); }; diff --git a/src/multigrid.cpp b/src/multigrid.cpp index 5938d4b..eaa55cc 100755 --- a/src/multigrid.cpp +++ b/src/multigrid.cpp @@ -27,20 +27,25 @@ MultiGrid::MultiGrid(string inname) //Constructor ReadConfigurationFile(inname); printf("Finished Reading config file\n"); // Then, we build the multigrid arrays and set the initial conditions - nsteps = 5 + (int)(log2(ScaleFactor)); + nsteps = 4 + (int)(log2(ScaleFactor)); // nsteps is the number of reduction steps in the VCycle. // This gives 4 grid cells in the z-direction at the coarsest scale phi = new Array3D*[nsteps+1]; rho = new Array3D*[nsteps+1]; - elec = new Array3D*[1]; + elec = new Array3D*[1]; + hole = new Array3D*[1]; BCType = new Array2D*[nsteps+1]; E = new Array3D*[3]; BuildArrays(phi, rho, elec, E, BCType); printf("Finished Building Arrays. \n"); + Channelkmin = phi[0]->ZIndex(GateOxide * EPSILON_SI / EPSILON_OX) + 1; + ChannelStopkmin = Channelkmin; + SetInitialVoltages(phi[0], BCType[0]); - SetFixedCharges(rho[0], BCType[0]); // Place fixed charges - SetMobileCharges(elec[0]); // This sets initial mobile charges + SetFixedCharges(rho[0], BCType[0]); // Place fixed charges + SetInitialHoles(rho[0], hole[0]); + SetInitialElectrons(rho[0], elec[0]); // This sets initial electrons time2 = time(NULL); setup_time = difftime(time2, time1); printf("Finished Setting ICs. Setup time = %.3f seconds\n",setup_time); @@ -48,47 +53,69 @@ MultiGrid::MultiGrid(string inname) //Constructor // Now we run NumSteps cycle, adding NumElec electrons each step and re-solving // Poisson's equation at each step. - int m; + int m, kmax; string StepNum; string underscore = "_"; for (m=0; m(m); - SetFixedCharges(rho[0], BCType[0]); // Place fixed charges - FillRho(rho[0], elec[0]); // Add mobile charges. - // Now we cycle through the VCycles to solve Poisson's equation - int n; - for (n=0; n= 0 && m % PixelAreas == 0) { - CalculatePixelAreas(E, m); + CalculatePixelAreas(m); } if (PixelBoundaryTestType == 0) { - TraceGrid(E, m); + TraceGrid(m); } if (PixelBoundaryTestType == 1) { - TraceSpot(elec[0], E, m); + TraceSpot(m); } if (PixelBoundaryTestType == 2) { - TraceRegion(E, m); + TraceRegion(m); + } + if (PixelBoundaryTestType == 3) + { + TraceMultipleSpots(m); } // Now, we write out the potential and charge density results @@ -96,10 +123,14 @@ MultiGrid::MultiGrid(string inname) //Constructor trace_time = difftime(time2, time1); printf("Finished tracing electrons. Trace time = %.3f seconds\n",trace_time); + if (SaveElec !=0 && m % SaveElec == 0) + { + WriteOutputFile(outputfiledir, outputfilebase+underscore+StepNum, "Elec", elec[0]); + WriteOutputFile(outputfiledir, outputfilebase+underscore+StepNum, "Hole", hole[0]); + } if (SaveData !=0 && m % SaveData == 0) { - WriteOutputFile(outputfiledir, outputfilebase+underscore+StepNum, "Elec", elec[0]); WriteOutputFile(outputfiledir, outputfilebase+underscore+StepNum, "phi", phi[0]); WriteOutputFile(outputfiledir, outputfilebase+underscore+StepNum, "rho", rho[0]); WriteOutputFile(outputfiledir, outputfilebase+underscore+StepNum, "Ex", E[0]); @@ -141,7 +172,8 @@ void MultiGrid::ReadConfigurationFile(string inname) // Overall setup - SaveData = GetIntParam(inname, "SaveData", 1); // 1 - Save all data, 0 - Save only Pts + SaveData = GetIntParam(inname, "SaveData", 1); // 0 - Save only Pts, N save phi,rho,E every Nth step + SaveElec = GetIntParam(inname, "SaveElec", 1); // 0 - Save only Pts, N save Elec every Nth step ScaleFactor = GetIntParam(inname, "ScaleFactor", 1); // Power of 2 that sets the grid size // ScaleFactor = 1 means grid size is 5/6 micron, 128 grids in the z-direction PixelSize = GetDoubleParam(inname, "PixelSize", 10.0); // Pixel size in microns @@ -155,7 +187,7 @@ void MultiGrid::ReadConfigurationFile(string inname) Ny = Ny * ScaleFactor; Nz = 160; // Number of grids in z at ScaleFactor = 1 Nz = Nz * ScaleFactor; - Nzelec = 16; // Number of grids in z in electron array at ScaleFactor = 1 + Nzelec = 32; // Number of grids in z in electron array at ScaleFactor = 1 Nzelec = Nzelec * ScaleFactor; XBCType = GetIntParam(inname, "XBCType", 1); // 0 - Free BC, 1 - Periodic BC YBCType = GetIntParam(inname, "YBCType", 1); // 0 - Free BC, 1 - Periodic BC @@ -170,8 +202,7 @@ void MultiGrid::ReadConfigurationFile(string inname) Vaverage = (8.0 * Vparallel_lo + 4.0 * Vparallel_hi) / 12.0; Vchannelstop = GetDoubleParam(inname, "Vchannelstop", 0.0); Vscupper = GetDoubleParam(inname, "Vscupper", 5.0); - GateOxide = GetDoubleParam(inname, "GateOxide", 0.15); - Channelkmin = (int)rint(GateOxide * EPSILON_SI / EPSILON_OX / (PixelSize / (double)GridsPerPixel)); + GateOxide = GetDoubleParam(inname, "GateOxide", 0.15); BackgroundDoping = GetDoubleParam(inname, "BackgroundDoping", -1.0E12); ChannelStopDoping = GetDoubleParam(inname, "ChannelStopDoping", -1.0E12); ChannelStopDepth = GetDoubleParam(inname, "ChannelStopDepth", 1.0); @@ -328,17 +359,17 @@ void MultiGrid::BuildArrays(Array3D** phi, Array3D** rho, Array3D** elec, Array3 nzz = Nz + 1; dx = PixelSize / (double)GridsPerPixel; dy = dx; - dz = dx; Xmin = SimulationRegionLowerLeft[0]; Ymin = SimulationRegionLowerLeft[1]; Zmin = 0.0; Xmax = dx * (double)nxx + Xmin; Ymax = dy * (double)nyy + Ymin; - Zmax = dz * (double)nzz + Zmin; - zmaxelec = dz * (double)Nzelec + Zmin; + Zmax = 100.0; phi[0] = new Array3D(Xmin,Xmax,nxx,Ymin,Ymax,nyy,Zmin,Zmax,nzz); rho[0] = new Array3D(Xmin,Xmax,nxx,Ymin,Ymax,nyy,Zmin,Zmax,nzz); - elec[0] = new Array3D(Xmin,Xmax,nxx,Ymin,Ymax,nyy,Zmin,zmaxelec,Nzelec); + zmaxelec = rho[0]->Z(rho[0]->zp[Nzelec] + rho[0]->dzp / 2.0); + elec[0] = new Array3D(Xmin,Xmax,nxx,Ymin,Ymax,nyy,Zmin,zmaxelec,Nzelec); + hole[0] = new Array3D(Xmin,Xmax,nxx,Ymin,Ymax,nyy,Zmin,zmaxelec,Nzelec); BCType[0] = new Array2D(Xmin,Xmax,nxx,Ymin,Ymax,nyy); for (n=1; nnz - 1) / (int)pow(2,n) + 1; dx = phi[0]->dx * (int)pow(2,n); dy = phi[0]->dy * (int)pow(2,n); - dz = phi[0]->dz * (int)pow(2,n); + dz = phi[0]->dzp * (int)pow(2,n); xmin = phi[0]->xmin + phi[0]->dx / 2.0 - dx / 2.0; ymin = phi[0]->ymin + phi[0]->dy / 2.0 - dy / 2.0; - zmin = phi[0]->zmin + phi[0]->dz / 2.0 - dz / 2.0; + zmin = phi[0]->zmin + phi[0]->dzp / 2.0 - dz / 2.0; xmax = phi[0]->xmax - phi[0]->dx / 2.0 + dx / 2.0; ymax = phi[0]->ymax - phi[0]->dy / 2.0 + dy / 2.0; - zmax = phi[0]->zmax - phi[0]->dz / 2.0 + dz / 2.0; + zmax = phi[0]->zmax - phi[0]->dzp / 2.0 + dz / 2.0; phi[n] = new Array3D(xmin,xmax,nx,ymin,ymax,ny,zmin,zmax,nz); rho[n] = new Array3D(xmin,xmax,nx,ymin,ymax,ny,zmin,zmax,nz); BCType[n] = new Array2D(xmin,xmax,nx,ymin,ymax,ny); @@ -467,154 +498,195 @@ void MultiGrid::SetInitialVoltages(Array3D* phi, Array2D* BCType) void MultiGrid::SetFixedCharges(Array3D* rho, Array2D* BCType) { int i, j, k, n, index, index2; - int ChannelStopkmax=0, FixedRegionkmax; - int ChannelStopkmin, FixedRegionkmin; - ChannelStopkmin = Channelkmin; - FixedRegionkmin = Channelkmin; + int FixedRegionkmin, FixedRegionkmax; + FixedRegionkmin = ChannelStopkmin; if (ChannelProfile == 0) // Square well { - Channelkmax = Channelkmin - 1 + (int)(ChannelDepth / (PixelSize / (double)GridsPerPixel)); + Channelkmax = rho->ZIndex(rho->Z(rho->zp[Channelkmin]) + ChannelDepth); } if (ChannelProfile == 1) // Gaussian { - Channelkmax = Channelkmin - 1 + (int)(4.0 * ChannelDepth / (PixelSize / (double)GridsPerPixel)); + Channelkmax = rho->ZIndex(rho->Z(rho->zp[Channelkmin]) + 4.0 * ChannelDepth); } if (ChannelStopProfile == 0) // Square well { - ChannelStopkmax = ChannelStopkmin - 1 + (int)(ChannelStopDepth / (PixelSize / (double)GridsPerPixel)); + ChannelStopkmax = rho->ZIndex(rho->Z(rho->zp[ChannelStopkmin]) + ChannelStopDepth); } if (ChannelStopProfile == 1) // Gaussian { - ChannelStopkmax = ChannelStopkmin - 1 + (int)(4.0 * ChannelStopDepth / (PixelSize / (double)GridsPerPixel)); + ChannelStopkmax = rho->ZIndex(rho->Z(rho->zp[ChannelStopkmin]) + 2.0 * ChannelStopDepth); } int PixX, PixY; - double PixXmin, PixYmin; + double PixXmin, PixYmin, FRChargeDepth, CChargeDepth; double ChargeFactor = (QE*MICRON_PER_M/(EPSILON_0*EPSILON_SI)) / pow(MICRON_PER_CM, 3); // ChargeFactor converts doping in cm^-3 into the appropriate units - double ChannelStopCharge, ChannelCharge, FixedRegionCharge; + double ChannelCharge, FixedRegionCharge; ChannelStopCharge = ChannelStopDoping * MICRON_PER_CM * ChargeFactor; ChannelCharge = ChannelDoping * MICRON_PER_CM * ChargeFactor; + CSChargeDepth = rho->Z(rho->zp[ChannelStopkmax] + rho->dzp / 2.0) - rho->Z(rho->zp[ChannelStopkmin] - rho->dzp / 2.0); + CChargeDepth = rho->Z(rho->zp[Channelkmax] + rho->dzp / 2.0) - rho->Z(rho->zp[Channelkmin] - rho->dzp / 2.0); + printf("CChargeDepth = %.4f\n",CChargeDepth); + double ChannelZmin, ChannelZmax, ChannelStopZmin, ChannelStopZmax, ChannelTotal, ChannelStopTotal, DeltaZ; + ChannelZmin = rho->Z(rho->zp[Channelkmin] - rho->dzp / 2.0); + ChannelZmax = rho->Z(rho->zp[Channelkmax] + rho->dzp / 2.0); + ChannelTotal = erf((ChannelZmax - ChannelZmin) / (sqrt(2.0) * ChannelDepth)); + ChannelStopZmin = rho->Z(rho->zp[ChannelStopkmin] - rho->dzp / 2.0); + ChannelStopZmax = rho->Z(rho->zp[ChannelStopkmax] + rho->dzp / 2.0); + ChannelStopTotal = erf((ChannelStopZmax - ChannelStopZmin) / (sqrt(2.0) * ChannelStopDepth)); // Set the background charge: - printf("In SetFixedCharges, BackgroundCharge = %.4f \n",BackgroundDoping*ChargeFactor); + double Gox_effective = rho->Z(rho->zp[Channelkmin] - rho->dzp / 2.0) * EPSILON_OX / EPSILON_SI; + printf("In SetFixedCharges, BackgroundCharge = %.4f Effective Gate Oxide thickness = %.3f microns.\n",BackgroundDoping*ChargeFactor, Gox_effective); printf("In SetFixedCharges, Channelkmin = %d, Channelkmax = %d, ChannelZWidth = %d grid cells, ChannelCharge = %.4f \n",Channelkmin, Channelkmax, (Channelkmax - Channelkmin + 1), ChannelCharge); printf("In SetFixedCharges, ChannelStopkmin = %d, ChannelStopkmax = %d, ChannelStopZWidth = %d grid cells, ChannelStopCharge = %.4f \n",ChannelStopkmin, ChannelStopkmax, (ChannelStopkmax - ChannelStopkmin + 1), ChannelStopCharge); for (i=0; inx; i++) { for (j=0; jny; j++) - { - for (k=Channelkmin; knz-1; k++) - { - index = i + j * rho->nx + k * rho->nx * rho->ny; - rho->data[index] = BackgroundDoping * ChargeFactor; - } - } + { + for (k=Channelkmin; knz-1; k++) + { + index = i + j * rho->nx + k * rho->nx * rho->ny; + rho->data[index] = BackgroundDoping * ChargeFactor; + } + } } - + // Fixed Potentials or free Boundary Conditions on bottom for (n=0; nZIndex(rho->Z(rho->zp[Channelkmin]) + ChannelDepth); + FixedRegionkmax = rho->ZIndex(rho->Z(rho->zp[FixedRegionkmin]) + FixedRegionChargeDepth[n]); + FRChargeDepth = rho->Z(rho->zp[FixedRegionkmax] + rho->dzp / 2.0) - rho->Z(rho->zp[FixedRegionkmin] - rho->dzp / 2.0); + FixedRegionCharge = FixedRegionDoping[i] * MICRON_PER_CM / FRChargeDepth * ChargeFactor; for (i=0; inx; i++) - { - for (j=0; jny; j++) - { - index = i + j * rho->nx; - if (rho->x[i] >= FixedRegionLowerLeft[n][0] && rho->x[i] <= FixedRegionUpperRight[n][0] && rho->y[j] >= FixedRegionLowerLeft[n][1] && rho->y[j] <= FixedRegionUpperRight[n][1]) { - if (FixedRegionBCType[n] == 0) // Fixed potential region - { - for (k=FixedRegionkmin; kny; j++) { - index2 = index + k * rho->nx * rho->ny; - rho->data[index2] = FixedRegionCharge; + index = i + j * rho->nx; + if (rho->x[i] >= FixedRegionLowerLeft[n][0] && rho->x[i] <= FixedRegionUpperRight[n][0] && rho->y[j] >= FixedRegionLowerLeft[n][1] && rho->y[j] <= FixedRegionUpperRight[n][1]) + { + if (FixedRegionBCType[n] == 0) // Fixed potential region + { + for (k=FixedRegionkmin; knx * rho->ny; + rho->data[index2] = FixedRegionCharge; + } + } + else // Free Boundary Condition region + { + BCType->data[index] = 1; + } + } } - } - else // Free Boundary Condition region - { - BCType->data[index] = 1; - } } - } - } } + + // Charges in Pixel Region + + //int nx2 = rho->nx / 2; Debugging + //int ny2 = rho->ny / 2; + //double TotalChannelCharge = 0.0; - // Charges in Pixel Region for (n=0; nnx; i++) - { - if (rho->x[i] < PixelRegionLowerLeft[n][0] || rho->x[i] > PixelRegionUpperRight[n][0]) - { - continue; // If not in PixelRegion, continue - } - for (j=0; jny; j++) - { - if (rho->y[j] < PixelRegionLowerLeft[n][1] || rho->y[j] > PixelRegionUpperRight[n][1]) - { - continue; // If not in PixelRegion, continue - } - index = i + j * rho->nx; - PixX = (int)((rho->x[i] - PixelRegionLowerLeft[n][0]) / PixelSize); - PixY = (int)((rho->y[j] - PixelRegionLowerLeft[n][1]) / PixelSize); - PixXmin = PixelRegionLowerLeft[n][0] + (double)PixX * PixelSize; - PixYmin = PixelRegionLowerLeft[n][1] + (double)PixY * PixelSize; - // Now set the charges - if (rho->x[i] <= PixXmin + ChannelStopWidth/2.0 || rho->x[i] >= PixXmin + PixelSize - ChannelStopWidth/2.0) - { - // This is the Channel Stop Region - for (k=ChannelStopkmin; knx * rho->ny; - if (ChannelStopProfile == 0) // Square Well - { - rho->data[index2] = ChannelStopCharge / (((double)ChannelStopkmax - (double)ChannelStopkmin + 1.0) * GridSpacing); - } - if (ChannelStopProfile == 1) // Gaussian - { - rho->data[index2] = ChannelStopCharge / GridSpacing * (erf((rho->z[k]+rho->dz/2.0) / (sqrt(2.0) * ChannelStopDepth)) - erf((rho->z[k]-rho->dz/2.0) / (sqrt(2.0) * ChannelStopDepth))); - } - } - } - else { - // This is the channel region - for (k=Channelkmin; knx * rho->ny; - if (ChannelProfile == 0) // Square Well + if (rho->x[i] < PixelRegionLowerLeft[n][0] || rho->x[i] > PixelRegionUpperRight[n][0]) { - rho->data[index2] = ChannelCharge / (((double)Channelkmax - (double)Channelkmin + 1.0) * GridSpacing); + continue; // If not in PixelRegion, continue } - if (ChannelProfile == 1) // Gaussian + for (j=0; jny; j++) { - rho->data[index2] = ChannelCharge / GridSpacing * (erf((rho->z[k]+rho->dz/2.0) / (sqrt(2.0) * ChannelDepth)) - erf((rho->z[k]-rho->dz/2.0) / (sqrt(2.0) * ChannelDepth))); + if (rho->y[j] < PixelRegionLowerLeft[n][1] || rho->y[j] > PixelRegionUpperRight[n][1]) + { + continue; // If not in PixelRegion, continue + } + index = i + j * rho->nx; + PixX = (int)((rho->x[i] - PixelRegionLowerLeft[n][0]) / PixelSize); + PixY = (int)((rho->y[j] - PixelRegionLowerLeft[n][1]) / PixelSize); + PixXmin = PixelRegionLowerLeft[n][0] + (double)PixX * PixelSize; + PixYmin = PixelRegionLowerLeft[n][1] + (double)PixY * PixelSize; + // Now set the charges + if (rho->x[i] <= PixXmin + ChannelStopWidth/2.0 || rho->x[i] >= PixXmin + PixelSize - ChannelStopWidth/2.0) + { + // This is the Channel Stop Region + for (k=Channelkmin; knx * rho->ny; + rho->data[index2] = 0.0; + } + for (k=ChannelStopkmin; kZ(rho->zp[k] + rho->dzp / 2.0) - rho->Z(rho->zp[k] - rho->dzp / 2.0); + index2 = index + k * rho->nx * rho->ny; + if (ChannelStopProfile == 0) // Square Well + { + rho->data[index2] = ChannelStopCharge / CSChargeDepth; + } + if (ChannelStopProfile == 1) // Gaussian + { + rho->data[index2] = ChannelStopCharge / ChannelStopTotal / DeltaZ * (erf((rho->Z(rho->zp[k]+rho->dzp/2.0) - ChannelStopZmin) / (sqrt(2.0) * ChannelStopDepth)) - erf((rho->Z(rho->zp[k]-rho->dzp/2.0) - ChannelStopZmin) / (sqrt(2.0) * ChannelStopDepth))); + } + } + } + else + { + // This is the channel region + for (k=Channelkmin; kZ(rho->zp[k] + rho->dzp / 2.0) - rho->Z(rho->zp[k] - rho->dzp / 2.0); + index2 = index + k * rho->nx * rho->ny; + if (ChannelProfile == 0) // Square Well + { + rho->data[index2] = ChannelCharge / CChargeDepth; + } + if (ChannelProfile == 1) // Gaussian + { + rho->data[index2] = ChannelCharge / ChannelTotal / DeltaZ * (erf((rho->Z(rho->zp[k]+rho->dzp/2.0) - ChannelZmin) / (sqrt(2.0) * ChannelDepth)) - erf((rho->Z(rho->zp[k]-rho->dzp/2.0) - ChannelZmin) / (sqrt(2.0) * ChannelDepth))); + } + /* + if (i == nx2 && j == ny2) + { + //printf("DeltaZ = %.4f\n",DeltaZ); + TotalChannelCharge+=rho->data[index2] * DeltaZ; + }Debug purposes */ + } + } } - } } - } - } } printf("Finished setting Fixed Charges, \n"); + //printf("TotalChannelCharge = %.6g\n", TotalChannelCharge); fflush(stdout); return; } -void MultiGrid::SetMobileCharges(Array3D* elec) +void MultiGrid::SetInitialElectrons(Array3D* rho, Array3D* elec) { int i, j, k, n, q, index, index2; int CollectedChargeimin, CollectedChargeimax, CollectedChargeXWidth; + CollectedChargeimin = rho->XIndex(CollectedChargeXmin); + CollectedChargeimax = rho->XIndex(CollectedChargeXmax); + CollectedChargeXWidth = CollectedChargeimax - CollectedChargeimin + 1; + int CollectedChargejmin, CollectedChargejmax, CollectedChargeYWidth; + CollectedChargejmin = rho->YIndex(CollectedChargeYmin); + CollectedChargejmax = rho->YIndex(CollectedChargeYmax); + CollectedChargeYWidth = CollectedChargejmax - CollectedChargejmin + 1; + + CollectedChargeimin = (int)(CollectedChargeXmin / GridSpacing); CollectedChargeimax = (int)(CollectedChargeXmax / GridSpacing); CollectedChargeXWidth = CollectedChargeimax - CollectedChargeimin + 1; - int CollectedChargejmin, CollectedChargejmax, CollectedChargeYWidth; CollectedChargejmin = (int)(CollectedChargeYmin / GridSpacing); CollectedChargejmax = (int)(CollectedChargeYmax / GridSpacing); CollectedChargeYWidth = CollectedChargejmax - CollectedChargejmin + 1; + + + int CollectedChargekmin, CollectedChargekmax, CollectedChargeZWidth; - CollectedChargekmin = (int)(CollectedChargeZmin / GridSpacing); - CollectedChargekmax = (int)(CollectedChargeZmax / GridSpacing); + CollectedChargekmin = rho->ZIndex(CollectedChargeZmin); + CollectedChargekmax = rho->ZIndex(CollectedChargeZmax); CollectedChargeZWidth = CollectedChargekmax - CollectedChargekmin + 1; int PixX, PixY, FilledPixX, FilledPixY, Pixi, Pixj; double PixXmin, PixYmin, CollectCharge=0.0; @@ -668,22 +740,249 @@ void MultiGrid::SetMobileCharges(Array3D* elec) } } } - printf ("In SetMobileCharges, CollectCharge = %.3f\n", CollectCharge); - printf("Finished setting Mobile Charges, %.1f total electrons placed.\n", TotalElectrons); + printf ("In SetInitialElectrons, CollectCharge = %.3f\n", CollectCharge); + printf("Finished setting Initial Electrons, %.1f total electrons placed.\n", TotalElectrons); + fflush(stdout); + return; +} + +void MultiGrid::SetInitialHoles(Array3D* rho, Array3D* hole) +{ + // This sets an initial guess at the free hole density by setting it to the + // expected solution based on the 1D solution. + // It is then adjusted by the routine AdjustHoles + int i, j, k, n, index, index2; + int PixX, PixY; + double PixXmin, PixYmin, AddedHoles, TotalAddedHoles = 0.0; + double ChargeDepth, ZL, Vdelta, Slope1, Slope2, SlopeDelta; + double RhoChargeFactor = (QE*MICRON_PER_M / (EPSILON_0*EPSILON_SI)) / (GridSpacing * GridSpacing); + ZL = rho->zmax - rho->Z(rho->zp[ChannelStopkmax] - rho->dzp / 2.0); + Vdelta = BackgroundDoping / pow(MICRON_PER_CM, 3) * RhoChargeFactor * ZL * ZL * GridSpacing * GridSpacing; + printf("In SetInitialHoles\n"); + + for (n=0; nnx; i++) + { + if (rho->x[i] < PixelRegionLowerLeft[n][0] || rho->x[i] > PixelRegionUpperRight[n][0]) + { + continue; // If not in PixelRegion, continue + } + for (j=0; jny; j++) + { + if (rho->y[j] < PixelRegionLowerLeft[n][1] || rho->y[j] > PixelRegionUpperRight[n][1]) + { + continue; // If not in PixelRegion, continue + } + index = i + j * rho->nx; + PixX = (int)((rho->x[i] - PixelRegionLowerLeft[n][0]) / PixelSize); + PixY = (int)((rho->y[j] - PixelRegionLowerLeft[n][1]) / PixelSize); + PixXmin = PixelRegionLowerLeft[n][0] + (double)PixX * PixelSize; + PixYmin = PixelRegionLowerLeft[n][1] + (double)PixY * PixelSize; + // Now set the charges + if (rho->x[i] <= PixXmin + ChannelStopWidth/2.0 || rho->x[i] >= PixXmin + PixelSize - ChannelStopWidth/2.0) + { + // This is the channel stop region + if (((rho->y[j] >= PixYmin + PixelSize/6.0 && rho->y[j] <= PixYmin + 5.0*PixelSize/6.0) && CollectingPhases == 2) || ((rho->y[j] >= PixYmin + PixelSize/3.0 && rho->y[j] <= PixYmin + 2.0*PixelSize/3.0) && CollectingPhases == 1)) + { + // This is the Channel Stop Region under the collecting gates + Slope1 = (Vchannelstop - Vparallel_hi) / (rho->z[ChannelStopkmin] - rho->z[0]); + } + else + { + // This is the Channel Stop Region under the barrier gates + Slope1 = (Vchannelstop - Vparallel_lo) / (rho->z[ChannelStopkmin] - rho->z[0]); + } + for (k=ChannelStopkmin; knx * rho->ny; + ChargeDepth = rho->Z(rho->zp[k] + rho->dzp / 2.0) - rho->Z(rho->zp[k] - rho->dzp / 2.0); + SlopeDelta = rho->data[index2] * ChargeDepth * 2.0; // 2.0 Fudge factor not understood. + if (k == ChannelStopkmax) + { + Slope1 = 0.0; + Slope2 = (Vbb - Vdelta) / ZL; + AddedHoles = (Slope1 - Slope2) / RhoChargeFactor; + AddedHoles += -rho->data[index2] * ChargeDepth / RhoChargeFactor; // Add in charge to compensate fixed charge + AddedHoles = max(AddedHoles, -hole->data[index2]); + hole->data[index2] = AddedHoles; + TotalAddedHoles += AddedHoles; + } + else if ((Slope1 - SlopeDelta) < 0.0) + { + // Not enough fixed charge yet + Slope1 = Slope1 - SlopeDelta; + hole->data[index2] = 0.0; + } + else + { + // Now have enough fixed charge + Slope2 = 0.0; + AddedHoles = (Slope1 - Slope2) / RhoChargeFactor; + AddedHoles += -rho->data[index2] * ChargeDepth / RhoChargeFactor; // Add in charge to compensate fixed charge + AddedHoles = max(AddedHoles, -hole->data[index2]); + hole->data[index2] = AddedHoles; + TotalAddedHoles += AddedHoles; + Slope1 = 0.0; + } + } // ends k + } // ends channel stop region + else + { + // This is the channel region + continue; + } + } // ends j + } // ends i + } // ends n + double TotHoles = 0.0; + for (i=0; inx; i++) + { + for (j=0; jny; j++) + { + for (k=0; knz; k++) + { + index = i + j * rho->nx + k * rho->nx * rho->ny; + TotHoles += hole->data[index]; + } + } + } + printf("Finished setting Initial holes, %.6g total holes placed.\n", TotalAddedHoles); fflush(stdout); return; + } +void MultiGrid::AdjustHoles(Array3D* phi, Array3D* rho, Array3D* hole) +{ + // This routine adjusts the free hole density to "pin" the potential in + // the channel stop region to be equal to Vchannelstop. + // It needs to be run iteratively to converge to a solution. + int i, j, k, n, index, index2; + int PixX, PixY; + double PixXmin, PixYmin, AddedHoles, MinusHoles, PartialHoles, TotalAddedHoles = 0.0, ChargeIncrement; + //ChargeIncrement = -5.0 * ChannelStopCharge / CSChargeDepth / (double)(pow(ScaleFactor, 3.0)); + ChargeIncrement = 20.0 / (double)(pow(ScaleFactor, 3.0)); + printf("ChargeIncrement = %f\n",ChargeIncrement); + // This sets how rapidly we converge to a solution. + double MaxIncrement = 10000.0; + double TotHoles = 0.0; + for (i=0; inx; i++) + { + for (j=0; jny; j++) + { + for (k=0; knz; k++) + { + index = i + j * rho->nx + k * rho->nx * rho->ny; + TotHoles += hole->data[index]; + } + } + } + printf("Starting adjusting Mobile holes, %.6g total holes.\n", TotHoles); + + for (n=0; nnx; i++) + { + if (rho->x[i] < PixelRegionLowerLeft[n][0] || rho->x[i] > PixelRegionUpperRight[n][0]) + { + continue; // If not in PixelRegion, continue + } + for (j=0; jny; j++) + { + if (rho->y[j] < PixelRegionLowerLeft[n][1] || rho->y[j] > PixelRegionUpperRight[n][1]) + { + continue; // If not in PixelRegion, continue + } + index = i + j * rho->nx; + PixX = (int)((rho->x[i] - PixelRegionLowerLeft[n][0]) / PixelSize); + PixY = (int)((rho->y[j] - PixelRegionLowerLeft[n][1]) / PixelSize); + PixXmin = PixelRegionLowerLeft[n][0] + (double)PixX * PixelSize; + PixYmin = PixelRegionLowerLeft[n][1] + (double)PixY * PixelSize; + // Now set the charges + if (rho->x[i] <= PixXmin + ChannelStopWidth/2.0 || rho->x[i] >= PixXmin + PixelSize - ChannelStopWidth/2.0) + { + // This is the Channel Stop Region + for (k=ChannelStopkmin; k < ChannelStopkmax+1; k++) + { + index2 = index + k * rho->nx * rho->ny; + if (phi->data[index2] < Vchannelstop) + { + // Region needs more free holes + if ((Vchannelstop - phi->data[index2]) > 0.5) + { + AddedHoles = ChargeIncrement * (Vchannelstop - phi->data[index2]); + } + else + { + AddedHoles = 2.0 * ChargeIncrement * (Vchannelstop - phi->data[index2]); + } + AddedHoles = min(MaxIncrement, AddedHoles); + hole->data[index2] += AddedHoles; + TotalAddedHoles += AddedHoles; + } + else + { + //phi->data[index2] > Vchannelstop + // Region has too many free holes + if ((phi->data[index2] - Vchannelstop) > 0.5) + { + MinusHoles = ChargeIncrement * (phi->data[index2] - Vchannelstop); } + else + { + MinusHoles = 2.0 * ChargeIncrement * (phi->data[index2] - Vchannelstop); } + MinusHoles = min(MaxIncrement, MinusHoles); + if (MinusHoles < hole->data[index2]) + { + // We're less than the hole value, so just subtract it. + hole->data[index2] -= MinusHoles; + TotalAddedHoles -= MinusHoles; + } + else + { + // We're over the value to bring this to zero, so bring this cell to zero + PartialHoles = hole->data[index2]; + hole->data[index2] -= PartialHoles; + TotalAddedHoles -= PartialHoles; + } + }// ends else + }// ends k + }// ends channel stop region + else + { + // This is the channel region + continue; + } + } + } + } + TotHoles = 0.0; + for (i=0; inx; i++) + { + for (j=0; jny; j++) + { + for (k=0; knz; k++) + { + index = i + j * rho->nx + k * rho->nx * rho->ny; + TotHoles += hole->data[index]; + } + } + } + printf("Finished adjusting Mobile Holes, %.6g added holes, %.6g total holes.\n", TotalAddedHoles, TotHoles); + fflush(stdout); + return; +} void MultiGrid::SOR(Array3D* phi, Array3D* rho, Array2D* BCType, double w) { // Assumes fixed potentials on the top, mixture of fixed and free BC on bottom, free or periodic BC on the sides. double newphi; double omw, w6, hsquared; + w6 = w / 6.0; int i, j, k, im, ip, j0, jm, jp, nxy, ind, indmx, indpx, indmy, indpy, indmz, indpz; nxy = phi->nx * phi->ny; hsquared = phi->dx * phi->dy; - omw = 1.0 - w; w6 = w / 6.0; + omw = 1.0 - w; for (i=0; inx; i++) { if (XBCType == 0) @@ -723,6 +1022,7 @@ void MultiGrid::SOR(Array3D* phi, Array3D* rho, Array2D* BCType, double w) } for (k=1; knz-1; k++) { + w6 = w / (4.0 + phi->zplus[k] + phi->zminus[k]); ind = i + j0 + k * nxy; indmx = ind - im; indpx = ind + ip; @@ -730,7 +1030,7 @@ void MultiGrid::SOR(Array3D* phi, Array3D* rho, Array2D* BCType, double w) indpy = ind + jp; indmz = ind - nxy; indpz = ind + nxy; - newphi = omw * phi->data[ind] + w6 * (phi->data[indmx]+phi->data[indpx]+phi->data[indmy]+phi->data[indpy]+phi->data[indmz]+phi->data[indpz] + hsquared * rho->data[ind]); + newphi = omw * phi->data[ind] + w6 * (phi->data[indmx]+phi->data[indpx]+phi->data[indmy]+phi->data[indpy]+phi->zminus[k]*phi->data[indmz]+phi->zplus[k]*phi->data[indpz] + hsquared * rho->data[ind]); phi->data[ind] = newphi; } } @@ -738,85 +1038,6 @@ void MultiGrid::SOR(Array3D* phi, Array3D* rho, Array2D* BCType, double w) return; } -void MultiGrid::SOR_N(Array3D* phi, Array3D* rho, Array2D* BCType, double w, int ncycles) -{ - // Assumes fixed potentials on the top, mixture of fixed and free BC on bottom, free or periodic BC on the sides. - // Does ncycles cycles of SOR, concentrated near the bottom - double newphi; - double omw, w6, hsquared; - int n, i, j, k, im, ip, j0, jm, jp, nxy, ind, indmx, indpx, indmy, indpy, indmz, indpz; - int kmax, kmax1, kmax2, kmax3; - nxy = phi->nx * phi->ny; - hsquared = phi->dx * phi->dy; - omw = 1.0 - w; w6 = w / 6.0; - if (phi->nz - 1 < 128) - { - kmax1 = phi->nz - 1; kmax2 = kmax1; kmax3 = kmax1; - } - else - { - kmax1 = (phi->nz - 1) / 2; kmax2 = kmax1 / 2; kmax3 = kmax2 / 2; - } - for (n=0; nnz - 1; } - else if (n%16 == 0){ kmax = kmax1; } - else if (n%4 == 0){ kmax = kmax2; } - else { kmax = kmax3; } - for (i=0; inx; i++) - { - if (XBCType == 0) - { - if (i == 0) {im = 0;} else {im = 1;} // Free BC - if (i == phi->nx-1) {ip = 0;} else {ip = 1;} // Free BC - } - else - { - if (i == 0) {im = -phi->nx + 2;} else {im = 1;} // Periodic BC - if (i == phi->nx-1) {ip = -phi->nx + 2;} else {ip = 1;} // Periodic BC - } - for (j=0; jny; j++) - { - j0 = j * phi->nx; - if (YBCType == 0) - { - if (j == 0) {jm = 0;} else {jm = phi->nx;} // Free BC - if (j == phi->ny-1) {jp = 0;} else {jp = phi->nx;} // Free BC - } - else - { - if (j == 0) {jm = (-phi->ny + 2) * phi->nx;} else {jm = phi->nx;} // Periodic BC - if (j == phi->ny-1) {jp = (-phi->ny + 2) * phi->nx;} else {jp = phi->nx;} // Periodic BC - } - ind = i + j0; - if (BCType->data[ind] == 1) // Free BC at z = 0 - { - indmx = ind - im; - indpx = ind + ip; - indmy = ind - jm; - indpy = ind + jp; - indmz = ind; - indpz = ind + nxy; - newphi = omw * phi->data[ind] + w6 * (phi->data[indmx]+phi->data[indpx]+phi->data[indmy]+phi->data[indpy]+phi->data[indmz]+phi->data[indpz] + hsquared * rho->data[ind]); - phi->data[ind] = newphi; - } - for (k=1; kdata[ind] + w6 * (phi->data[indmx]+phi->data[indpx]+phi->data[indmy]+phi->data[indpy]+phi->data[indmz]+phi->data[indpz] + hsquared * rho->data[ind]); - phi->data[ind] = newphi; - } - } - } - } - return; -} double MultiGrid::Error(Array3D* phi, Array3D* rho) { @@ -838,7 +1059,7 @@ double MultiGrid::Error(Array3D* phi, Array3D* rho) indpy = ind + phi->nx; indmz = ind - nxy; indpz = ind + nxy; - newphi = (phi->data[indmx]+phi->data[indpx]+phi->data[indmy]+phi->data[indpy]+phi->data[indmz]+phi->data[indpz] + hsquared * rho->data[ind]) / 6.0; + newphi = (phi->data[indmx]+phi->data[indpx]+phi->data[indmy]+phi->data[indpy]+phi->zminus[k]*phi->data[indmz]+phi->zplus[k]*phi->data[indpz] + hsquared * rho->data[ind]) / (4.0+phi->zplus[k]+phi->zminus[k]); error = max(error, fabs(phi->data[ind] - newphi)); } } @@ -1026,7 +1247,10 @@ void MultiGrid::VCycle(Array3D** phi, Array3D** rho, Array2D** BCType, double w, { Prolongate(phi[i], phi[i-1], BCType[i-1]); niter = ncycle * (int)pow(2,i-1); - SOR_N(phi[i-1], rho[i-1], BCType[i-1], w, niter); + for (j=0; jnx-1,phi[i-1]->ny-1,phi[i-1]->nz-1,niter,error); fflush(stdout); @@ -1125,35 +1349,36 @@ void MultiGrid::Gradient(Array3D* phi, Array3D** E) for (j=0; jny; j++) { ind = i + j * phi->nx; - E[2]->data[ind] = (phi->data[ind+nxy] - phi->data[ind]) / phi->dz; + E[2]->data[ind] = (phi->data[ind+nxy] - phi->data[ind]) / phi->dzp * phi->dzpdz[0]; ind = i + j * phi->nx + nxy; - E[2]->data[ind] = (phi->data[ind+nxy] - phi->data[ind-nxy]) / (2.0 * phi->dz); + E[2]->data[ind] = (phi->data[ind+nxy] - phi->data[ind-nxy]) / (2.0 * phi->dzp) * phi->dzpdz[1]; ind = i + j * phi->nx + (phi->nz-2) * nxy; - E[2]->data[ind] = (phi->data[ind+nxy] - phi->data[ind-nxy]) / (2.0 * phi->dz); + E[2]->data[ind] = (phi->data[ind+nxy] - phi->data[ind-nxy]) / (2.0 * phi->dzp) * phi->dzpdz[phi->nz-2]; ind = i + j * phi->nx + (phi->nz-1) * nxy; - E[2]->data[ind] = (phi->data[ind] - phi->data[ind-nxy]) / phi->dz; + E[2]->data[ind] = (phi->data[ind] - phi->data[ind-nxy]) / phi->dzp * phi->dzpdz[phi->nz-1]; for (k=2; knz-2; k++) { ind = i + j * phi->nx + k * nxy; - E[2]->data[ind] = (-phi->data[ind+2*nxy] + 8.0 * phi->data[ind+nxy] - 8.0 * phi->data[ind-nxy] + phi->data[ind-2*nxy]) / (12.0 * phi->dz); + E[2]->data[ind] = (-phi->data[ind+2*nxy] + 8.0 * phi->data[ind+nxy] - 8.0 * phi->data[ind-nxy] + phi->data[ind-2*nxy]) / (12.0 * phi->dzp) * phi->dzpdz[k]; } } } return; } -void MultiGrid::Trace(Array3D** E, double* point, ofstream& file) +void MultiGrid::Trace(double* point, int bottomsteps, bool savecharge, double bottomcharge, ofstream& file) { // This traces an electron down to the bottom, saving path info if requested // Diffusion has now been added. This version recalculates mu at each point. - // And iterates 1000 steps after reaching the bottom. - int i, nsteps = 0, nstepsmax = 10000, bottomsteps = 1000; + // And iterates bottomsteps steps after reaching the bottom. + // If savecharge is true, it finds and stores the self-consistent charge locations + int i, j, k, nsteps = 0, nstepsmax = 10000; bool ReachedBottom = false; double mu, E2, Emag, ve, vth, tau, Tscatt; double theta, phiangle, zmin, zbottom; - double x, y, z, xbot=0.0, ybot=0.0, zbot=0.0; + double x, y, z; zmin = (E[0]->z[Channelkmax] + E[0]->z[Channelkmin]) / 2.0; - zbottom = E[0]->z[Channelkmin - 1] + E[0]->dz / 2.0; + zbottom = E[0]->Z(E[0]->zp[Channelkmin] - E[0]->dzp / 2.0 + 0.01); x = point[0]; y = point[1]; z = point[2]; double* E_interp = new double[3]; @@ -1179,34 +1404,42 @@ void MultiGrid::Trace(Array3D** E, double* point, ofstream& file) point[0] += (vth * sin(theta) * cos(phiangle) + E_interp[0] * ve) * Tscatt; point[1] += (vth * sin(theta) * sin(phiangle) + E_interp[1] * ve) * Tscatt; point[2] += (vth * cos(theta) + E_interp[2] * ve) * Tscatt; + if (LogPixelPaths == 1) + { + file << setw(15) << x << setw(15) << y << setw(15) << z << setw(15) << point[0] << setw(15) << point[1] << setw(15) << point[2] << endl; + } if (point[2] < zmin && !ReachedBottom) { ReachedBottom = true; - nstepsmax = nsteps + bottomsteps; // After reaching bottom, iterate bottomsteps more steps. - //printf("Reached bottom. zmin = %.6f, z = %.6f\n",zmin, point[2]); - xbot = 0.0; ybot = 0.0; zbot = 0.0; + nstepsmax = nsteps + bottomsteps + bottomsteps / 10; + // After reaching bottom, iterate bottomsteps (*1.1) more steps. + // The first bottomsteps/10 steps are to let it settle to an + // equilibrium location, then we start logging the charge location } - if (ReachedBottom) + if (ReachedBottom && nsteps > nstepsmax - bottomsteps) { - xbot += point[0]; ybot += point[1]; zbot += point[2]; + // Start logging location after bottomsteps / 10. point[2] = max(zbottom, point[2]); - } - if (LogPixelPaths == 1) - { - file << setw(15) << x << setw(15) << y << setw(15) << z << setw(15) << point[0] << setw(15) << point[1] << setw(15) << point[2] << endl; + i = E[0]->XIndex(point[0]); + j = E[0]->YIndex(point[1]); + k = E[0]->ZIndex(point[2]); + if (i > 0 && i < elec[0]->nx-1 && j > 0 && j < elec[0]->ny-1 && k < elec[0]->nz-1 && savecharge) + { + elec[0]->data[i + j * elec[0]->nx + k * elec[0]->nx * elec[0]->ny] += bottomcharge;// Add bottomcharge to this grid cell + } } } - xbot /= (double) bottomsteps; ybot /= (double) bottomsteps; zbot /= (double) bottomsteps; - point[0] = xbot; point[1] = ybot; point[2] = zbot; delete[] E_interp; return; } -void MultiGrid::TraceSpot(Array3D* elec, Array3D** E, int m) +void MultiGrid::TraceSpot(int m) { // This builds up a Gaussian spot with given center (Xoffset, Yoffset) and SigmaX and SigmaY double x, y, z, rsq, v1, v2, fac, xwindow, ywindow, xcenter, ycenter; - int i, j, k, n; + int n; + int bottomsteps = 1000; + double bottomcharge = .001; double* point = new double[3]; string underscore = "_", slash = "/", name = "Pts"; string StepNum = boost::lexical_cast(m); @@ -1239,36 +1472,68 @@ void MultiGrid::TraceSpot(Array3D* elec, Array3D** E, int m) point[1] = y; z = ElectronZ0Fill; point[2] = z; - Trace(E, point, file); - // Trace returns the final location which is an average of last 1000 steps. - i = elec->XIndex(point[0]); - j = elec->YIndex(point[1]); - k = elec->ZIndex(point[2]); - if (SaturationModel == 1) + Trace(point, bottomsteps, true, bottomcharge, file); + // Trace returns the final location + file << setw(15) << x << setw(15) << y << setw(15) << z << setw(15) << point[0] << setw(15) << point[1] << setw(15) << point[2] << endl; + } + file.close(); + printf("Finished writing grid file - %s\n",filename.c_str()); + fflush(stdout); + delete[] point; + return; +} + +void MultiGrid::TraceMultipleSpots(int m) +{ + // This builds up multiple Gaussian spots + // Extents still hard coded - needs some work + double x, y, z, rsq, v1, v2, fac, xcenter, ycenter; + int i, j, n, Nume; + int bottomsteps = 1000; + double bottomcharge = .001; + double* point = new double[3]; + ofstream dummyfile; + xcenter = (PixelBoundaryUpperRight[0] + PixelBoundaryLowerLeft[0]) / 2.0 + Xoffset; + ycenter = (PixelBoundaryUpperRight[1] + PixelBoundaryLowerLeft[1]) / 2.0 + Yoffset; + for (i=-4; i<5; i++) + { + for (j=-4; j<5; j++) { - // Note that the requirement k > 0 will delete electrons that reach the last grid cell. - if (i > 0 && i < elec->nx-1 && j > 0 && j < elec->ny-1 && k > 0 && k < elec->nz-1) + if (i == 0 && j == 0) { - elec->data[i + j * elec->nx + k * elec->nx * elec->ny] += 1.0;// Add one electron to this grid cell + Nume = NumElec + NumElec / 10; } - } - else - { - if (i > 0 && i < elec->nx-1 && j > 0 && j < elec->ny-1 && k < elec->nz-1) + else { - elec->data[i + j * elec->nx + k * elec->nx * elec->ny] += 1.0;// Add one electron to this grid cell + Nume = NumElec; + } + for (n=0; n= 1.0 || rsq == 0.0) + { + v1 = 2.0 * drand48() - 1.0; + v2 = 2.0 * drand48() - 1.0; + rsq = v1*v1 + v2 *v2; + } + fac = sqrt(-2.0 * log(rsq) / rsq); + x = xcenter + (double)i * PixelSize + Sigmax * v1 * fac; + y = ycenter + (double)j * PixelSize + Sigmay * v2 * fac; + point[0] = x; + point[1] = y; + z = ElectronZ0Fill; + point[2] = z; + Trace(point, bottomsteps, true, bottomcharge, dummyfile); + // Trace returns the final location } } - file << setw(15) << x << setw(15) << y << setw(15) << z << setw(15) << point[0] << setw(15) << point[1] << setw(15) << point[2] << endl; } - file.close(); - printf("Finished writing grid file - %s\n",filename.c_str()); - fflush(stdout); delete[] point; return; } -void MultiGrid::TraceGrid(Array3D** E, int m) +void MultiGrid::TraceGrid(int m) { // This traces a grid of starting electron locations. double x, y, z; @@ -1294,7 +1559,7 @@ void MultiGrid::TraceGrid(Array3D** E, int m) point[1] = y; z = ElectronZ0Fill; point[2] = z; - Trace(E, point, file); + Trace(point, 100, false, 0.0, file); file << setw(15) << x << setw(15) << y << setw(15) << z << setw(15) << point[0] << setw(15) << point[1] << setw(15) << point[2] << endl; y += PixelBoundaryStepSize[1]; } @@ -1307,7 +1572,7 @@ void MultiGrid::TraceGrid(Array3D** E, int m) return; } -void MultiGrid::TraceRegion(Array3D** E, int m) +void MultiGrid::TraceRegion(int m) { // This traces a random set of starting electron locations within the PixelBoundary. double x, y, z, boxx, boxy; @@ -1338,7 +1603,7 @@ void MultiGrid::TraceRegion(Array3D** E, int m) point[1] = y; z = ElectronZ0Fill; point[2] = z; - Trace(E, point, file); + Trace(point, 100, false, 0.0, file); file << setw(15) << x << setw(15) << y << setw(15) << z << setw(15) << point[0] << setw(15) << point[1] << setw(15) << point[2] << endl; } file.close(); @@ -1348,7 +1613,7 @@ void MultiGrid::TraceRegion(Array3D** E, int m) return; } -void MultiGrid::FindEdge(Array3D** E, double* point, double theta, ofstream& file) +void MultiGrid::FindEdge(double* point, double theta, ofstream& file) { // This finds the edge of the pixel through binary search given a starting point and a line angle int nsteps, pixx, pixy, lastpixx, lastpixy, newpixx, newpixy; @@ -1361,7 +1626,7 @@ void MultiGrid::FindEdge(Array3D** E, double* point, double theta, ofstream& fil pixy = (int)floor((point[1] - PixelBoundaryLowerLeft[1]) / PixelSize); lastpixx = pixx; lastpixy = pixy; deltar = 1.0; - tolerance = 0.001; + tolerance = 0.0001; nsteps = 0; while (fabs(deltar) > tolerance) { @@ -1377,7 +1642,7 @@ void MultiGrid::FindEdge(Array3D** E, double* point, double theta, ofstream& fil point[0] = x; point[1] = y; point[2] = z0; - Trace(E,point,file); + Trace(point, 10, false, 0.0, file); newpixx = (int)floor((point[0] - PixelBoundaryLowerLeft[0]) / PixelSize); newpixy = (int)floor((point[1] - PixelBoundaryLowerLeft[1]) / PixelSize); //printf("Finding edge, newpixx = %d, newpixy = %d, theta = %.3f, %d steps, x = %.3f, y = %.3f\n",newpixx, newpixy, theta, nsteps,point[0],point[1]); @@ -1407,7 +1672,7 @@ void MultiGrid::FindEdge(Array3D** E, double* point, double theta, ofstream& fil return; } -void MultiGrid::FindCorner(Array3D** E, double* point, double* theta, ofstream& file) +void MultiGrid::FindCorner(double* point, double* theta, ofstream& file) { // This finds the corner of the pixel through binary search given a starting point and a line angle int nsteps; @@ -1417,7 +1682,7 @@ void MultiGrid::FindCorner(Array3D** E, double* point, double* theta, ofstream& z0 = point[2]; x0 = point[0]; y0 = point[1]; deltar = 1.0; - tolerance = 0.001; + tolerance = 0.0001; nsteps = 0; while (fabs(deltar) > tolerance) { @@ -1429,15 +1694,15 @@ void MultiGrid::FindCorner(Array3D** E, double* point, double* theta, ofstream& break; } point[0] = x0; point[1] = y0; point[2] = z0; - FindEdge(E, point, theta0, file); + FindEdge(point, theta0, file); r = sqrt((point[0] - x0) * (point[0] - x0) + (point[1] - y0) * (point[1] - y0)); r0 = r; point[0] = x0; point[1] = y0; point[2] = z0; - FindEdge(E, point, theta0 + delta_theta, file); + FindEdge(point, theta0 + delta_theta, file); r = sqrt((point[0] - x0) * (point[0] - x0) + (point[1] - y0) * (point[1] - y0)); rp = r; point[0] = x0; point[1] = y0; point[2] = z0; - FindEdge(E, point, theta0 - delta_theta, file); + FindEdge(point, theta0 - delta_theta, file); r = sqrt((point[0] - x0) * (point[0] - x0) + (point[1] - y0) * (point[1] - y0)); rm = r; //printf("Step = %d, theta = %.5f, r0 = %.4f, rm = %.4f, rp = %.4f\n",nsteps,theta,r0,rm,rp); @@ -1468,7 +1733,7 @@ void MultiGrid::FindCorner(Array3D** E, double* point, double* theta, ofstream& return ; } -void MultiGrid::CalculatePixelAreas(Array3D** E, int m) +void MultiGrid::CalculatePixelAreas(int m) { // This finds the pixel vertices and the areas of the pixel grid. int OldLogPixelPaths, k, n, pixx, pixy; @@ -1503,7 +1768,7 @@ void MultiGrid::CalculatePixelAreas(Array3D** E, int m) point[0] = x; point[1] = y; point[2] = ElectronZ0Area; - FindCorner(E, point, &theta, ptsfile); + FindCorner(point, &theta, ptsfile); Point* two_d_point = new Point(point[0], point[1], theta); polyarray[pixx + PixelBoundaryNx * pixy]->AddPoint(two_d_point); } @@ -1527,7 +1792,7 @@ void MultiGrid::CalculatePixelAreas(Array3D** E, int m) point[0] = x; point[1] = y; point[2] = ElectronZ0Area; - FindEdge(E, point, theta, ptsfile); + FindEdge(point, theta, ptsfile); //printf("Found edge, pixx = %d, pixy = %d, theta = %.3f, x = %.3f, y = %.3f\n",pixx, pixy, theta, point[0],point[1]); Point* two_d_point = new Point(point[0], point[1], theta); polyarray[pixx + PixelBoundaryNx * pixy]->AddPoint(two_d_point); @@ -1665,22 +1930,30 @@ double MultiGrid::mu_Si (double E,double T) return((vm/Ec)/pow(1 + pow(fabs(E)/Ec,beta),1/beta)); } -void MultiGrid::FillRho(Array3D* rho, Array3D* elec) +void MultiGrid::FillRho(Array3D* rho, Array3D* elec, Array3D* hole) { - //Fill rho with data from electron array + //Fill rho with data from electron array and hole array int i, j, k, index; - double ChargeFactor = -(QE*MICRON_PER_M/(EPSILON_0*EPSILON_SI)) / (GridSpacing * GridSpacing * GridSpacing); - for (i=0; inx-1; i++) + double RhoChargeFactor = (QE*MICRON_PER_M/(EPSILON_0*EPSILON_SI)) / (GridSpacing * GridSpacing); + double ChargeDepth, TotalElectrons = 0.0, TotalHoles = 0.0; + for (i=0; inx; i++) { - for (j=0; jny-1; j++) + for (j=0; jny; j++) { - for (k=0; knz-1; k++) + for (k=0; knz; k++) { + ChargeDepth = rho->Z(rho->zp[k] + rho->dzp / 2.0) - rho->Z(rho->zp[k] - rho->dzp / 2.0); index = i + j * rho->nx + k * rho->nx * rho->ny; - rho->data[index] += elec->data[index] * ChargeFactor; + rho->data[index] += (hole->data[index] - elec->data[index]) * RhoChargeFactor / ChargeDepth; + if (hole->data[index] < -1.0E-6 || elec->data[index] < -1.0E-6) + { + printf("Negative hole or electron count! Something failed!\n"); + } + TotalElectrons += elec->data[index]; + TotalHoles += hole->data[index]; } } } - printf("Mobile charges added into rho.\n"); + printf("Mobile charges added into rho.Total electrons=%.1f, Total holes=%.6g\n", TotalElectrons, TotalHoles); return; } diff --git a/src/multigrid.h b/src/multigrid.h index 63d4542..319f1c4 100755 --- a/src/multigrid.h +++ b/src/multigrid.h @@ -38,7 +38,7 @@ class MultiGrid public: double w; // Successive Over-Relaxation factor - int ncycle; // Number of SOR sysles at each resolution + int ncycle; // Number of SOR cycles at each resolution int iterations; // Number of VCycles int ScaleFactor; // Power of 2 that sets the grid size @@ -66,18 +66,22 @@ class MultiGrid double Vparallel_lo; // Parallel Low Voltage double Vparallel_hi; // Parallel High Voltage double Vserial_lo; // Serial Low Voltage - double Vaverage; // Average volatge on bottom + double Vaverage; // Average voltage on bottom double Vchannelstop; // Voltage of undepleted channel stop double Vscupper; // Scupper voltage - int Channelkmin; // Bottom of the silicon - first doped grid point + int Channelkmin; // Bottom of channel region doping int Channelkmax; // Top of channel region doping + int ChannelStopkmin; // Bottom of channel stop region doping + int ChannelStopkmax; // Top of channel stop region doping int ChannelProfile; // 0 = Square well, 1 = Gaussian int ChannelStopProfile; // 0 = Square well, 1 = Gaussian double BackgroundDoping; // Background doping double ChannelStopDoping; // Channel Stop doping double ChannelStopDepth; // Channel stop depth in microns double ChannelStopWidth; // Channel stop width in microns + double ChannelStopCharge; + double CSChargeDepth; double ChannelDoping; // Channel doping double ChannelDepth; // Channel depth in microns double GateOxide; // Gate oxide thickness in microns @@ -149,11 +153,13 @@ class MultiGrid string outputfiledir; // Output filename directory int SaveData; + int SaveElec; Array3D** phi; // Phi arrays Array3D** rho; // Rho arrays Array3D** E; Array3D** elec; // Number of stored electrons + Array3D** hole; // Number of mobile holes MultiGrid() {}; MultiGrid(string); @@ -163,7 +169,9 @@ class MultiGrid void BuildArrays(Array3D**, Array3D**, Array3D**, Array3D**, Array2D**); void SetInitialVoltages(Array3D*, Array2D*); void SetFixedCharges(Array3D*, Array2D*); - void SetMobileCharges(Array3D*); + void SetInitialElectrons(Array3D*, Array3D*); + void SetInitialHoles(Array3D*, Array3D*); + void AdjustHoles(Array3D*, Array3D*, Array3D*); void SOR(Array3D*, Array3D*, Array2D*, double); void SOR_N(Array3D*, Array3D*, Array2D*, double, int); double Error(Array3D*, Array3D*); @@ -172,15 +180,16 @@ class MultiGrid void VCycle(Array3D**, Array3D**, Array2D**, double, int, int); void WriteOutputFile(string, string, string, Array3D*); void Gradient(Array3D*, Array3D**); - void Trace(Array3D**, double*, ofstream&); - void TraceSpot(Array3D*, Array3D**, int); - void TraceGrid(Array3D**, int); - void TraceRegion(Array3D**, int); - void FindEdge(Array3D**, double*, double, ofstream&); - void FindCorner(Array3D**, double*, double*, ofstream&); - void CalculatePixelAreas(Array3D**, int); + void Trace(double*, int, bool, double, ofstream&); + void TraceSpot(int); + void TraceMultipleSpots(int); + void TraceGrid(int); + void TraceRegion(int); + void FindEdge(double*, double, ofstream&); + void FindCorner(double*, double*, ofstream&); + void CalculatePixelAreas(int); void AddDipolePotentials(Array3D*); double mu_Si (double, double); - void FillRho(Array3D*, Array3D*); + void FillRho(Array3D*, Array3D*, Array3D*); };