2

I have a four byte integer that i want to convert to a unsigned 32 bits integer and write as a raw binary data (little endian). This value will be used as a offset in a .vtu file to be read in paraview, according to this pattern https://www.paraview.org/pipermail/paraview/2007-October/006064.html I already tried ZEXT and IAND functions but i didn't had success probably because my knowledge in C language and of c-fortran interfaces are very basic. Below have a draft of what I'm attempting to do

use ISO_C_BINDING
...
INTEGER(kind=4), dimension(8):: offset=0
...
OPEN(newunit=vtu, action='write', access='stream', STATUS='new', form='unformatted', FILE=filename)
....
WRITE(vtu)char(95),ZEXT(offset(1),C_INT32_T),...
WRITE(vtu)ZEXT(offset(2),C_INT32_T),...
...

--EDIT (01/05/2020)

SUBROUTINE print_vtu_binary_appended
USE DECLARE
use iso_fortran_env
IMPLICIT NONE

INTEGER(kind=int32) :: i, vtu, print_number=0
INTEGER(kind=int32), dimension(6) :: offset

character (len=24) :: folder
IF (step==0) then
    call new_folder(folder)
END IF

offset(1) = 0
offset(2) = offset(1) + 4 + SIZEOF(preceding_position)
offset(3) = offset(2) + 4 + SIZEOF(preceding_velocity)
offset(4) = offset(3) + 4 + SIZEOF(radius)
offset(5) = offset(4) + 4
offset(6) = offset(5) + 4

!or
!offset(1) = 0
!offset(2) = offset(1) + 4 + 8*number_of_particles*3 !(double precision*no_particles*no_components)
!offset(3) = offset(2) + 4 + 8*number_of_particles*3
!offset(4) = offset(3) + 4 + 8*number_of_particles
!offset(5) = offset(4) + 4
!offset(6) = offset(5) + 4

OPEN(newunit=vtu, action='write', access='stream', STATUS='new', form='unformatted', FILE='./'//folder//'/'//TRIM(system_name)//itoa(print_number)//'.vtu')
WRITE(vtu)'<?xml version="1.0"?>'//NEW_LINE('A')
WRITE(vtu)'<VTKFile type="UnstructuredGrid" version="0.1" byte_order="LittleEndian">'//NEW_LINE('A')
WRITE(vtu)'<UnstructuredGrid>'//NEW_LINE('A')
WRITE(vtu)'<Piece NumberOfPoints="'//itoa(number_of_particles)//'" NumberOfCells="0">'//NEW_LINE('A')
WRITE(vtu)'<Points>'//NEW_LINE('A')
WRITE(vtu)'<DataArray name="Position" type="Float64" NumberOfComponents="3" format="appended" offset="'//itoa(offset(1))//'">'//NEW_LINE('A')
WRITE(vtu)'</DataArray>'//NEW_LINE('A')
WRITE(vtu)'</Points>'//NEW_LINE('A')
WRITE(vtu)'<PointData>'//NEW_LINE('A')
WRITE(vtu)'<DataArray type="Float64" Name="Velocity" NumberOfComponents="3" format="appended" offset="'//itoa(offset(2))//'">'//NEW_LINE('A')
WRITE(vtu)'</DataArray>'//NEW_LINE('A')
WRITE(vtu)'<DataArray type="Float64" Name="Radius" format="appended" offset="'//itoa(offset(3))//'" >'//NEW_LINE('A')
WRITE(vtu)'</DataArray>'//NEW_LINE('A')
WRITE(vtu)'</PointData>'//NEW_LINE('A')
WRITE(vtu)'<Cells>'//NEW_LINE('A')
WRITE(vtu)'<DataArray type="Int32" Name="connectivity" format="appended" offset="'//itoa(offset(4))//'">'//NEW_LINE('A')
WRITE(vtu)'</DataArray>'//NEW_LINE('A')
WRITE(vtu)'<DataArray type="Int32" Name="offsets" format="appended" offset="'//itoa(offset(5))//'">'//NEW_LINE('A')
WRITE(vtu)'</DataArray>'//NEW_LINE('A')
WRITE(vtu)'<DataArray type="UInt8" Name="types" format="appended" offset="'//itoa(offset(6))//'">'//NEW_LINE('A')
WRITE(vtu)'</DataArray>'//NEW_LINE('A')
WRITE(vtu)'</Cells>'//NEW_LINE('A')
WRITE(vtu)'</Piece>'//NEW_LINE('A')
WRITE(vtu)'</UnstructuredGrid>'//NEW_LINE('A')
WRITE(vtu)'<AppendedData encoding="raw">'//NEW_LINE('A')
WRITE(vtu)char(95),offset(1),preceding_position
WRITE(vtu)offset(2),preceding_velocity
WRITE(vtu)offset(3),radius
WRITE(vtu)offset(4),offset(5),offset(6)

!a different way to write
!WRITE(vtu)char(95),offset(1),(preceding_position,i=1,number_of_particles)
!WRITE(vtu)offset(2),(preceding_velocity,i=1,number_of_particles)
!WRITE(vtu)offset(3),(radius,i=1,number_of_particles)
!WRITE(vtu)offset(4),offset(5),offset(6)

!another different way
!WRITE(vtu)char(95),offset(1),(preceding_position(i,1),preceding_position(i,2),preceding_position(i,3),i=1,number_of_particles)
!WRITE(vtu)offset(2),(preceding_velocity(i,1),preceding_velocity(i,2),preceding_velocity(i,3),i=1,number_of_particles)
!WRITE(vtu)offset(3),(radius,i=1,number_of_particles)
!WRITE(vtu)offset(4),offset(5),offset(6)
WRITE(vtu)NEW_LINE('A')//'</AppendedData>'//NEW_LINE('A')
WRITE(vtu)'</VTKFile>'

CLOSE(unit=vtu)

print_number = print_number + 1

END SUBROUTINE print_vtu_binary_appended

Thank you Vladimir F for your answer. However, i still receiving this error message:

ERROR: In C:\bbd\ecd3383f\build\superbuild\paraview\src\VTK\IO\XML\vtkXMLUnstructuredDataReader.cxx, line 466 vtkXMLUnstructuredGridReader (00000244BF849310): Cannot read points array from Points in piece 0. The data array in the element may be too short.

I thought that the problem was in the way i was writing the offsets (in other words, Paraview wasn't recognizing a signed integer). I tested three ways of writing and two ways to calculate the offsets (as you can see in the code). I don't have any ideia of what went wrong. I did a similar subroutine to print a .vtu ASCII file, a .vtk binary file and i had success in both.

grpllrne
  • 41
  • 4
  • Welcome, do not use the javascript snapshot button to format your code, use the code button. – Vladimir F Героям слава Apr 30 '20 at 14:09
  • 1
    Fortran has no knowledge of unsigned integers, even with C interoperability in mind, so what are you trying to do with converting a four-byte integer to a 32-bit unsigned integer? – francescalus Apr 30 '20 at 14:16
  • You really need to have a look at the file you create to figure out specifically what's wrong with it. That will put you in a far better position to adjust the program to write output that will be accepted. – John Bollinger May 01 '20 at 23:57
  • I looked at the file and compared it to the binary file generated by paraview from the _correct_ .vtu ascii file. However, I still don't recognize the error. – grpllrne May 02 '20 at 00:09
  • Please do not share any important information on an external resource. 1. no one knows what kind of virus can be there. 2. It is not going to stay there frever and the queation will stop making sense. – Vladimir F Героям слава May 02 '20 at 06:39
  • @grpllrne Please nnote that changing tour queatioon so much, after havig received asome answers, is strongly discouraged. It is really often often better to a ask a new question. I did a partial revert. Please consider asking a new question instead. – Vladimir F Героям слава May 02 '20 at 06:41
  • Instead of linking the binary file, in your new question, make the code complete. Your current code is very incomplete. We are missing the declarations of important variables so we do not know their type and cannot know what might be wrong. – Vladimir F Героям слава May 02 '20 at 06:47

1 Answers1

2

Fortran integers are signed. However, positive integer numbers are the same in signed and unsigned. So, if your numbers are positive, there is no reason to use any function. If you have an unformatted stream file and you want to write a four byte integer, you just do

use iso_fortran_inv
INTEGER(kind=int32):: number

open(newunit=vtu, action='write', access='stream', STATUS='new', form='unformatted', FILE=filename)

WRITE(vtu) number

That's all. There are no conversion functions involved provided that your number is small enough.

If your number is larger than the maximum signed 32-bit value, it really depends on what you do in Fortran before that. How you actually use the number.

  • If it is a negative 32-bit integer number and you want to write it as unsigned - again, no conversion involved. Just write the signed number and Paraview will read it as unsigned.

  • If your Fortran code uses larger integer kinds to represent the number as positive in Fortran, you have to do a conversion. In that case you need to copy the bit pattern and that is best done using the transfer() function or using the old equivalence.

An example conversion is here. I just stress that it is only necessary when you use a larger integer kind to represent the full value as a positive one (i.e. positive for Fortran):

 use iso_fortran_env
 integer(int64) :: large
 integer(int32) :: unsigned
 integer(int32) :: tmp(2)    

 large = 3000000000_int64
 print '(z0)', large

 tmp = transfer(large, tmp)     
 unsigned = tmp(1)

 print '(z0)', unsigned
end

The output is (on a little-endian machine):

> ./a.out 
B2D05E00
B2D05E00

Do not use int(kind=4), it is not portable Fortran: integer*4 vs integer(4) vs integer(kind=4)