Fortran赋值操作后出现数据丢失问题求助
Fortran派生类型复制后数据丢失问题排查请求
在Fortran中使用自定义复制子routine复制包含可分配coarray的派生类型实例后,调用后续子程序得到的结果与直接使用原实例的结果不一致,多次复制后的实例结果一致但仍与原实例不同,无法通过简单示例复现,请求排查思路。
场景示例
示例0(正常结果)
type(emulator_sp) :: I1 call do_some_things(I1,...)
示例1(结果异常)
type(emulator_sp) :: I1, I2 call copy_emulator(I2, from=I1) call do_some_things(I2,...)
示例2(结果与示例1一致但仍异常)
type(emulator_sp) :: I1, I2,I3 call copy_emulator(I2, from=I1) call copy_emulator(I3, from=I2) call do_some_things(I3,...)
相关代码
派生类型定义
type emulator_sp real, allocatable :: pars(:,:,:,:)[:] character(128), dimension(3), private :: state_var_names character(128), dimension(5), private :: forc_var_names logical :: optimized integer, dimension(2) :: train_yrs character(10) :: parnames(15) character(128) :: parunits(15) end type emulator_sp
复制子routine
! To copy one emulator to another subroutine copy_emulator(to, from) implicit none type(emulator_sp), intent(inout) :: to type(emulator_sp), intent(in) :: from integer :: shp(4) if (allocated(to%pars)) deallocate(to%pars) if (allocated(from%pars)) then shp = shape(from%pars) allocate(to%pars(shp(1), shp(2), shp(3), shp(4))[*]) to%pars = from%pars end if to%state_var_names = from%state_var_names to%forc_var_names = from%forc_var_names to%optimized = from%optimized to%train_yrs = from%train_yrs to%parnames = from%parnames to%parunits = from%parunits end subroutine copy_emulator
编译器版本
ifort (IFORT) 19.0.3.199 20190206
排查思路
- 检查coarray跨镜像同步:复制子routine仅完成本地赋值
to%pars = from%pars,若from%pars的其他镜像存在数据,副本to%pars的对应镜像未同步。可在复制后添加sync all或sync images(*),确保所有镜像数据一致。 - 验证实例复制完整性:调用
do_some_things前,逐组件对比原实例与副本的所有数据,包括pars的每个维度、每个镜像的数值,确认是否存在复制遗漏或赋值错误。 - 排查
do_some_things内部逻辑:该子程序可能依赖实例的内存地址、coarray镜像索引等隐含属性,而非仅显式数据。例如是否直接操作coarray的镜像编号,或使用了未显式复制的隐藏状态。 - 测试编译器版本兼容性:ifort 19版本较旧,存在coarray相关的已知bug(如可分配coarray复制时的内存管理问题)。可尝试升级至Intel Fortran 2021及以上版本,或使用gfortran最新版本复现问题,验证是否为编译器bug导致。
- 检测未定义行为:使用编译器调试选项(如
-check all -traceback)编译代码,运行时排查内存越界、未初始化变量等问题,复制过程或do_some_things中可能存在未定义行为引发数据异常。 - 尝试默认赋值替代自定义复制:暂时用直接赋值
I2 = I1替换copy_emulator,测试结果是否正常。Fortran 2003及以上支持派生类型默认赋值,若默认赋值后结果正常,说明自定义复制子routine存在未覆盖的细节。
内容的提问来源于stack exchange,提问作者water
相关产品推荐
相关产品推荐

