CFD Online Discussion Forums

CFD Online Discussion Forums (http://www.cfd-online.com/Forums/)
-   OpenFOAM Programming & Development (http://www.cfd-online.com/Forums/openfoam-programming-development/)
-   -   Cannot read 2nd column of data in libforces.so output force.dat file (http://www.cfd-online.com/Forums/openfoam-programming-development/122928-cannot-read-2nd-column-data-libforces-so-output-force-dat-file.html)

musahossein September 1, 2013 00:39

Cannot read 2nd column of data in libforces.so output force.dat file
 
Dear all:

I am using libforces.so in control dict. The output is forces.dat file and has the following format:

time ((number, number, numer), (number ...etc)

the problem is that there is NO spaces between the first pair of parenthesis and the number right after it. As a result, that number cannot be read as a number but has to be read as character. I have a FORTRAN code that reads this file, and I found that it was not possible to read the first number after the double parenthesis as a real. So my only option is to read it as character - which makes this data useless. Can the OpenFOAM creators please rewrite the code so that there is space between the number and the parenthesis?. Also, would it be possible to include the number of lines of data in the file in the first line? something like this:

# Time forces((.....)) moment ((......)) lines of data (......)

Thanks.

Thanks.

wyldckat September 1, 2013 06:57

Hi Musaddeque,

:confused: Why should the developers change the source code, when it works fine as it is? Specially when it is formatted in a way that OpenFOAM itself can easily re-read the data back into memory!
Nonetheless, what you might want to ask for is for a way to choose other output formats for the forces function object.

Either way, there are several ways you can fix this problem on your side! Some examples:
  1. You can pre-process the file with a script, to remove the parenthesis. sed and/or awk can help you with this. The simplest command I can remember is to simply use:
    Code:

    sed -i -e 's/[()]/ /g' forces.dat
    It will convert the parenthesis characters to spaces. You can search online on how to use sed and awk.
  2. In FORTRAN you can easily read the parenthesis characters with CHAR variables, therefore filtering out what you don't want.
  3. OpenFOAM is open-source! You can modify the source code for the forces function object and make it write things as you want it to!
Best regards,
Bruno

ngj September 1, 2013 07:49

Hi Musaddeque,

Please read and follow the detailed step-by-step guide, which I wrote a couple of weeks ago in this thread:

http://www.cfd-online.com/Forums/ope...utput-csv.html

Kind regards

Niels

musahossein September 1, 2013 10:58

Quote:

Originally Posted by wyldckat (Post 449167)
Hi Musaddeque,

:confused: Why should the developers change the source code, when it works fine as it is? Specially when it is formatted in a way that OpenFOAM itself can easily re-read the data back into memory!
Nonetheless, what you might want to ask for is for a way to choose other output formats for the forces function object.

Either way, there are several ways you can fix this problem on your side! Some examples:
  1. You can pre-process the file with a script, to remove the parenthesis. sed and/or awk can help you with this. The simplest command I can remember is to simply use:
    Code:

    sed -i -e 's/[()]/ /g' forces.dat
    It will convert the parenthesis characters to spaces. You can search online on how to use sed and awk.
  2. In FORTRAN you can easily read the parenthesis characters with CHAR variables, therefore filtering out what you don't want.
  3. OpenFOAM is open-source! You can modify the source code for the forces function object and make it write things as you want it to!
Best regards,
Bruno

Gentlemen: appended below are few lines from the forces.dat file.

# Time forces(pressure, viscous, porous) moment(pressure, viscous, porous)
0.00116279 ((0 65.2165 0),(-1.20232e-17 0.00107097 5.21998e-07),(0 0 0)) ((15.435 0 0),(0.000198423 2.02581e-17 8.3249e-17),(0 0 0))
0.00251938 ((0 86.7929 0),(-1.10799e-16 0.00264427 1.61168e-06),(0 0 0)) ((20.5327 0 0),(0.000532886 -2.13627e-17 -1.9528e-16),(0 0 0))
0.00410207 ((0 30.7788 0),(-1.1e-16 0.00314398 4.56226e-06),(0 0 0)) ((7.26688 0 0),(0.000714734 -5.21951e-17 6.56713e-17),(0 0 0))
0.00593798 ((0 -34.7985 0),(-8.21523e-17 0.00205407 -1.62991e-06),(0 0 0)) ((-8.2514 0 0),(0.000595282 -1.95364e-17 -1.90247e-17),(0 0 0))

Now observe the second line:

0.00116279 ((0 65.2165 0), .....

I am using fortran read command as follows:

read(......) time, char, char, forceX, forceY, forceZ etc..

Fortran hangs at char, as it cannot distinguish between the "((" and the "0" right after it and gives an error saying bad real number. So now, if I revise the read statement as:

read(...) time, char, forceY, forceZ, --- in other words treat "((0" as a char, then fortran will read it as char and move the the next number. I agree that scripts can be written to remove the parenthesis, but it does not permit an elegant solution. At the programming time, all the programmer would have had to do was to add a few spaces between the parenthesis, and between the parenthesis and the number.

wyldckat September 1, 2013 13:07

Hi Musaddeque,

Well... I had to smile a bit now... I remembered to search in the official bug tracker for OpenFOAM and found this feature request: http://www.openfoam.org/mantisbt/view.php?id=777
I found it by searching in Google with:
Code:

site:www.openfoam.org/mantisbt forces output
Therefore, the suggestion you've made has already been made 5.5 months ago as well :)


Now, as for the problem you have at the moment, the big question is: how do you want to solve this?
I ask this because:
  1. I'm very well experienced in FORTRAN 90 and know a bit the quirks of FORTRAN 77. Therefore, if you are using GNU FORTRAN (the one that comes with GCC) and tell me if you are using F77 or F90, then I can easily create the line of code that handles reading these lines.
  2. It also depends on whether you need to process the forces output, while it's still running, because there are a few possible solutions.
  3. If you prefer to have your own variant of the forces library, it's very simple to explain how you can create your own function object, derived from the original source code.
  4. If you forcefully want the original source code to be modified... then the only way that can happen with greater speed, is to acquire from the official OpenFOAM team a support contract for this particular feature.
Best regards,
Bruno

musahossein September 2, 2013 09:08

fortran read of force.dat file
 
This is what I wrote to read the lines of data. I am only interested in the x y z forces, so my read line in fortran was as follows:

character(len=20):: charA,
double precision::time, force_x, force_y, force_z

read(unit=unit_force_dat,fmt=*)

do i=1,num_dat

read(unit=unit_force_dat,fmt=*) time, charA, force_y

write(fout_gplt,100) time*3.13029, force_y/9810.0

end do

Now note the data is out put in the following format (skipping the first line):
0.1 ((0 -5.06121 0),(-3.99743e-17 -0.00915985 -0.00028693),(0 0 0)) ((-0.801432 0 0),(-0.0036854 -3.35203e-18 2.30784e-17),(0 0 0))
0.2 ((0 19.0264 0),(1.57733e-17 0.00228343 -0.000354185),(0 0 0)) ((4.92259 0 0),(0.0023383 7.10629e-18 1.67709e-18),(0 0 0))
0.3 ((0 11.5462 0),(-7.85821e-18 0.00388275 -0.000954584),(0 0 0)) ((2.82873 0 0),(0.00702285 -4.54422e-18 -1.1446e-18),(0 0 0))

So starting from the left, there is one real number, followed by space, then two parenthesis and then three real numbers. So my read statement should be:

read (...) time, charA, charB, forceX, forceY, forceZ

But it seems that the real number after the second parenthesis is so close, that fortran gives a "bad real number" error if I use this format. So the "workaround" that I have is to treat the ((0 as char and then read forceY. Perhaps you may have a better suggestion.

Thanks
Musa

wyldckat September 7, 2013 11:02

1 Attachment(s)
Hi Musaddeque,

I forgot that I haven't actually seriously programmed in FORTRAN for several years now... I'm getting old :rolleyes:.

Attached is a zip file that demonstrates how you can filter out the stuff you don't need from each line.
Since you didn't specify any compiler limitations, nor did you specify the FOTRAN standard, I simply used the one I'm familiar with.


To detail some of the aspects to this:
  1. I used gfortran that GCC provides, more specifically version 4.6.3.
  2. The FORTRAN file is named "test.f90" and the data file is named "data".
  3. The core reading and writing code:
    Code:

    CHARACTER(LEN=200):: buffer
    DOUBLE PRECISION::time, force_x, force_y, force_z
    INTEGER :: unit_force_dat=10, i, num_dat=3, fout_gplt=20

    OPEN(UNIT=unit_force_dat, FILE="data", ACTION="READ", POSITION="REWIND", ACCESS="SEQUENTIAL")
    OPEN(UNIT=fout_gplt, FILE="output.txt", ACTION="WRITE", POSITION="REWIND", ACCESS="SEQUENTIAL")

    READ(UNIT=unit_force_dat,FMT=*)

    DO i=1, num_dat

      READ(UNIT=unit_force_dat, FMT='(A)') buffer

      !Filter out the parenthesis and commas
      CALL FilterLine(buffer)

      READ(buffer, FMT=*) time, force_x, force_y, force_z
     
      WRITE(fout_gplt, *) time*3.13029, force_y/9810.0

    END DO

    CLOSE(unit_force_dat)
    CLOSE(fout_gplt)

    1. As you can see, I loaded the whole line into a long character array, to act as a buffer.
    2. Then call the subroutine "FilterLine" to remove the parenthesis and commas.
    3. Then read directly from the cleaned text line that is on the updated buffer.
  4. The subroutine is this one:
    Code:

    SUBROUTINE FilterLine(buffer)

        CHARACTER(*), INTENT(IN OUT) :: buffer
        CHARACTER(3) :: junk = "(),"
        INTEGER :: I, N
       
        DO I = 1, LEN(buffer)
           
            DO N = 1, 3
               
                IF (buffer(I:I) == " ") EXIT
                IF (buffer(I:I) == junk(N:N)) THEN
                   
                    buffer(I:I) = " "
                    EXIT
                   
                END IF
               
            END DO
       
        END DO
       
    RETURN
    END SUBROUTINE FilterLine

  5. I compiled and ran the binary like this:
    Code:

    gfortran test.f90
    ./a.out

Best regards,
Bruno

musahossein September 8, 2013 11:44

very clever! thanks.

musahossein February 21, 2015 23:08

reading force data from interDyMFOAM
 
Quote:

Originally Posted by wyldckat (Post 450396)
Hi Musaddeque,

I forgot that I haven't actually seriously programmed in FORTRAN for several years now... I'm getting old :rolleyes:.

Attached is a zip file that demonstrates how you can filter out the stuff you don't need from each line.
Since you didn't specify any compiler limitations, nor did you specify the FOTRAN standard, I simply used the one I'm familiar with.


To detail some of the aspects to this:
  1. I used gfortran that GCC provides, more specifically version 4.6.3.
  2. The FORTRAN file is named "test.f90" and the data file is named "data".
  3. The core reading and writing code:
    Code:

    CHARACTER(LEN=200):: buffer
    DOUBLE PRECISION::time, force_x, force_y, force_z
    INTEGER :: unit_force_dat=10, i, num_dat=3, fout_gplt=20

    OPEN(UNIT=unit_force_dat, FILE="data", ACTION="READ", POSITION="REWIND", ACCESS="SEQUENTIAL")
    OPEN(UNIT=fout_gplt, FILE="output.txt", ACTION="WRITE", POSITION="REWIND", ACCESS="SEQUENTIAL")

    READ(UNIT=unit_force_dat,FMT=*)

    DO i=1, num_dat

      READ(UNIT=unit_force_dat, FMT='(A)') buffer

      !Filter out the parenthesis and commas
      CALL FilterLine(buffer)

      READ(buffer, FMT=*) time, force_x, force_y, force_z
     
      WRITE(fout_gplt, *) time*3.13029, force_y/9810.0

    END DO

    CLOSE(unit_force_dat)
    CLOSE(fout_gplt)

    1. As you can see, I loaded the whole line into a long character array, to act as a buffer.
    2. Then call the subroutine "FilterLine" to remove the parenthesis and commas.
    3. Then read directly from the cleaned text line that is on the updated buffer.
  4. The subroutine is this one:
    Code:

    SUBROUTINE FilterLine(buffer)

        CHARACTER(*), INTENT(IN OUT) :: buffer
        CHARACTER(3) :: junk = "(),"
        INTEGER :: I, N
       
        DO I = 1, LEN(buffer)
           
            DO N = 1, 3
               
                IF (buffer(I:I) == " ") EXIT
                IF (buffer(I:I) == junk(N:N)) THEN
                   
                    buffer(I:I) = " "
                    EXIT
                   
                END IF
               
            END DO
       
        END DO
       
    RETURN
    END SUBROUTINE FilterLine

  5. I compiled and ran the binary like this:
    Code:

    gfortran test.f90
    ./a.out

Best regards,
Bruno

Wyldckat:

Your test file has space after the first real data and before the parenthesis. However the output from OpenFOAM has a tab. And this tab I cannot overcome! I look forward to your reply

musahossein February 21, 2015 23:43

Quote:

Originally Posted by musahossein (Post 532819)
Wyldckat:

Your test file has space after the first real data and before the parenthesis. However the output from OpenFOAM has a tab. And this tab I cannot overcome! I look forward to your reply

Bruno:
Sorry for the false alarm. The code works. I randomly put tabs and the code ignored them and got the results. I tell you, if a movie was ever made about the gods of CFD, you would be the one and only star!.

Thanks again for your help!


All times are GMT -4. The time now is 18:43.