I was working on my analysis code's input part, but I've got stuck because of multiple errors. Here is my unfinished code:
c sinle event analysis
implicit real(a-h,o-z)
real day(12), nmonth(12), year(12), clas(12),
$ hour(12), nmin(12), sec(12)
real mark(12)
real tst(12)
dimension D(12)
real time(2054904), proa(2054904), w1(2054904),
$ w2(2054904), w3(2054904), w4(2054904)
D(1) = 31, D(2) = 28, D(3) = 31, D(4) = 30, D(5) = 31,
$ D(6) = 30, D(7) = 31, D(8) = 31, D(9) = 30, D(10) = 31,
$ D(11) = 30, D(12) = 31
open(100,file='singleE.txt',status='OLD')
do i=1, 12
tst(i)=0
enddo
900 do i=1, 12
read(100, 1150) day(i), nmonth(i), year(i),
$ hour(i), nmin(i), sec(i), clas(i)
do j=12, 1, -1
if integer(nmonth(i)) == j then
tst(i) = tst(i) + D(j-1)
endif
enddo
tst(i) = tst(i) + day(i) + (year(i) - 2010)*365
$ + (hour(i) + nmin(i)/60)/24
if year(i) > 2011 then tst(i) = tst(i) + 1/365
endif
print *, day(i), nmonth(i), year(i), hour(i), nmin(i),
$ sec(i), clas(i), tst(i)
enddo
open(200,file='hole.dat',status='OLD')
950 FORMAT(F12.7,2x,E10.3,2x,E10.3,2x,E10.3,2x,E10.3,
$ 2x,E10.3,2x,E10.3)
1150 FORMAT(F2.0,1x,F2.0,1x,F4.0,1x,F2.0,1x,F2.0,4x,
$ F3.1)
end
The code is breaking up, I don't know why :(
Anyways, And here is the errors I've got:
singleA.f:13.6:
D(1) = 31, D(2) = 28, D(3) = 31, D(4) = 30, D(5) = 31,
1
Error: Unclassifiable statement at (1)
singleA.f:29.8:
if integer(nmonth(i)) == j then
1
Error: Unclassifiable statement at (1)
singleA.f:31.11:
endif
1
Error: Expecting END DO statement at (1)
singleA.f:38.7:
if year(i) > 2011 then tst(i) = tst(i) + 1/365
1
Error: Unclassifiable statement at (1)
singleA.f:39.10:
endif
1
Error: Expecting END DO statement at (1)
The main problem are the first and the second ones. The rest of them are, I think, caused by the second error. I know this is a long code, but It would be nice if somebody enlighten me of my mistake :)
This, and the lines like it
D(1) = 31, D(2) = 28, D(3) = 31, D(4) = 30, D(5) = 31,
is just not syntactically correct; in fact it's so broken the compiler can't figure out what's wrong and marks it as 'unclassifiable'.
The easy fix would be to put every statement on a separate line and lose the commas. Or you could replace , with ; which is the Fortran statement separator character.
Related
I am trying to parse an Abaqus input file and read the desired nodes into an array. I first try to compare a string and if it matches then I want to read in an unknown number of integer values from the next line.
An example of the text file is shown below. I want to read the values under nset=bf1:
** PARTS
*Part, name=Beam
*Nset, nset=bf1, instance=Beam-1
1, 2, 5, 43, 45, 48, 49, 50, 105, 106, 1189, 1190, 1191, 1192, 1193, 1194
5275, 5276, 5277, 5278
*Elset, elset=_Surf-3_SNEG, internal, instance=Beam-1
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
What I am doing right now is this
program nset_parser
implicit none
integer, parameter :: rk = selected_real_kind(10,40)
real(kind=rk), dimension(:), allocatable :: values
integer :: ios,l,val, n, nlines
character(len=80) :: file_name = 'code_check.inp'
character (len=*), parameter :: search_str = "bf1"
character(len=5096) :: input_line, line
character(len=10) :: keyword, get_keyword
logical :: h_nset=.false.
l = len(search_str)
open(unit=10, file=file_name, status="old", action='read') ! open file
do
read(10, '(a)',iostat=ios) input_line ! read the lines
if (ios /=0) exit
input_line = adjustl(input_line)
if (input_line(1:1) == '*' .and. input_line(2:2) /= '*') then ! check if it is a comment line or data line
keyword=get_keyword(input_line)
if (trim(keyword) == 'Nset') then
read(input_line,'(a)') line
val = index(line, search_str)
if (val /= 0) then
h_nset=.true.
print*, line(val:val+l-1)
end if
end if
end if
end do
close(10)
end program nset_parser
but after this I am sort of stumped.
I've rewritten my answer to be more general. This code will handle multiple lines of integers between a line with "nset=bf1" and any other line beginning '*'.
Because the lines of ints can vary in length, a 2D int array is inappropriate. Instead I am storing all the ints in a 1D array, and storing the array index of each new line.
To avoid reading everything twice, I am increasing the size of arrays on the fly if necessary.
Note that if your compiler doesn't support MOVE_ALLOC (Fortran 2003), then you'll just need to replace each call with a 'deallocate, allocate, deallocate' set.
program nset_parser
implicit none
INTEGER :: ios,l,val, i, n, nlines, comma_idx, next_idx
INTEGER, ALLOCATABLE :: my_ints(:), line_starts(:), work_ints(:)
character(len=80) :: file_name = 'code_check.inp'
character (len=*), parameter :: search_str = "bf1"
character(len=5096) :: input_line
character(len=10) :: keyword
logical :: h_nset=.false.
l = len(search_str)
ALLOCATE(line_starts(10), my_ints(1000))
next_idx = 1
nlines = 0
open(unit=10, file=file_name, status="old", action='read') ! open file
DO
! Read and adjust the line
read(10, '(a)',iostat=ios) input_line
if (ios /=0) exit
input_line = adjustl(input_line)
! Ignore blank lines
IF(LEN(TRIM(input_line))==0) CYCLE
! This section picks up any line beginning *
! and either sets or unsets h_nset
IF (input_line(1:1) == '*' .AND. input_line(2:2) /= '*') THEN ! check if it is a comment line or data line
! Use of keyword below is a little unsafe if
! keywords can be longer than 10 chars (the length of 'keyword')
! Instead, better to check if input_line(2:5) == Nset
! I left it like this in case you want to be able to check multiple
! keywords or something.
comma_idx = INDEX(input_line, ',')
keyword = input_line(2:comma_idx-1)
IF (TRIM(keyword) == 'Nset') THEN
val = INDEX(input_line, search_str)
IF (val /= 0) THEN
h_nset=.TRUE. ! Switch on when nset=bf1 line is found
CYCLE
END IF
END IF
h_nset = .FALSE. ! Only reach this point if we are in a * line which isn't nset=bf1
END IF
IF(h_nset) THEN
n = COUNT(TRANSFER(input_line, 'a', LEN(input_line)) == ",") + 1 !cast to chars and count occurrence of comma
nlines = nlines + 1
! Double size of arrays on the fly if necessary
IF(nlines > SIZE(line_starts)) THEN
ALLOCATE(work_ints(nlines * 2))
work_ints(1:SIZE(line_starts)) = line_starts
CALL MOVE_ALLOC(work_ints, line_starts)
END IF
IF(next_idx+n > SIZE(my_ints)) THEN
ALLOCATE(work_ints(2*SIZE(my_ints)))
work_ints(1:SIZE(my_ints)) = my_ints
CALL MOVE_ALLOC(work_ints, my_ints)
END IF
line_starts(nlines) = next_idx
READ(input_line, *) my_ints(next_idx:next_idx+n-1)
next_idx = next_idx + n
END IF
END DO
close(10)
! This helps with the printing below
line_starts(nlines+1) = line_starts(nlines) + n
DO i=1, nlines
PRINT *, my_ints(line_starts(i):line_starts(i+1)-1)
END DO
end program nset_parser
Problem description (think of a membership with different prices for adults and kids):
I am having two data sets, one containing age and a code. A second dataframe "decodes" the codes to numeric values dependent someone is a kid or adult. I know want to match the codes in both data sets and receive a vector that contains numeric values for each customer in the data set.
I can make this work with standard R-functionalities, but since my original data contains several million observations I would like to speed up computation using the Rcpp package.
Unfortunately I do not succeed, especially how to perform the subsetting based on a logical vector as I would do it in R. I am quite new to Rcpp and have no experience with C++ so I am maybe missing some very basic point.
I attached a minimum working example for R and appreciate any kind of help or explanation!
library(Rcpp)
raw_data = data.frame(
age = c(10, 14, 99, 67, 87, 54, 12, 44, 22, 8),
iCode = c("code1", "code2", "code3", "code1", "code4", "code3", "code2", "code5", "code5", "code3"))
decoder = data.frame(
code = c("code1","code2","code3","code4","code5"),
kid = c(0,0,0,0,100),
adult = c(100,200,300,400,500))
#-------- R approach (works, but takes ages for my original data set)
calc_value = function(data, decoder){
y = nrow(data)
for (i in 1:nrow(data)){
position_in_decoder = (data$iCode[i] == decoder$code)
if (data$age[i] > 18){
y[i] = decoder$adult[position_in_decoder]
}else{
y[i] = decoder$kid[position_in_decoder]
}
}
return(y)
}
y = calc_value(raw_data, decoder)
#--------- RCPP approach (I cannot make this one work) :(
cppFunction(
'NumericVector calc_Rcpp(DataFrame df, DataFrame decoder) {
NumericVector age = df["age"];
CharacterVector iCode = df["iCode"];
CharacterVector code = decoder["code"];
NumericVector adult = decoder["adult"];
NumericVector kid = decoder["kid"];
const int n = age.size();
LogicalVector position;
NumericVector y(n);
for (int i=0; i < n; ++i) {
position = (iCode[i] == code);
if (age[i] > 18 ) y[i] = adult[position];
else y[i] = kid[position];
}
return y;
}')
There is no need to go for C++ here. Just use R properly:
raw_data = data.frame(
age = c(10, 14, 99, 67, 87, 54, 12, 44, 22, 8),
iCode = c("code1", "code2", "code3", "code1", "code4", "code3", "code2", "code5", "code5", "code3"))
decoder = data.frame(
code = c("code1","code2","code3","code4","code5"),
kid = c(0,0,0,0,100),
adult = c(100,200,300,400,500))
foo <- merge(raw_data, decoder, by.x = "iCode", by.y = "code")
foo$res <- ifelse(foo$age > 18, foo$adult, foo$kid)
foo
#> iCode age kid adult res
#> 1 code1 10 0 100 0
#> 2 code1 67 0 100 100
#> 3 code2 14 0 200 0
#> 4 code2 12 0 200 0
#> 5 code3 54 0 300 300
#> 6 code3 99 0 300 300
#> 7 code3 8 0 300 0
#> 8 code4 87 0 400 400
#> 9 code5 44 100 500 500
#> 10 code5 22 100 500 500
That should also work for large data sets.
I have the following external file with 8 rows ad 11 columns. This file cannot be changed in anyway.
Name Sun Jupiter Saturn Uranus Neptune EarthBC Mercury Venus Mars Pluto
mass(Msun) 1.000 9.547922048e-4 2.858857575e-4 4.366245355e-5 5.151391279e-5 3.040433607e-6 1.660477111e-7 2.448326284e-6 3.227778035e-7 6.607313077e-9
a(AU) 5.20219308 9.54531447 19.19247127 30.13430686 1.00000159 0.38709889 0.72332614 1.52364259 39.80634014
e 0.04891224 0.05409072 0.04723911 0.00734566 0.01669714 0.20563613 0.00676922 0.09330305 0.25439724
I(deg) 1.30376425 2.48750693 0.77193683 1.77045595 0.00090235 7.00457121 3.39460666 1.84908137 17.12113756
M(deg) 240.35086842 045.76754755 171.41809349 293.26102612 094.81131358 242.19484206 345.30814403 330.93171908 024.68081529
w(deg) 274.15634048 339.60245769 098.79773610 255.50375800 286.84104687 029.14401042 054.54948603 286.56509772 114.39445491
OMEGA(deg) 100.50994468 113.63306105 073.98592654 131.78208581 176.14784451 048.32221297 076.66204037 049.53656349 110.32482041
This file is read by the following program which compiles properly
program readtable
implicit none
integer :: i, j, num_col, num_row
double precision, dimension (8,11) :: a
character(14), dimension (8) :: par
num_col = 4
num_row = 8
open(100,file='SSL.dat',status='old')
do j=1, num_row
read(100,*) par(j), (a(i,j), i=1,num_col)
end do
print *, par
print *, a(2,3) !Jupiter's Mass
end program
When I run this program as Fortran90 I get the following message:
At line 14 of file test.f (unit = 100, file='SSL.dat')
Fortran runtime error: Bad real number in item 2 of list input
I think I need to make a FORMAT() statement to help the program read the file properly but I can't seem to get the format right.
As agentp said list directed is fine here, you just have to account for the first 2 lines being different. I'd do it it something like (slight guess here - I'm not 100% convinced I understand what you want):
ian-admin#agon ~/test $ cat r.f90
Program readtable
Implicit None
Integer, Parameter :: wp = Selected_real_kind( 13, 70 )
Integer :: i, j, num_col, num_row
Real( wp ) :: msun
Real( wp ), Dimension (9,11) :: a
Character(14), Dimension (8) :: par
num_col = 9
num_row = 7
Open( 100, file = 'SSL.dat', status = 'old' )
Read( 100, * )
j = 1
Read( 100, * ) par(j), msun, (a(i,j), i=1,num_col)
Do j = 2, num_row
Read(100,*) par(j), (a(i,j), i=1,num_col)
End Do
Write( *, * ) par
Write( *, * ) a(2,3) !Jupiter's Mass
End Program readtable
ian-admin#agon ~/test $ gfortran -std=f2003 -Wall -Wextra -O -fcheck=all r.f90
ian-admin#agon ~/test $ ./a.out
mass(Msun) a(AU) e I(deg) M(deg) w(deg) OMEGA(deg)
5.4090720000000002E-002
I'm trying to make a program that print every 100K-th odd prime number until 10M using Potion, my code:
last = 3
res = (last) # create array
loop:
last += 2
prime = true
len = res length -1
i = 0
while(i<len):
v = res at(i)
if(v*v > last): break.
if(last%v == 0): prime = false, break.
i += 1
.
if(prime):
res append(last)
if(res size % 100000 == 0): last print.
if(last>9999999): break.
.
.
But this gives Segmentation fault (core dumped), I wonder what's wrong?
For reference, the working Ruby version:
res = [last=3]
loop do
last += 2
prime = true
res.each do |v|
break if v*v > last
if last % v == 0
prime = false
break
end
end
if prime
res << last
puts last if res.length % 100000 == 0
break if last > 9999999
end
end
The output should be:
1299721
2750161
4256249
5800139
7368791
8960467
and no, this is not a homework, just out of curiosity.
you found it out by yourself, great!
println is called say in potion.
And it crashed in res size.
E.g. use this for debbugging:
rm config.inc
make DEBUG=1
bin/potion -d -Dvt example/100thoddprime.pn
and then press enter until you get to the crash.
(example/100thoddprime.pn:18): res append(last)
>
; (3, 5)
[95] getlocal 1 1 ; (3, 5)
[96] move 2 1 ; (3, 5)
[97] loadk 1 5 ; size
[98] bind 1 2 ; function size()
[99] loadpn 3 0 ; nil
[100] call 1 3Segmentation fault
so size on res returned nil, and this caused the crash.
And instead of last print, "\n" print.
Just do last say.
This came from perl6 syntax, sorry :)
My bad, I forgot to change from res length -1 to res length when changing from 0 to len (i), because this syntax not recognized as a loop (failed to receive break).
last = 3
res = (last)
loop:
last println
last += 2
prime = true
len = res length
i = 0
while(i<len):
v = res at(i)
if(v*v > last): break.
if(last%v == 0): prime = false, break.
i += 1
.
if(prime):
res append(last)
if(res length % 100000 == 0): last print, "\n" print.
if(last>9999999): break.
.
.
I have a string like "0189", for which I need to generate all subsequences, but the ordering of the individual characters must be kept, i.e, here 9 should not come before 0, 1 or 8. Ex: 0, 018, 01, 09, 0189, 18, 19, 019, etc.
Another example is "10292" for which subsequences would be: 1, 10, 02, 02, 09, 29, 92, etc. As you might have noticed '02' two times, since '2' comes twice in the given string. But again things like: 21, 01, 91 are invalid as order is to be maintained.
Any algorithm or psuedo code, which could be implemented in C/C++ would be appreciated!
Try a recursive approach:
the set of subsequences can be split into the ones containing the first character and the ones not containing it
the ones containing the first character are build by appending that character to the subsequences which don't contain it (+ the subsequence which contains only the first character itself)
I'd recommend using the natural correspondence between the power set of a sequence and the set of binary numbers from 0 to 2^n - 1, where n is the length of the sequence.
In your case, n is 4, so consider 0 = 0000 .. 15 = 1111; where there is a 1 in the binary expression include the corresponding item from the sequence. To implement this you'll need bitshift and binary operations:
for (int i = 0; i < (1 << n); ++i) {
std::string item;
for (j = 0; j < n; ++j) {
if (i & (1 << j)) {
item += sequence[j];
}
}
result.push_back(item);
}
Also consider how you'd handle sequences longer than can be covered by an int (hint: consider overflow and arithmetic carry).
In Python:
In [29]: def subseq(s): return ' '.join((' '.join(''.join(x) for x in combs(s,n)) for n in range(1, len(s)+1)))
In [30]: subseq("0189")
Out[30]: '0 1 8 9 01 08 09 18 19 89 018 019 089 189 0189'
In [31]: subseq("10292")
Out[31]: '1 0 2 9 2 10 12 19 12 02 09 02 29 22 92 102 109 102 129 122 192 029 022 092 292 1029 1022 1092 1292 0292 10292'
In [32]:
__author__ = 'Robert'
from itertools import combinations
g = combinations(range(4), r=2)
print(list(g)) #[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
def solve(string_):
n = len(string_)
for repeat in range(1, len(string_) + 1):
combos = combinations(range(len(string_)), r=repeat)
for combo in combos:
sub_string = "".join(string_[i] for i in combo)
yield sub_string
print(list(solve('0189'))) #['0', '1', '8', '9', '01', '08', '09', '18', '19', '89', '018', '019', '089', '189']
#using recursion
def solve2(string_, i):
if i >= len(string_):
return [""] #no sub_strings beyond length of string_
character_i = string_[i]
all_sub_strings = solve2(string_, i + 1)
all_sub_strings += [character_i + sub_string for sub_string in all_sub_strings]
return all_sub_strings
print(solve2('0189', 0)) #['', '9', '8', '89', '1', '19', '18', '189', '0', '09', '08', '089', '01', '019', '018', '0189']