Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

create matrix from a file's data

Status
Not open for further replies.

DimGio

Programmer
Feb 20, 2008
12
GR
Greetings to you all! It is the first time i use Tcl and i would like your assistance immediately. It might sounds easy for you ,but for me, who i have no experience at all is quite a trouble. I need to do this :
I have a file of inputs. (a matrix 100X100 saved from Matlab..in txt form)
I want to manipulate this matrix with Tcl/Tk because i need the values of each row and column.
I only know how to open the file:
set file [open "filename" r].
I don't know what to do after.....
Help!!!



 
A matrix in Tcl is, as it is anywhere, a 2D array. In Tcl, you don't have to declare an array or specify its dimensions beforehand. So, you can assign element A(i,j) to a value with
set A(i,j) <blah blah>

So, when you read the text file, how are the data arranged? Let's say you have 100 lines of 100 numbers each, with each line comma delimited. I don't know if that's what you have but let's just say so...
Code:
set fid [open <filename> r]; #assign a channel to the file
set rowslst [split [read $fid] \n]; #make a list of lines
close $fid
set i 0
foreach rw $rowslst {
  set elmlst [split $rw ,]; #make a list of elements on each line
  set j 0
  foreach elm $elmlst {
     set A($i,$j) $elm; # assuming your array is named "A"
     incr j
  }
  incr i
}

_________________
Bob Rashkin
 
Let me explain you my project..

Let'say that y=var1*var2*var3..*var100
where var1,var2...var100 are random variables.(The take different values every time)

I have (let'say) 100 random variables. For each one of them i create 100 samples( i give them 100 different values).

variables samples
var1 1value1 1value2 . . . 1value100
var2 2value1 2value2 . . . 2value100
var3 3value1 3value2 . . . 3value100
.
.
var100 100value1 100value2 . . . 100value100

I do this in matlab.I save the matrix data as a text file.The data have the above form. The values in every line are seperated by space.

I run a program (Opensees) which uses Tcl/Tk. It is a program for engineers.
Somewhere inside my code i have the random variables
(var1, var2, var3,...,var100).

I treat them as a vector for every sample. This mean that i will use, in a certain run, the values :

(var1, var2,...,var100)=(1value1, 2value1,...100value1)
result :y1=a1

in another run

(var1, var2,...,var100)=(1value2, 2value2,...100value2)
result:y2=a2

etc...

(var1, var2,...,var100)=(1value100,2value100,...100value10
result : y100=a100

So , i need the values of every column in every run.
I will do that 100 times. So i will take 100 outcomes.Let's say that i will take y={ a1, a2, ..., a100)
where y=f(var1, var2, ...var100)

I must be able to do that with a loop, not manually (100 times!!!!) and i must concetrate all the values in a line, so that i will be able to use them in matlab..

Can you give me a direction?

Thank you my friend!

 
Let's see...
First, your data are space delimited rather than comma delimited (as I assumed in my example). Fine. There are many ways to proceed here but I would use regsub to change all occurrences of any number of spaces to commas:
regsub -all {\s+} $rw {,} rw
Now your data will look like:
[tt]var1,1value1,1value2, . . . ,1value100
var2,2value1,2value2, . . . ,2value100
var3,3value1,3value2, . . . ,3value100[/tt]

I'm still not clear as to what you do with the data, that is, how you use it inside Opensees. Therefore, I can't say whether a 2-d array is the best way to store it. Assuming (as you suggest in your post) that, indeed, you want to build an array that will be 100x100, the only thing we need to do is get rid of the first element of each row (line), since that will be the variable name:
set elmlst [lreplace $elmslt 0 0]
If you want to be really cute, instead of the row index being a number from 0-99, it can be the variable name, itself, otherwise, I have no reason to change what I had before:
Code:
set fid [open <filename> r]; #assign a channel to the file
set rowslst [split [read $fid] \n]; #make a list of lines
close $fid
[s]set i 0[/s]
foreach rw $rowslst {
  [red]regsub -all {\s+} $rw {,} rw[/red];#make rw comma-delimited
  set elmlst [split $rw ,]; #make a list of elements on each line
  set j 0
  [red]set i [lindex $elmlst 0][/red];#make i = varname
  [red]set elmlst [lreplace $elmslt 0 0][/red];#remove 0th element
  foreach elm $elmlst {
     set A($i,$j) $elm; # assuming your array is named "A"
     incr j
  }
  [s]incr i[/s]
}

_________________
Bob Rashkin
 
Obviously,
set elmlst [lreplace $elmslt 0 0]
should be
set elmlst [lreplace [red]$elmlst[/red] 0 0]

_________________
Bob Rashkin
 
Thank you my friend!I changer the spaces with commas in the txt file so it will not be necessary to do that in the code.

The first column is not the name of the variables it's their first values...So i do need the first column.

Here is the code i use in opensees :

It calculates the displacement of a beam which consists of 100 elements

.......................................................
model basic -ndm 2 -ndf 3

# Nodal coordinates
node 1 0 0
node 2 1.5 0
node 3 3 0
node 4 4.5 0

# Boundary conditions
fix 1 1 1 1
fix 2 0 0 0
fix 3 1 1 0
fix 4 0 0 0

# Transformation
geomTransf Linear 1

# Elements
element elasticBeamColumn 1 1 2 0.015 $var1 0.000028125 1
element elasticBeamColumn 2 2 3 0.015 $var2 0.000028125 1
element elasticBeamColumn 3 3 4 0.015 $var3 0.000028125 1
.
.
element elasticBeamColumn 3 3 4 0.015 $var100 0.000028125 1

# Loads
pattern Plain 1 Linear {
load 1 0.0 11250 2812.5
load 2 0.0 22500 0.0
load 3 0.0 11250 -2812.5
load 4 0.0 -2500 0.0
}

constraints Transformation
numberer RCM
system BandGeneral
test NormDispIncr 1.0e-6 6
algorithm Newton
integrator LoadControl 0.1
analysis Static
analyze 1
loadConst -time 0.0

# End of the analysis

# Recorders
recorder Node -file Node4.out -time -node 4 -dof 2 disp
............................................................

Now you can see were i use the values of the random variables. The values of the variables in the first column of the array (100 values) give me the first value of the displacement. The values of the second column of the array(100) give me the second value of the displacement...etc.
I record the values of the displacement with the coomand :

recorder Node -file Node4.out -time -node 4 -dof 2 disp


Ins a file named Node4..I need to concentrate all the values(100) of the displacement in one file which i will be able to use in matlab..

Do you have a better view now? How should i pass the data in the code?
 
Forgot to say..
The displacement every time is calculated after the end of the analysis.

 
OK. You didn't need to change the text file; Tcl can split on spaces. I just inferred from your sample that the number of spaces between values was not consistent. Anyway split will use any valid character (including a space) as a delimiter. No matter. It seems we're back, then, to the original code:
Code:
set fid [open <filename> r]; #assign a channel to the file
set rowslst [split [read $fid] \n]; #make a list of lines
close $fid
set i 0
foreach rw $rowslst {
  set elmlst [split $rw ,]; #make a list of elements on each line
  set j 0
  foreach elm $elmlst {
     set A($i,$j) $elm; # assuming your array is named "A"
     incr j
  }
  incr i
}

Having done that, A(i,j) is your array of values. Now it looks from:
[tt]# Elements
element elasticBeamColumn 1 1 2 0.015 $var1 0.000028125 1
element elasticBeamColumn 2 2 3 0.015 $var2 0.000028125 1
element elasticBeamColumn 3 3 4 0.015 $var3 0.000028125 1
.
.
element elasticBeamColumn 3 3 4 0.015 $var100 0.000028125 1
[/tt]
like the numbers between elasticBeamColumn and $varn change with each element (ven though you seem to have violated that with the n=100 line. That is, each element has:
...elasticBeamColumn n n n+1 0.015 elem(n) ... where n is the element number. If that's the case, the use of the matrix can be considerably shortened:
Code:
for {set i 0} {$i<100} {incr i} {
   for {set j 0} {$j<100} {incr j} {
     set a [expr $j+1]
     set b [expr $a+1]
     element elasticBeamColumn $a $a $b 0.015 $A($i,$j) 0.000028125 1
   }
   #[red]insert the rest of your Opensees code[/red]
}

_________________
Bob Rashkin
 
Thank you my friend!

The difficult part is that i must do that so many times as the number of columns of the input data..For example, if i have in the text file the data of a matrix 2x3 it means that i have to run the analysis(put the values of the 2 variables in ) 3 times, and get 3 values for the displacement.
It means i have to create a file that will constist all the 3 values of the displacement.

example.

input data:

the elements of the array A are:
a,b,c
d,e,f

opensees code:

1st run
.
.
.
element elasticBeamColumn 1 1 2 0.015 a 0.000028125 1
element elasticBeamColumn 2 2 3 0.015 d 0.000028125 1
.
.
.
result : d1

2nd run
.
.
element elasticBeamColumn 1 1 2 0.015 b 0.000028125 1
element elasticBeamColumn 2 2 3 0.015 e 0.000028125 1
.
.
.
result : d2

3d run

.
.
element elasticBeamColumn 1 1 2 0.015 c 0.000028125 1
element elasticBeamColumn 2 2 3 0.015 f 0.000028125 1
.
.
.
result : d3



results
d1,d2,d3 : must be all together in a file because i need to use them in matlab!


I must do that so many times as the number of columns of the input data from matlab.

That is quite difficult if i have to do that 10000 times.
Is it more clear now? Can you tell me how to do that with a loop?





 
I'm afraid you've lost me.
Are you saying that you don't loop the same number of times as there are rows in your data matrix (in this case, 100)?

_________________
Bob Rashkin
 
I will have to loop the same number of times as there are columns in my data matrix. If i had one random variable (1 row) and 5 values for that random variable (5 columns) i would loop 5 times and i would find 5 displacements.
In every loop i have to pass the values of the respective column to the respective random variables.

For example.

i: number of rows
j: number of columns

for j =1 :$number of columns
.
.
for i=1:number of rows

element elasticBeamColumn 1 1 2 0.015 $A(i,j) 0.000028125 1

end i
.
.
d(j)=

end j

Is it more clear now?

I have to loop twice!

The values d(j) , i need the concentrate in one file!


 
OK, I think. In any case, you have your variable values in the matrix, A(i,j). Both i and j can take values between 0 and 99.

I don't really need to know how your Opensees code looks exactly. Think of it this way:
Code:
A bunch of statements that are the same every run
A bunch of statements that are different every run
A bunch of statements that are the same every run

For those statements that will be different each run, formulate them as:
statement=some function of A(i,J), where J is the "run number".

Then your code becomes:
Code:
for {set runNumber 0} {$runNumber<100} {incr runNumber} {
   [i]bunch of statements that don't change[/i]
   for {set varNumber 0} {$varNumber<100} {incr varNumber} {
     [b]sequence of statements as functions of A($varNumber,$runNumber)[/b]
   }
   [i]bunch of statements that don't change[/i]
}

_________________
Bob Rashkin
 

Thank you my friend!

Can you tell me how to save the results from the different runs in one file?
 
In your example above, your results are a single variable, dn, per run, where n is the run number. I would collect these in a Tcl list, say rsltLst.
Code:
for {set runNumber 0} {$runNumber<100} {incr runNumber} {
   bunch of statements that don't change
   for {set varNumber 0} {$varNumber<100} {incr varNumber} {
     sequence of statements as functions of A($varNumber,$runNumber)
   }
   bunch of statements that don't change
   [red]lappend rsltLst $d[/red]
}

Then you can output rsltLst to a file as comma-delimited elements:
Code:
set fid [open <output filename> w]
puts $fid [join $rsltLst ,]
close $fid

_________________
Bob Rashkin
 
I am back...
If i have 10 files with 1 value in every file how can i create 1 file with all the 10 values?
 
Within Tcl, itself, I don't think you can do it without opening each file (depending on your OS, you might be able to concatenate the file contents from the command line).

So, in Tcl:
Code:
set outfile [open <output file name> w]
foreach infname {<1st file> <2nd file> ... <10th file>} {
   set fid [open $infname r]
   puts $outfile [read $fid]
   close $fid
}
close $outfile

assuming that each file has the same format and that no intermediate processing has to be done. That is, this just concatenates the file contents.

_________________
Bob Rashkin
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top