【问题标题】:write a raw binary unsigned 32bit integer in fortran在 fortran 中写一个原始的二进制无符号 32 位整数
【发布时间】:2020-08-14 19:14:02
【问题描述】:

我有一个四字节整数,我想将其转换为无符号 32 位整数并作为原始二进制数据(小端序)写入。根据此模式https://www.paraview.org/pipermail/paraview/2007-October/006064.html,此值将用作要在 paraview 中读取的 .vtu 文件中的偏移量 我已经尝试过 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),...
...

--编辑 (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

感谢弗拉基米尔 F 的回答。但是,我仍然收到此错误消息:

错误:在 C:\bbd\ecd3383f\build\superbuild\paraview\src\VTK\IO\XML\vtkXMLUnstructuredDataReader.cxx 中,第 466 行 vtkXMLUnstructuredGridReader (00000244BF849310): 无法从第 0 片的点中读取点数组。元素中的数据数组可能太短。

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

【问题讨论】:

  • 欢迎,不要使用javascript快照按钮来格式化你的代码,使用代码按钮。
  • Fortran 对无符号整数一无所知,即使考虑到 C 互操作性,那么您将如何将四字节整数转换为 32 位无符号整数?
  • 您确实需要查看您创建的文件以明确找出其中的问题所在。这将使您处于一个更好的位置来调整程序以编写将被接受的输出。
  • 我查看了该文件并将其与 paraview 从 正确 .vtu ascii 文件生成的二进制文件进行了比较。但是,我仍然无法识别错误。
  • 请不要分享有关外部资源的任何重要信息。 1. 没有人知道会有什么样的病毒。 2.它不会一直呆在那里,问题将不再有意义。

标签: binary fortran uint32


【解决方案1】:

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

输出是(在 little-endian 机器上):

> ./a.out 
B2D05E00
B2D05E00

不要使用int(kind=4),它不可移植Fortran: integer*4 vs integer(4) vs integer(kind=4)

【讨论】:

  • 感谢您的回答,但我仍然收到来自 Paraview 的相同错误消息。我编辑了我的帖子并添加了用于在 fortran 中打印 .vtu 文件的子例程。
  • 查看问题下的 cmets。
猜你喜欢
  • 1970-01-01
  • 2013-06-21
  • 2014-07-15
  • 2011-01-31
  • 2012-07-27
  • 2011-06-02
  • 2018-03-17
  • 2012-05-24
  • 2011-03-09
相关资源
最近更新 更多