I have an array of floating point numbers and want to write the values to a file. Then read them back.
I am writing to the file as follows
Do k = 1, nk
Do j = 1, nj
Write (u,*) (lec(i,j,k), i = 1, ni)
End Do
End Do
This writes the numbers as follows when
ni = 5, nj = 4 and nk = 2.
1.1 1.2 1.3 1.4 1.5
2.1 2.2 2.3 2.4 2.5
3.1 3.2 3.3 3.4 3.5
4.1 4.2 4.3 4.4 4.5
1.1 1.2 1.3 1.4 1.5
2.1 2.2 2.3 2.4 2.5
3.1 3.2 3.3 3.4 3.5
4.1 4.2 4.3 4.4 4.5
I want to change the format of the output file in the following way
lec: 1.1 1.2 1.3 1.4 1.5
+ 2.1 2.2 2.3 2.4 2.5
+ 3.1 3.2 3.3 3.4 3.5
+ 4.1 4.2 4.3 4.4 4.5
+ 1.1 1.2 1.3 1.4 1.5
+ 2.1 2.2 2.3 2.4 2.5
+ 3.1 3.2 3.3 3.4 3.5
+ 4.1 4.2 4.3 4.4 4.5
How can I modify the code to get this form of output?
I read things the same way, but I read the values in lec only when I encounter key lec: in the file.
Do k = 1, nk
Do j = 1, nj
if(k.eq.1.and.j.eq.1)then
write(u,'(a)',advance='no')'lec:'
else
write(u,'(a)',advance='no')'+'
endif
Write (u,*) (lec(i,j,k), i = 1, ni)
End Do
End Do
or
Do k = 1, nk
Do j = 1, nj
if(k.eq.1.and.j.eq.1)then
write(u,'(a,99f4.1))'lec:',(lec(i,j,k), i = 1, ni)
else
write(u,'(a,99f4.1)')'+',(lec(i,j,k), i = 1, ni)
endif
End Do
End Do
the 99 can be any number larger than ni or * if your compiler supports it.
Related
Using julia, I want to select the first x rows of an array per group.
In the following example, I want the first two rows where the second column is equal to 1.0, then the first two rows where the second column is equal to 2.0, etc.
XX = [repeat([1.0], 6) vcat(repeat([1.0], 3), repeat([2.0], 3))]
XX2 = [repeat([2.0], 6) vcat(repeat([3.0], 3), repeat([4.0], 3))]
beg = [XX;XX2]
> 12×2 Matrix{Float64}:
> 1.0 1.0
> 1.0 1.0
> 1.0 1.0
> 1.0 2.0
> 1.0 2.0
> 1.0 2.0
> 2.0 3.0
> 2.0 3.0
> 2.0 3.0
> 2.0 4.0
> 2.0 4.0
> 2.0 4.0
The final array would look like this:
8×2 Matrix{Float64}:
1.0 1.0
1.0 1.0
1.0 2.0
1.0 2.0
2.0 3.0
2.0 3.0
2.0 4.0
2.0 4.0
I use the following code, but I am not sure whether there is a simpler way (one function) that does already that in a more efficient way?
x = []
for val in unique(beg[:,2])
x = append!(x, findfirst(beg[:,2].==val))
end
idx = sort([x; x.+1])
final = beg[idx, :]
Assuming your data:
is sorted (i.e. groups are forming continuous blocks)
each group is guaranteed to have at least two elements
(your code assumes both)
then you can generate idx filter that you want in the following way:
idx == [i for i in axes(beg, 1) if i < 3 || beg[i, 2] != beg[i-1, 2] || beg[i, 2] != beg[i-2, 2]]
If you cannot assume either of the above please comment and I can show a more general solution.
EDIT
Here is an example without using any external packages:
julia> using Random
julia> XX = [repeat([1.0], 6) vcat(repeat([1.0], 3), repeat([2.0], 3))]
6×2 Matrix{Float64}:
1.0 1.0
1.0 1.0
1.0 1.0
1.0 2.0
1.0 2.0
1.0 2.0
julia> XX2 = [repeat([2.0], 7) vcat(repeat([3.0], 3), repeat([4.0], 3), 5.0)] # last group has length 1
7×2 Matrix{Float64}:
2.0 3.0
2.0 3.0
2.0 3.0
2.0 4.0
2.0 4.0
2.0 4.0
2.0 5.0
julia> beg = [XX;XX2][randperm(13), :] # shuffle groups so they are not in order
13×2 Matrix{Float64}:
2.0 3.0
1.0 2.0
2.0 4.0
2.0 3.0
2.0 4.0
2.0 5.0
2.0 3.0
1.0 2.0
1.0 2.0
1.0 1.0
1.0 1.0
2.0 4.0
1.0 1.0
julia> x = Dict{Float64, Vector{Int}}() # this will store indices per group
Dict{Float64, Vector{Int64}}()
julia> for (i, v) in enumerate(beg[:, 2]) # collect the indices
push!(get!(x, v, Int[]), i)
end
julia> x
Dict{Float64, Vector{Int64}} with 5 entries:
5.0 => [6]
4.0 => [3, 5, 12]
2.0 => [2, 8, 9]
3.0 => [1, 4, 7]
1.0 => [10, 11, 13]
julia> idx = sort!(mapreduce(x -> first(x, 2), vcat, values(x))) # get first two indices per group in ascending order
9-element Vector{Int64}:
1
2
3
4
5
6
8
10
11
I'm a Julia beginner (scripting beginner too).
I have a text file which consists in 4 columns:
1 5.4 9.5 19.5
2 5.4 9.4 20.6
2 6.2 9.6 18.3
1 9.1 0.5 17.2
2 8.5 1.4 19.6
2 8.4 0.6 24.1
etc.
I have no idea how in Julia I can replace certain values in the rows or add a new one according to a existing column pattern 122 122. For example I would like to add the column with letter C and O (C when is 1 in the first column and O when is 2). I would like to add new column after the one with C and O where the pattern 1 2 2 is designated by number 4 and next by number 5. This is how I imagine the result:
C 4 1 5.4 9.5 19.5
O 4 2 5.4 9.4 20.6
O 4 2 6.2 9.6 18.3
C 5 1 9.1 0.5 17.2
O 5 2 8.5 1.4 19.6
O 5 2 8.4 0.6 24.1
Thank you for your help in advance.
Kasia.
String processing is fairly straightforward in Julia. You might write a function that takes an input and output filename as follows:
function munge_file(in::AbstractString, out::AbstractString)
# open the output file for writing
open(out, "w") do out_io
# open the input file for reading
open(in, "r") do in_io
# and process the contents
munge_file(in_io, out_io)
end
end
end
Now, the inner call to munge_file will have to do the actual work (this isn't particularly optimized, but should very straightforward):
function munge_file(input::IO, io::IO = IOBuffer())
# initialize the pattern index
pattern_index = 3
# iterate over each line of the input
for line in eachline(input)
# skip empty lines
isempty(line) && continue
# split the current line into parts
parts = split(line, ' ')
# this line doesn't conform to the specified input pattern
# might be better to throw an error here
length(parts) == 4 || continue
# this line starts a new pattern if the first character is a 1
is_start = parse(Int, parts[1]) == 1
# increment the counter (for the second output column)
pattern_index += is_start
# first column depends on whether a 1 2 2 pattern starts here or not
print(io, is_start ? 'C' : 'O')
print(io, ' ')
# print the pattern counter
print(io, pattern_index)
print(io, ' ')
# print the original line
println(io, line)
end
return io
end
Using the code in the REPL produces the expected output:
shell> cat input.txt
1 5.4 9.5 19.5
2 5.4 9.4 20.6
2 6.2 9.6 18.3
1 9.1 0.5 17.2
2 8.5 1.4 19.6
2 8.4 0.6 24.1
julia> munge_file("input.txt", "output.txt")
IOStream(<file output.txt>)
shell> cat output.txt
C 4 1 5.4 9.5 19.5
O 4 2 5.4 9.4 20.6
O 4 2 6.2 9.6 18.3
C 5 1 9.1 0.5 17.2
O 5 2 8.5 1.4 19.6
O 5 2 8.4 0.6 24.1
Assuming your file is input.txt you could do:
open("output.txt","w") do f
println.(Ref(f),replace.(replace.(readlines("input.txt"),r"^1 "=>"C "), r"^2 "=>"O "))
end;
Dots (.) in the above code vectorize it so functions work on vectors rather than scalars. The replace function takes a String, regular expression and new value. ^ in regular expression means "line starts with".
I have a function that takes a 2d array as an input, and outputs the array with the sign of random coordinates flipping. I want to repeat this function n times, with it taking the output of the function as the input for the next time. How am i able to do this? The array S is an n*n array of randomised 1s and -1s
Thermal<-function(S,t=0.000000000001,k=1){
#Defing beta
beta<-1/(k*t)
#multiplying each point of the array by all its adjacent points
#and summing them
Spointenergy<-S*((S2)+(S3)+S4+S5)
#Creating a loop over the whole array
for(i in 1:n){
for (j in 1:n){
#defining the change in energy at each point
dE<-energychange(S,i,j)
#By default each point does not flip
accept<-FALSE
#If energy decreases spin flip occurs 100% of the time
if (dE<0){
accept<-TRUE
}
#If energy increases a spin flip will occur if w is greater than or equal
#to u.
if (dE>=0){
w<-exp(-beta*dE)
u<-runif(1,0,1)
if (w>=u){
accept<-TRUE
}
}
#If no spin flip occurs there is no change in energy
if (accept==FALSE){
dE<-0
}
#if spin flip does occur then the magnitude of each lattice point is flipped
#from positive to negative or visa versa
if (accept==TRUE){
S[i,j]<--S[i,j]
}
}
}
return(S)
}
Maybe you can add the S to the global environment with <<- and then run a loop:
Thermal<-function(S,t=0.000000000001,k=1){
#Defing beta
beta<-1/(k*t)
#multiplying each point of the array by all its adjacent points
#and summing them
Spointenergy<-S*((S2)+(S3)+S4+S5)
#Creating a loop over the whole array
for(i in 1:n){
for (j in 1:n){
#defining the change in energy at each point
dE<-energychange(S,i,j)
#By default each point does not flip
accept<-FALSE
#If energy decreases spin flip occurs 100% of the time
if (dE<0){
accept<-TRUE
}
#If energy increases a spin flip will occur if w is greater than or equal
#to u.
if (dE>=0){
w<-exp(-beta*dE)
u<-runif(1,0,1)
if (w>=u){
accept<-TRUE
}
}
#If no spin flip occurs there is no change in energy
if (accept==FALSE){
dE<-0
}
#if spin flip does occur then the magnitude of each lattice point is flipped
#from positive to negative or visa versa
if (accept==TRUE){
S[i,j]<--S[i,j]
}
}
}
return(S)
S<<-S
}
for (x in 1:10) {
Thermal(S)
}
S
Example with iris dataset:
> iris_num <- iris[,-5]
> head(iris_num)
Sepal.Length Sepal.Width Petal.Length Petal.Width
1 5.1 3.5 1.4 0.2
2 4.9 3.0 1.4 0.2
3 4.7 3.2 1.3 0.2
4 4.6 3.1 1.5 0.2
5 5.0 3.6 1.4 0.2
6 5.4 3.9 1.7 0.4
>
> testfunction <- function(iris_num)
+ {
+ iris_num <<- iris_num + 1
+ }
>
> testfunction(iris_num)
> head(iris_num)
Sepal.Length Sepal.Width Petal.Length Petal.Width
1 6.1 4.5 2.4 1.2
2 5.9 4.0 2.4 1.2
3 5.7 4.2 2.3 1.2
4 5.6 4.1 2.5 1.2
5 6.0 4.6 2.4 1.2
6 6.4 4.9 2.7 1.4
>
> for (x in 1:10) {
+ testfunction(iris_num)
+ }
>
> head(iris_num)
Sepal.Length Sepal.Width Petal.Length Petal.Width
1 16.1 14.5 12.4 11.2
2 15.9 14.0 12.4 11.2
3 15.7 14.2 12.3 11.2
4 15.6 14.1 12.5 11.2
5 16.0 14.6 12.4 11.2
6 16.4 14.9 12.7 11.4
>
I try to calculate a mean value of 10 matrix entries (1:10, 2:11, 3:12 and so on) and then make a new matrix out of these mean values. However, it always gives me Invalid Index.
A=rand(150,1);
number_of_rows=size(A,1);
for i=1:number_of_rows
B=mean(A(i:i+9,1),1);
C(i,:)=B;
end
The trivial following code does it, for any window's length n:
A = grand(1,40,"uin",0,9)
n = 10;
C = [0 cumsum(A)];
C = (C(n+1:$)-C(1:$-n))/n
Result (sample):
--> A = grand(1,40,"uin",0,9)
A =
column 1 to 24
3. 2. 2. 9. 2. 6. 1. 5. 1. 5. 7. 2. 5. 8. 3. 0. 3. 8. 3. 3. 4. 8. 8. 1.
column 25 to 40
4. 2. 0. 8. 5. 8. 5. 3. 7. 3. 1. 8. 8. 0. 0. 4.
--> n = 10;
--> C = [0 cumsum(A)];
--> C = (C(n+1:$)-C(1:$-n))/n
C =
column 1 to 20
3.6 4. 4. 4.3 4.2 4.3 3.7 3.9 4.2 4.4 4.2 3.9 4.5 4.8 4.1 4.2 4.4 4.1 4.1 4.3
column 21 to 31
4.8 4.9 4.4 4.3 4.5 4.2 4.8 5.6 4.8 4.3 3.9
--> mean(A(1:n))
ans =
3.6
However, cumsum() would propagate any Inf or NaN value belonging to A.
I have a data file with 4 columns:
x y u v
such that x and y are the coordinate positions associated to the values u and v.
The data is structured such that
x y u v
1 1 # #
2 1 # #
3 1 # #
...
However, I would like to restructure the file such that
x y u v
1 1 # #
1 2 # #
1 3 # #
...
Is there a function in fortran which can achieve this?
Well, I never make claims about "pretty," but it should do the job. Obviously, you will need to check your FORMAT statements:
PROGRAM TEST
REAL*8 :: U(4,4)
REAL*8 :: V(4,4)
INTEGER :: X, Y
DO
READ(*,'(2I2)',ADVANCE='NO',END=10) X,Y
READ(*,'(2F6.1)',ADVANCE='YES',END=10) U(X,Y),V(X,Y)
END DO
10 CONTINUE
WRITE(*,'(2I4,2F10.2)') ((I,J,U(I,J),V(I,J),J=1,4),I=1,4)
END
I'm assuming that your arrays are already allocated properly.
Here's my input file:
$ cat test.in
1 1 5.0 10.0
2 1 1.3 -0.2
3 1 5.1 0.0
4 1 -9.1 3.0
1 2 4.0 2.0
2 2 14.0 -8.0
3 2 -8.0 8.0
4 2 4.0 9.6
1 3 2.0 1.1
2 3 3.4 8.0
3 3 4.0 7.0
4 3 4.0 4.1
1 4 5.5 8.4
2 4 34.1 23.0
3 4 -4.1 4.0
4 4 6.0 8.4
And the output:
$ cat test.in | ./a.out
1 1 5.0 10.0
1 2 4.0 2.0
1 3 2.0 1.1
1 4 5.5 8.4
2 1 1.3 -0.2
2 2 14.0 -8.0
2 3 3.4 8.0
2 4 34.1 23.0
3 1 5.1 0.0
3 2 -8.0 8.0
3 3 4.0 7.0
3 4 -4.1 4.0
4 1 -9.1 3.0
4 2 4.0 9.6
4 3 4.0 4.1
4 4 6.0 8.4