Tcl: processing variables in a list - loops

Maybe this is pretty stupid, but I really can't find a soulution. I created two variables and want to transform them into lists.
This commands are tool specific, but they work the way I want:
redirect max_transition {report_constraint -view $pargs(-scenario) -drv_violation_type {max_transition} -all_violators} -variable
redirect max_capacitance {report_constraint -view $pargs(-scenario) -drv_violation_type {max_capacitance} -all_violators} -variable
Now I want to create tcl lists out of them. I could use a loop, because the data has the same structure.
set reports {$max_transition $max_capacitance}
set report_length [llength $reports]
for {set i 0} {$i < $report_length} {incr i} {
set tns_value 0
set max_wns 0
set vios 0
set report [lindex $reports $i]
puts $report
# remove all uneccessary white spaces
set no_space [regexp -all -inline {\S+} $report]
# insert a new line for every path
set insert_lines [string map {" U_" \nU_} $no_space]
# create list out of result reports
set report_list [split $insert_lines "\n"]
if {[llength $report_list] > 1} {
for {set i 1} {$i < [llength $report_list]} {incr i} {
# get value of violation
set slack [lindex [split [lindex $report_list $i] " "] 3]
set tns_value [expr $tns_value + $slack]
if {$vios == 0} {set max_wns $slack}
incr vios
}
}
# write out values
puts "$pargs(-scenario), $report, $max_wns, $tns_value, $vios"
}
But this does not work out. The loop just puts out the variable's names (because of "puts $report") but not its content.
If I do it without a loop (so for each variable the same code consecutively), I get the lists I want.
So how can I process these variables as a whole in a loop?

The problem lies in the below loop variable i, it is overriding variable value of outer-loop. Try changing inner-loop variable to j.
for {set i 1} {$i < [llength $report_list]} {incr i} {
# get value of violation
set slack [lindex [split [lindex $report_list $i] " "] 3]
set tns_value [expr $tns_value + $slack]
if {$vios == 0} {set max_wns $slack}
incr vios
}

It's hard to write an answer for this since so much is unknown. To begin with, you should probably change to assignment by list and a foreach loop like this:
set reports [list $max_transition $max_capacitance]
foreach report $reports {
Since you don't really need to use a for loop here, it makes sense to simplify it. Please comment and I will iteratively improve the answer if I can.

Related

Iterate while loop results to list in tcl

How to iterate while loop results to a list in Tcl?
set i 0
while { $i < ($num +1) } {
set list $i
incr i
}
create a list by using above while loop.
You've almost got it. You just need to use lappend inside the loop (and for is more idiomatic than while for this sort of thing). Note that where you put newlines is important; you can't put them between a while condition and the body of the loop (without putting a backslash in, which is ugly).
for {set i 0} {$i < ($num + 1)} {incr i} {
lappend list $i
}
You could write the following equivalent code, but the above is clearer:
set i 0
while {$i < ($num + 1)} {
lappend list $i
incr i
}
Finally, I'd actually use this:
for {set i 0} {$i <= $num} {incr i} {
lappend list $i
}
It emphasises that $num is the limit more clearly, with <= marking it as an inclusive limit. I'd do the same in many other languages too.
$i takes a value that is always going to be a number as the code is written. This value is then assigned to list. list should then be printed or stored... exactly what you want to do with list is not clear because as the code is written, it is simply overwritten on each iteration of the loop.
You also have a problem with your loop condition possibly. Unless you are looking for a list of numbers generated by the increment of i the code should be:
set i 0
while { i < ($num + 1)} {
set list $i
[here would be where you print/store list]
incr i
}
Does this help?

Retrieving modelsim signals into tcl

How can I retrieve a Modelsim signal value in this form x y into tcl so I can process x and y individually?
Currently I have this line in tcl to trace a signal value
when {/currentstate/comp_occupy} {set comp [exa
{/currentstate/comp_occupy}]}
This signal is a 2D array in Modelsim which is shown like x y in the widget.
This snippet should trace that variable
trace variable comp w grid_monitor
proc grid_monitor {name arrayindex op} {
global comp flag_ttt cells
if {$flag_ttt == 1} {
puts $comp
puts [llength $comp]
}
}
What I get out of this proc is like this {x y} but I have no idea how I can separate x and y. First I thought that's a list but llength returns 1!
Any idea how I can go about doing this? Or rather, how can I turn it into a proper list?
Thanks
Since we established that the braces were literal braces, you can trim them out. Once done, you can then split to get a list:
proc grid_monitor {name arrayindex op} {
global comp flag_ttt cells
if {$flag_ttt == 1} {
set new_comp [split [string trim $comp "{}"]]
puts $new_comp
puts [llength $new_comp]
}
}
string trim will trim from $comp the characters contained within the quotes, that is { and }. split will then split the string on space to give a list.
And if you want to assign x and y to the above, you can use lindex or lassign (if you have Tcl8.5 or later):
proc grid_monitor {name arrayindex op} {
global comp flag_ttt cells
if {$flag_ttt == 1} {
set new_comp [split [string trim $comp "{}"]]
puts $new_comp
puts [llength $new_comp]
set x [lindex $new_comp 0]
set y [lindex $new_comp 1]
puts "x is $x and y is $y"
}
}
Or...
set new_comp [split [string trim $comp "{}"]]
puts $new_comp
puts [llength $new_comp]
lassign $new_comp x y
puts "x is $x and y is $y"
In Tcl 8.5 the syntax to convert a string containing a valid list is to use the new expand operator:
set comp {*}$comp
It isn't clear if current versions of Modelsim have upgraded beyond 8.4 in which you need to do the same with eval:
eval set comp $comp
This uses the interpreter to do what it does best and avoids manually massaging the string.

Nested for loop issue TCL

#!/bin/sh
# This is a trial program
puts "++++++++++++++++++++++++++++++++++++++++++++++++++"
set y "0.0.0.0"
set z [split $y "."]
puts "z=$z"
lreplace $z 0 5
puts "z $z"
set v [llength $z]
puts "length of array= $v"
puts "in the loop-------->\n"
puts " "
incr v -1
puts $v
for {set ml $v } { $ml >= 0} { puts "$ml =ml"} {
for { set nl [lindex $z $ml]} { $nl >=4} { puts "$nl=nl"} {
puts $nl
after 2000
lset z $ml $nl
incr $nl
}
after 2000
incr ml -1
}
I am not able to enter the second for loop, is this a formatting issue ?
gives me some weird error. I added the sleep just to check whats happening so ignore that.
In your code your inner loop is only evaluating if nl >=4.
nl will be initialized as 0 from [lindex $z $ml]
Since you are incrementing $nl, my guess is you should change this line:
for { set nl [lindex $z $ml]} { $nl >=4} { puts "$nl=nl"} {
to this instead:
for { set nl [lindex $z $ml]} { $nl <=4} { puts "$nl=nl"} {
Was it perchance something like this you intended?
# This is a trial program
puts "++++++++++++++++++++++++++++++++++++++++++++++++++"
set y "0.0.0.0"
set z [split $y "."]
puts "\$z=$z"
set v [llength $z]
# the term 'array' means associative array in Tcl, better use 'list'
puts "length of list= $v"
puts "in the loop-------->\n\n"
incr v -1
puts "\$v=$v"
for {set ml $v} {$ml >= 0} {incr ml -1} {
for {set nl [lindex $z $ml]} {$nl <= 4} {incr nl} {
lset z $ml $nl
puts $z
}
}
Note that I've moved the incr command invocations to the third argument (the next command string, as the documentation puts it) of the for command invocations. You can put anything you want to run at the end of each iteration there, including puts commands as you did, but it's a convention and good practice to have the loop-control-changing commands (whatever they may be) there, and not much else.

loop within loop (with more detail)

I have a 229 residue protein and I need to measure from the center of mass of residue 1-12 (individually) to every other atom, residue 13 onwards, I also need this for each frame. so far I have this
set pro [atomselect top "resid 1 and not water and not ion"]
set atom [atomselect top "index 207"]
set nf [molinfo top get numframes]
set outfile [open test207.dat w]
for {set i 0} {$i < $nf} {incr i} {
puts "frame $i of $nf"
$pro frame $i
$atom frame $i
set com1 [measure center $pro weight mass]
set com2 [measure center $atom weight mass]
set distance [veclength [vecsub $com1 $com2]]
puts $outfile "$i $distance"
}
this is working to the extent that it's measure the distance between the first atom of residue 13 to the com of residue 1 for all frames, but I'm unsure as to how to put a second loop that will loop for every atom, instead of running the script thousands of times (changing the atom number each time) resulting in thousands of files.
Is there a way to loop for each atom and for each frame in the same script?
Is this the kind of thing you are trying to do?
for {set resid 1} {$resid < 10} {incr resid} {
set atomkey [format "resid %d and not water and not ion" $resid]
puts $atomkey
set filename [format "test%d.dat" $resid]
set outfile [open $filename w]
# Do stuff
close $outfile
}
This results in atomkey and filename being built with the value of resid embeded in it. So this type of technique will allow you to create your key strings and file names. If you can't generate the values using a for loop then you can also look at the foreach loop:
foreach resid [list 1 2 4 6 7 99 12] {
set atomkey [format "resid %d and not water and not ion" $resid]
puts $atomkey
}
You can build the compound values just using set, but I like to use format as I'm a C programmer at heart.
set atomkey "resid $resid and.."
Normally this is how you put two loops...
for (set j 0} {$j < $..} {incr j} {
for {set i 0} {$i < $nf} {incr i} {
}; # inner loop ends
}; # outer loop ends

TCL: List concat doesnt work

I am trying to join the below two elements as a single list
Tried concat , join , lappend etc but its not working
1134-1215 { W.1.Agg-251 ethernet4/28 island ethernet9/7}
I need the output of (links)list whose 1st element is 1134 , second element as W.1.Agg-251 etc
for {set index 0 } { $index <=328 } {incr index} {
lappend links [lindex $result2 $index] [lindex $list4 $index]
}
puts "===>$links"
where result 2 is a list like {1134-1150 1151-1600 .. }
and list4 is a list like {W.1.Agg-251 ethernet4/28 island ethernet9/7 X.1.Agg-251 ethernet4/29 island ethernet9/9... }
You probably meant to do something like
set links [concat $links [lindex $result2 $index] [lindex $list4 $index]]

Resources