用fortran写一个原始二进制无符号32位整数

问题描述 投票:1回答:1

我有一个四字节的整数,我想把它转换成一个无符号的32位整数,并写成一个原始的二进制数据(小恩迪安)。这个值将在.vtu文件中作为偏移量,在paraview中读取,根据这个模式。https:/www.paraview.orgpipermailparaview2007-October006064.html我已经尝试过ZEXT和IAND函数,但我没有成功,可能是因为我的C语言和c-fortran接口的知识是非常基本的。

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),...
...

--编辑(01052020)

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

谢谢你Vladimir F的回答。但是,我仍然收到这个错误信息。

ERROR: 在C:\bbd\ecd3383f\build/superbuild/paraview/src/VTK/\IOXML/vtkXMLUnstructuredDataReader.cxx,第466行vtkXMLUnstructuredGridReader (00000244BF849310): Cannot read points array from Points in piece 0.元素中的数据数组可能太短。

我认为问题出在我写偏移量的方式上(换句话说,Paraview没有识别有符号的整数)。我测试了三种写法和两种计算偏移量的方法(如你在代码中看到的)。我不知道哪里出了问题。我做了一个类似的子程序来打印一个.vtu ASCII文件,一个.vtk二进制文件,我都成功了。

binary fortran vtk paraview uint32
1个回答
2
投票

Fortran整数是有符号的。然而,正整数在有符号和无符号中是一样的。所以,如果你的数字是正数,就没有理由使用任何函数。如果你有一个未格式化的流文件,并且你想写一个四字节的整数,你只需要做以下操作

use iso_fortran_inv
INTEGER(kind=int32):: number

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

WRITE(vtu) number

就是这样。只要你的数字足够小,就不涉及转换函数。

如果你的数字大于最大的有符号的32位值,那真的要看你之前在Fortran中做了什么。你实际如何使用这个数字。

  • 如果它是一个负的32位整数,你想把它写成无符号的--同样,不涉及转换。只要写出有符号的数字,Paraview就会把它读成无符号的。

  • 如果你的Fortran代码使用较大的整数类型来表示Fortran中的正数,你必须进行转换。在这种情况下,你需要复制位模式,最好使用 transfer() 函数或使用旧的 equivalence.

这里有一个转换的例子。我只是强调,只有当你使用一个较大的整数种类将全值表示为正值时,才需要这样做(即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

输出是(在小二烯机器上)。

> ./a.out 
B2D05E00
B2D05E00

不要使用 int(kind=4)它是不可移动的 Fortran: integer*4 vs integer(4) vs integer(kind=4)

© www.soinside.com 2019 - 2024. All rights reserved.