Printing Examples: Difference between revisions
(3 intermediate revisions by 2 users not shown) | |||
Line 18: | Line 18: | ||
puts "The Junction Depth is [ [[ | puts "The Junction Depth is [ [[InterpolateCmd | interpolate]] silicon z=0.0]" | ||
The above command uses the interpolate command to locate the zero crossing and report the value. For the structure above, the output is: | The above command uses the interpolate command to locate the zero crossing and report the value. For the structure above, the output is: | ||
Line 25: | Line 25: | ||
The Junction Depth is 2.629046e-01 | The Junction Depth is 2.629046e-01 | ||
Additional processing can be performed using the [[ | Additional processing can be performed using the [[Print1DCmd | print.1d]] command. | ||
Line 42: | Line 42: | ||
Grid1D | Grid1D | ||
diffuse time=60 temp=1100 wet | |||
The above two commands grow an oxide that will be used in the remaining examples. | The above two commands grow an oxide that will be used in the remaining examples. | ||
set top [[[ | set top [ [[interfaceCmd | interface]] oxide /gas] | ||
set bot [[[ | set bot [ [[interfaceCmd | interface]] oxide /silicon] | ||
puts "Thickness is [expr $bot - $top]" | puts "Thickness is [expr $bot - $top]" | ||
Line 54: | Line 53: | ||
sel z = {$Oxidant} | |||
layers | layers | ||
Line 65: | Line 64: | ||
The oxide layer thickness is 0.674, and the dose of oxidant contained in the layer is 1.1e15. The silicon has been consumed as expected. | The oxide layer thickness is 0.674, and the dose of oxidant contained in the layer is 1.1e15. The silicon has been consumed as expected. | ||
= Printing to a txt file = | |||
You can use tcl to open up a channel to a file for writing (w) or appending (a). (You can also open up a file for reading (r), and use the "gets" command for that). The "open" function returns the channel name assigned by your computer, which you should store in a variable so you can access the channel later: | |||
set ch [open filename.txt w] | |||
In the line above, "set" is a tcl command which sets a variable named "ch" to whatever the command inside the brackets evaluate to, i.e. to whatever "[open filename.txt w]" evaluates to (this is what square brackets mean in tcl). Inside the brackets, "open" is a command which opens filename.txt for writing "w" and returns the channel name that your computer chooses (probably something like "file11"). Once this channel is open, and pointing to filename.txt, you can put anything in it. | |||
puts $ch "Hello World!" | |||
puts $ch [print.1d];# make sure you've selected something before trying to print.1d | |||
puts $ch "$myvar1\t$myvar2" | |||
At the end of everything, you MUST close the channel to finish writing to it. This is like "safely eject drive" before removing your flash drive on a windows machine. | |||
close $ch | |||
You can use scripting to automatically organize your files in directories and by naming them with variable names from floods: | |||
set ch_storage [open TXT/$dimension/$txtfilename a] | |||
puts $ch_storage "$Rd\t$Nit_10" | |||
close $ch_storage | |||
FLOODS can have some unwanted formatting in the print.1d, or the layers command that you may not want in your text file. You can print.1d to a variable first, then manipulate that variable to get it into the format you want, and then write to a text file. For example, the procedures below are simple (i.e. working but not the most clever or efficient or universal) examples that get rid of a specified character in a string (KillChar), clean a print.1d string for writing into a text file without brackets (Clean2Txt), or join multiple txt files in 2-column format into one text file with "x, y1, y2, ..., yn" format if x is the same in the files you want to join: | |||
#------------------------------------------------------------------------ | |||
# Kill Char gets rid of any $char's in you $str | |||
#------------------------------------------------------------------------ | |||
proc KillChar {str char} { | |||
while {[string first $char $str] >= 0} { | |||
set str [string replace $str [string first $char $str] [string first $char $str]] | |||
} | |||
return $str | |||
} | |||
#set str [KillChar $str \ ];# example usage, kills spaces | |||
#set str [KillChar $str m];# example usage, kills the letter m | |||
#puts $str;#to see it | |||
#------------------------------------------------------------------------------------------ | |||
# Clean2Txt prints a cleaned floods variable (eg DevPsi) into filename.txt, tab-deliniated | |||
#------------------------------------------------------------------------------------------ | |||
proc Clean2Txt {FloodsVar filename col1 col2} { | |||
#Create a temporary string we can chop up | |||
set tmp $FloodsVar | |||
set filename_txt [open $filename.txt w] | |||
#puts "We're going to take this string and write it cleanly into a file, $filename.txt\n$tmp" | |||
set tmp [KillChar $tmp \ ];#first kill all white spaces | |||
set lastline_yn 0;# initialize this flag: it is not the last line of the string | |||
set cleaned_list blankline | |||
for {set i 0} {$lastline_yn == 0} {incr i} { | |||
eval set stri_name str$i;#create a name for your new string: str0, str1, str2, etc... | |||
set $stri_name $tmp; eval set stri_value \$str$i;#create a value in your new string | |||
set brace_index [string last \{ $tmp];# finds last open brace | |||
set lastline_yn [string equal $brace_index 0];# 1=y, 0=n;# if last open brace is at i0, then it's the last line | |||
#if this not the last line, chop off lines 2 through end | |||
if {$lastline_yn == 0} { | |||
set newline_index [string first \n $tmp];# find the first newline index | |||
set $stri_name [string replace $tmp $newline_index end]; eval set stri_value \$str$i;#chop from that index | |||
} | |||
#get rid of last column | |||
set end_of_line [string last \t $stri_value];# finds the last tab | |||
set $stri_name [string replace $stri_value $end_of_line end]; eval set stri_value \$str$i | |||
#get rid of left bracket | |||
set $stri_name [string trimleft $stri_value \{]; eval set stri_value \$str$i;# here we must eval again to update | |||
#finally puts the line into the txt file: | |||
#puts "This is your final string $i that will goin into $filename.txt:\n$stri_value" | |||
if {$i == 0} {puts $filename_txt "$col1 $col2"} | |||
if {$i != 0} {puts $filename_txt "$stri_value"};# a newline is written automatically in your txt file | |||
#make the new tmp (deleating the first line you just wrote to the txt file) | |||
set tmp [string replace $tmp 0 $newline_index] | |||
} | |||
puts $filename_txt "$filename\t$filename" | |||
close $filename_txt | |||
return [puts "check $filename.txt to see your cleaned table\n\n"] | |||
} | |||
#example of how to call: | |||
#sel z=Hydrogen | |||
#set H2 [print.1d y.v=0] | |||
#Clean2Txt $H2 H2 "x(@y=0)" "H2_log";# makes H2.txt with cleaned Hydrogen profile at y=0 | |||
#--------------or-----------------------# | |||
#Clean2Txt $str str_name col1 col2 | |||
#-------------or------------------------# | |||
#sel z=[expr {-Vg}] | |||
#Clean2Txt [print.1d y.v=0] IV.Vg_is_$Vgg Vdd Vgg | |||
#Join2Txt IV.1 IV.2 IV.all | |||
proc Join2Txt {file1 file2 filename} { | |||
#if one of the files is "null", just copy the actual file to filename | |||
if {[file exists $file1.txt] ^ [file exists $file2.txt]} { | |||
if {[file exists $file1.txt]} {file copy $file1.txt $filename.txt} | |||
if {[file exists $file2.txt]} {file copy $file2.txt $filename.txt} | |||
#if not, then if both files exists, join them | |||
} elseif {[file exists $file1.txt] && [file exists $file2.txt]} { | |||
#first test if you need to append just a new y, or both x and y | |||
file copy $file1.txt bk1.txt | |||
file copy $file2.txt bk2.txt | |||
set bk1_txt [open bk1.txt r] | |||
set bk2_txt [open bk2.txt r] | |||
while {([eof $bk1_txt] || [eof $bk2_txt]) == 0} { | |||
set xfrom1 [gets $bk1_txt] | |||
set xfrom2 [gets $bk2_txt] | |||
set xfrom1 [string replace $xfrom1 [string first \t $xfrom1] end] | |||
set xfrom2 [string replace $xfrom2 [string first \t $xfrom2] end] | |||
if {$xfrom1 eq $xfrom2} {set appendboth_yn 0} | |||
if {$xfrom1 ne $xfrom2} { | |||
if {![eof $bk1_txt] && ![eof $bk2_txt]} { | |||
set appendboth_yn 0; break | |||
} else {set appendboth_yn 1; break} | |||
} | |||
} | |||
close $bk1_txt | |||
close $bk2_txt | |||
file delete bk1.txt | |||
file delete bk2.txt | |||
#this section actually writes the new columns | |||
set file1_txt [open $file1.txt r] | |||
set file2_txt [open $file2.txt r] | |||
set tmp_txt [open tmp.txt w] | |||
set linefrom1 [gets $file1_txt] | |||
set linefrom2 [gets $file2_txt];# appends both x and y | |||
if {$appendboth_yn == 0} {set linefrom2 [string replace $linefrom2 0 [string first \t $linefrom2]]};#just x | |||
while {([eof $file1_txt] || [eof $file2_txt]) == 0} { | |||
#add something here to account for collumns of different lengths | |||
append linefrom1 "\t$linefrom2" | |||
puts $tmp_txt $linefrom1 | |||
set linefrom1 [gets $file1_txt] | |||
set linefrom2 [gets $file2_txt] | |||
if {$appendboth_yn == 0} {set linefrom2 [string replace $linefrom2 0 [string first \t $linefrom2]]} | |||
} | |||
close $tmp_txt | |||
close $file1_txt | |||
close $file2_txt | |||
if {[file exists $filename.txt]} {file delete $filename.txt} | |||
file rename tmp.txt $filename.txt | |||
#if neither of the files exist, print an error | |||
} else { | |||
puts "INPUT ERROR, files DNE" | |||
} | |||
} | |||
#Example: | |||
#Clean2Txt $str1 file1 | |||
#Clean2Txt $str2 file2 | |||
#Join2Txt file1 file2 str1and2 | |||
#Example: | |||
#Join2Txt file1 null str1alone |
Latest revision as of 15:50, 14 June 2020
Junction Depth and Layers
Integrate Dose and Find Junction
Grid1D
sel z = {1.0e18*exp(-x * x / 0.01) - 1.0e15}
The above deck initializes the grid with a default one dimensional structure. The second command selects as the plot variable a Gaussian profile minus a background doping. The layers command integrates the selected variable and reports zero crossings. The output is:
Top Bottom Integral Material 0.00000e 00 2.62905e-01 8.83423e 12 Silicon 0.262905e-1 5.00000e 01 -4.97191e 12 Silicon
The top layer has positive sign and is silicon. The total integrated dose is 8.8e12 in this layer. From 0.26um down, the selected variable is negative. To a depth of 50um, the integrated value is about 5e12.
puts "The Junction Depth is [ interpolate silicon z=0.0]"
The above command uses the interpolate command to locate the zero crossing and report the value. For the structure above, the output is:
The Junction Depth is 2.629046e-01
Additional processing can be performed using the print.1d command.
set dep 0 foreach f [print.1d] { set x [lindex $f 0] set y [lindex $f 1] if {$y > 0.0} {incr dep} } puts $dep
Returns 227, the number of grid points that have a positive selected variable value. Other operations can be performed and are limited only by the tcl capabilities.
Interface Manipulations
Grid1D diffuse time=60 temp=1100 wet
The above two commands grow an oxide that will be used in the remaining examples.
set top [ interface oxide /gas] set bot [ interface oxide /silicon] puts "Thickness is [expr $bot - $top]"
The interface commands return the location of the interface. Since we can independently locate both the top and bottom, these can be subtracted to obtain the total oxide thickness. The total oxide thickness is 0.673907.
sel z = {$Oxidant} layers
These two commands sel the oxidant and then integrate it across all material layers. The output is:
Top Bottom Integral Material -3.68495e-01 3.05413e-01 1.12857e 15 Oxide 3.05413e-01 5.00000e 01 2.67928e 12 Silicon
The oxide layer thickness is 0.674, and the dose of oxidant contained in the layer is 1.1e15. The silicon has been consumed as expected.
Printing to a txt file
You can use tcl to open up a channel to a file for writing (w) or appending (a). (You can also open up a file for reading (r), and use the "gets" command for that). The "open" function returns the channel name assigned by your computer, which you should store in a variable so you can access the channel later:
set ch [open filename.txt w]
In the line above, "set" is a tcl command which sets a variable named "ch" to whatever the command inside the brackets evaluate to, i.e. to whatever "[open filename.txt w]" evaluates to (this is what square brackets mean in tcl). Inside the brackets, "open" is a command which opens filename.txt for writing "w" and returns the channel name that your computer chooses (probably something like "file11"). Once this channel is open, and pointing to filename.txt, you can put anything in it.
puts $ch "Hello World!" puts $ch [print.1d];# make sure you've selected something before trying to print.1d puts $ch "$myvar1\t$myvar2"
At the end of everything, you MUST close the channel to finish writing to it. This is like "safely eject drive" before removing your flash drive on a windows machine.
close $ch
You can use scripting to automatically organize your files in directories and by naming them with variable names from floods:
set ch_storage [open TXT/$dimension/$txtfilename a] puts $ch_storage "$Rd\t$Nit_10" close $ch_storage
FLOODS can have some unwanted formatting in the print.1d, or the layers command that you may not want in your text file. You can print.1d to a variable first, then manipulate that variable to get it into the format you want, and then write to a text file. For example, the procedures below are simple (i.e. working but not the most clever or efficient or universal) examples that get rid of a specified character in a string (KillChar), clean a print.1d string for writing into a text file without brackets (Clean2Txt), or join multiple txt files in 2-column format into one text file with "x, y1, y2, ..., yn" format if x is the same in the files you want to join:
#------------------------------------------------------------------------ # Kill Char gets rid of any $char's in you $str #------------------------------------------------------------------------ proc KillChar {str char} { while {[string first $char $str] >= 0} { set str [string replace $str [string first $char $str] [string first $char $str]] } return $str } #set str [KillChar $str \ ];# example usage, kills spaces #set str [KillChar $str m];# example usage, kills the letter m #puts $str;#to see it
#------------------------------------------------------------------------------------------ # Clean2Txt prints a cleaned floods variable (eg DevPsi) into filename.txt, tab-deliniated #------------------------------------------------------------------------------------------ proc Clean2Txt {FloodsVar filename col1 col2} { #Create a temporary string we can chop up set tmp $FloodsVar set filename_txt [open $filename.txt w] #puts "We're going to take this string and write it cleanly into a file, $filename.txt\n$tmp" set tmp [KillChar $tmp \ ];#first kill all white spaces set lastline_yn 0;# initialize this flag: it is not the last line of the string set cleaned_list blankline for {set i 0} {$lastline_yn == 0} {incr i} { eval set stri_name str$i;#create a name for your new string: str0, str1, str2, etc... set $stri_name $tmp; eval set stri_value \$str$i;#create a value in your new string set brace_index [string last \{ $tmp];# finds last open brace set lastline_yn [string equal $brace_index 0];# 1=y, 0=n;# if last open brace is at i0, then it's the last line #if this not the last line, chop off lines 2 through end if {$lastline_yn == 0} { set newline_index [string first \n $tmp];# find the first newline index set $stri_name [string replace $tmp $newline_index end]; eval set stri_value \$str$i;#chop from that index } #get rid of last column set end_of_line [string last \t $stri_value];# finds the last tab set $stri_name [string replace $stri_value $end_of_line end]; eval set stri_value \$str$i #get rid of left bracket set $stri_name [string trimleft $stri_value \{]; eval set stri_value \$str$i;# here we must eval again to update #finally puts the line into the txt file: #puts "This is your final string $i that will goin into $filename.txt:\n$stri_value" if {$i == 0} {puts $filename_txt "$col1 $col2"} if {$i != 0} {puts $filename_txt "$stri_value"};# a newline is written automatically in your txt file #make the new tmp (deleating the first line you just wrote to the txt file) set tmp [string replace $tmp 0 $newline_index] } puts $filename_txt "$filename\t$filename" close $filename_txt return [puts "check $filename.txt to see your cleaned table\n\n"] } #example of how to call: #sel z=Hydrogen #set H2 [print.1d y.v=0] #Clean2Txt $H2 H2 "x(@y=0)" "H2_log";# makes H2.txt with cleaned Hydrogen profile at y=0 #--------------or-----------------------# #Clean2Txt $str str_name col1 col2 #-------------or------------------------# #sel z=[expr {-Vg}] #Clean2Txt [print.1d y.v=0] IV.Vg_is_$Vgg Vdd Vgg #Join2Txt IV.1 IV.2 IV.all
proc Join2Txt {file1 file2 filename} { #if one of the files is "null", just copy the actual file to filename if {[file exists $file1.txt] ^ [file exists $file2.txt]} { if {[file exists $file1.txt]} {file copy $file1.txt $filename.txt} if {[file exists $file2.txt]} {file copy $file2.txt $filename.txt} #if not, then if both files exists, join them } elseif {[file exists $file1.txt] && [file exists $file2.txt]} { #first test if you need to append just a new y, or both x and y file copy $file1.txt bk1.txt file copy $file2.txt bk2.txt set bk1_txt [open bk1.txt r] set bk2_txt [open bk2.txt r] while {([eof $bk1_txt] || [eof $bk2_txt]) == 0} { set xfrom1 [gets $bk1_txt] set xfrom2 [gets $bk2_txt] set xfrom1 [string replace $xfrom1 [string first \t $xfrom1] end] set xfrom2 [string replace $xfrom2 [string first \t $xfrom2] end] if {$xfrom1 eq $xfrom2} {set appendboth_yn 0} if {$xfrom1 ne $xfrom2} { if {![eof $bk1_txt] && ![eof $bk2_txt]} { set appendboth_yn 0; break } else {set appendboth_yn 1; break} } } close $bk1_txt close $bk2_txt file delete bk1.txt file delete bk2.txt #this section actually writes the new columns set file1_txt [open $file1.txt r] set file2_txt [open $file2.txt r] set tmp_txt [open tmp.txt w] set linefrom1 [gets $file1_txt] set linefrom2 [gets $file2_txt];# appends both x and y if {$appendboth_yn == 0} {set linefrom2 [string replace $linefrom2 0 [string first \t $linefrom2]]};#just x while {([eof $file1_txt] || [eof $file2_txt]) == 0} { #add something here to account for collumns of different lengths append linefrom1 "\t$linefrom2" puts $tmp_txt $linefrom1 set linefrom1 [gets $file1_txt] set linefrom2 [gets $file2_txt] if {$appendboth_yn == 0} {set linefrom2 [string replace $linefrom2 0 [string first \t $linefrom2]]} } close $tmp_txt close $file1_txt close $file2_txt if {[file exists $filename.txt]} {file delete $filename.txt} file rename tmp.txt $filename.txt #if neither of the files exist, print an error } else { puts "INPUT ERROR, files DNE" } } #Example: #Clean2Txt $str1 file1 #Clean2Txt $str2 file2 #Join2Txt file1 file2 str1and2 #Example: #Join2Txt file1 null str1alone