2

I am trying to write a Fortran subroutine which outputs a .vtu file of raw binary data. I wrote with success a .vtk binary and .vtu ascii but in this kind of file I don´t know where is the problem. My subroutine, generated .vtu file and error message of paraview are below.

MODULE OUTPUT
IMPLICIT NONE
CONTAINS
function itoa(i) result(res)
  character(:),ALLOCATABLE :: res
  INTEGER,intent(in) :: i
  character(range(i)+2) :: tmp
  write(tmp,'(i0)') i
  res = trim(tmp)
end function
SUBROUTINE print_vtu_binary_appended(step,number_of_particles,system_name,position,velocity,radius)
use iso_fortran_env
implicit none
real(kind=real64), intent(in), dimension(number_of_particles,3) :: position, velocity
real(kind=real64), intent(in), dimension(number_of_particles) :: radius
integer(kind=int32), intent(in) :: step, number_of_particles
integer(kind=int32), dimension(6) :: offset
integer(kind=int32) :: vtu, print_number=0
character(len=*), intent(in) :: system_name

offset(1) = 0
offset(2) = offset(1) + 4 + SIZEOF(position)
offset(3) = offset(2) + 4 + SIZEOF(velocity)
offset(4) = offset(3) + 4 + SIZEOF(radius)
offset(5) = offset(4) + 4
offset(6) = offset(5) + 4
OPEN(newunit=vtu, action='write', access='stream', STATUS='new', form='unformatted', FILE='./'//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),position
WRITE(vtu)offset(2),velocity
WRITE(vtu)offset(3),radius
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
END MODULE OUTPUT
program test
use iso_fortran_env
use output
implicit none
integer(kind=int32) :: step=1, number_of_particles=2
real(kind=real64), dimension(2,3) :: position, velocity
real(kind=real64), dimension(2) :: radius
character(len=14) :: system_name='random_numbers'
position = reshape((/ 1.0754_real64, 2.0683_real64, 3.2479_real64, 4.08642_real64, 5.46906_real64, 6.36974_real64 /), shape(position))
velocity = reshape((/ 3.0754_real64, 7.0683_real64, 10.2479_real64, 72.08642_real64, 83.46906_real64, 22.36974_real64 /), shape(velocity))
radius = reshape((/ 0.0000754_real64, 0.00083_real64 /), shape(radius))
CALL print_vtu_binary_appended(step,number_of_particles,system_name,position,velocity,radius)
end program test

Sample of generated xml file:

<?xml version="1.0"?>
<VTKFile type="UnstructuredGrid" version="0.1" byte_order="LittleEndian">
<UnstructuredGrid>
<Piece NumberOfPoints="8" NumberOfCells="0">
<Points>
<DataArray name="Position" type="Float64" NumberOfComponents="3" format="appended" offset="0">
</DataArray>
</Points>
<PointData>
<DataArray type="Float64" Name="Velocity" NumberOfComponents="3" format="appended" offset="196">
</DataArray>
<DataArray type="Float64" Name="Radius" format="appended" offset="392" >
</DataArray>
</PointData>
<Cells>
<DataArray type="Int32" Name="connectivity" format="appended" offset="460">
</DataArray>
<DataArray type="Int32" Name="offsets" format="appended" offset="464">
</DataArray>
<DataArray type="UInt8" Name="types" format="appended" offset="468">
</DataArray>
</Cells>
</Piece>
</UnstructuredGrid>
<AppendedData encoding="raw">
...
</AppendedData>
</VTKFile>

Error in Paraview:

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

Ali_Sh
  • 2,667
  • 3
  • 43
  • 66
grpllrne
  • 41
  • 4
  • 1
    Please add some code (as simple as possible) that calls the subroutine so that we can actually test it. It seems that we can choose some random numbers for the arguments. Is it correct? Which would be the most simple? – Vladimir F Героям слава May 03 '20 at 11:45
  • 1
    Yes, they are random numbers. I updated the code, now it can be tested. – grpllrne May 03 '20 at 13:59
  • I can reproduce the problem. What is the exact meaning of the offsets? Could you link the format documentation? – Vladimir F Героям слава May 03 '20 at 15:35
  • The official documentation, which wasn't very clear for me [link](https://lorensen.github.io/VTKExamples/site/VTKFileFormats/#unstructuredgrid), a paraview forum post [link](https://www.paraview.org/pipermail/paraview/2007-October/006064.html) and the vtk users guide, which is the source of the first link [link](https://www.kitware.com/products/books/VTKUsersGuide.pdf). According to the vtk users guide, "offset -- If the format attribute is “appended”, this specifies the offset from the beginning of the appended data section to the beginning of this array’s data.". – grpllrne May 03 '20 at 18:10
  • when the .vtu file is save in notepad (windows) becomes readable from paraview (with the correct data). Comparing the binary files the written hex (byte) 0x0 (fortran) become 0x20 (notepad), the changes occured in the offsets. I don't know what that means neither if i did a wrong interpretation. I used HexCmp to compare. – grpllrne May 03 '20 at 19:41
  • Notepad saves text files with the CR LF endings instead of LF. But I do not know how exactly it could have changed the situation. – Vladimir F Героям слава May 03 '20 at 20:08
  • what seems to have changed, for example between the two last offsets (128,132) in hex (80 00 00 00 84) became (80 20 20 20 84). in other words a "null" char become a "space" char. That happens in all offsets and somehow become readable for paraview. After saving it in notepad the "ending indicator" remained unix(lf) – grpllrne May 03 '20 at 20:30
  • A quick search about your error lead me to this : https://stackoverflow.com/a/25729302/10219194 that can be related – Nico Vuaille May 04 '20 at 07:44
  • Same error. According to [vtk wiki](https://vtk.org/Wiki/VTK_XML_Formats) "The header-type specified may be either "UInt32" or "UInt64" and indicates the integer type used in binary data headers (see below). If no such attribute is specified (as in version 0.1) the header type is UInt32." – grpllrne May 04 '20 at 10:25
  • I can confirm that after opening and saving in notepad.exe (even on Linux) it works. – Vladimir F Героям слава May 04 '20 at 16:10

1 Answers1

1

I guess that probably the issue is caused by the end record, I suggest to use "char(10)" instead of the intrinsic "new_line".

In my library (https://github.com/szaghi/VTKFortran) I use

character(1), parameter :: end_rec = char(10) !< End-character for binary-record finalize.

EDIT

Sorry for wrong guessing, I supposed that "char(10)" was more safe because with "new_line" you can choose the kind and thus I supposed a different number of bytes termination, my bad.

Reading your code you used "offset" for both tracking appended data offset and the number of the bytes of each dataarray in the appended section. I think this is not safe: if you change your offset definition from int64 to int32 kind your test works in my current architecture (GNU Fortran 9.3.0, Linux 4.19.0-6-amd64, paraview 5.8.0).

Note also that your itao function has not a kind definition for the passed argument "i", but you are passing both int64 and int32.

I suggest to separate the definition of offset and bytes number, but for small file defining offset as int32 seems to work for me.

szaghi
  • 13
  • 5