如何以Python数组风格在Fortran中处理派生类型与嵌套结构?
Fortran实现Python嵌套列表式结构的方案
要在Fortran中实现类似Python嵌套列表的可迭代、可索引访问结构,核心是用派生类型+动态数组替代带命名成员的静态派生类型,这样就能实现数组式访问、迭代和元素数量获取。以下是具体实现:
1. 定义嵌套派生类型结构
先从最底层的基函数类型开始,逐层向上构建分子的嵌套结构:
module gaussian_types implicit none ! 最底层:基函数类型,对应Python的primitive_gaussian类 type :: PrimitiveGaussian real :: alpha ! 指数参数 real :: coeff ! 收缩系数 integer :: l, m, n ! 角量子数 end type PrimitiveGaussian ! 中间层:单个原子的基组,对应Python中单个原子的基函数列表 type :: AtomBasis character(len=2) :: atom_symbol ! 原子符号(如"H"、"O") type(PrimitiveGaussian), allocatable :: pgs(:) ! 该原子的所有基函数 end type AtomBasis ! 顶层:分子结构,对应Python的molecule嵌套列表 type :: Molecule type(AtomBasis), allocatable :: atoms(:) ! 分子中的所有原子基组 end type Molecule contains ! 初始化原子基组的工具子程序 subroutine init_atom_basis(atom, symbol, pg_list) type(AtomBasis), intent(out) :: atom character(len=*), intent(in) :: symbol type(PrimitiveGaussian), intent(in) :: pg_list(:) atom%atom_symbol = symbol allocate(atom%pgs(size(pg_list))) atom%pgs = pg_list end subroutine init_atom_basis ! 初始化分子的工具子程序 subroutine init_molecule(mol, atom_list) type(Molecule), intent(out) :: mol type(AtomBasis), intent(in) :: atom_list(:) allocate(mol%atoms(size(atom_list))) mol%atoms = atom_list end subroutine init_molecule ! 动态追加基函数到原子基组(类似Python列表的append) subroutine append_pg_to_atom(atom, new_pg) type(AtomBasis), intent(inout) :: atom type(PrimitiveGaussian), intent(in) :: new_pg type(PrimitiveGaussian), allocatable :: temp(:) if (allocated(atom%pgs)) then allocate(temp(size(atom%pgs)+1)) temp(1:size(atom%pgs)) = atom%pgs temp(size(atom%pgs)+1) = new_pg deallocate(atom%pgs) call move_alloc(temp, atom%pgs) else allocate(atom%pgs(1)) atom%pgs(1) = new_pg end if end subroutine append_pg_to_atom end module gaussian_types
2. 使用示例:访问、迭代与数量获取
以下代码演示如何初始化结构、像数组一样访问属性、嵌套迭代,以及获取各层元素数量:
program test_molecule use gaussian_types implicit none type(PrimitiveGaussian) :: h_pg1, h_pg2, o_pg1 type(AtomBasis) :: h1_basis, h2_basis, o_basis type(Molecule) :: water_mol integer :: i, k ! 初始化基函数实例 h_pg1 = PrimitiveGaussian(alpha=0.5, coeff=1.0, l=0, m=0, n=0) h_pg2 = PrimitiveGaussian(alpha=0.1, coeff=0.5, l=0, m=0, n=0) o_pg1 = PrimitiveGaussian(alpha=1.0, coeff=0.8, l=0, m=0, n=0) ! 初始化原子基组 call init_atom_basis(h1_basis, "H", [h_pg1, h_pg2]) call init_atom_basis(h2_basis, "H", [h_pg1]) call init_atom_basis(o_basis, "O", [o_pg1]) ! 动态给氧原子追加一个基函数 call append_pg_to_atom(o_basis, PrimitiveGaussian(alpha=0.3, coeff=0.2, l=1, m=0, n=0)) ! 初始化水分子 call init_molecule(water_mol, [o_basis, h1_basis, h2_basis]) ! 1. 便捷访问属性(对应Python的 molecule[i][k].some_value) ! 注意:Fortran数组下标从1开始,Python从0开始,需调整索引 print *, "氧原子第2个基函数的指数:", water_mol%atoms(1)%pgs(2)%alpha ! 2. 嵌套迭代所有基函数 print *, new_line('a')//"=== 遍历所有基函数 ===" do i = 1, size(water_mol%atoms) print *, "原子", i, "(", trim(water_mol%atoms(i)%atom_symbol), "):" do k = 1, size(water_mol%atoms(i)%pgs) print *, " 基函数", k, ": alpha=", water_mol%atoms(i)%pgs(k)%alpha, & ",coeff=", water_mol%atoms(i)%pgs(k)%coeff end do end do ! 3. 获取各层元素数量 print *, new_line('a')//"=== 各层元素数量 ===" print *, "分子中的原子数:", size(water_mol%atoms) do i = 1, size(water_mol%atoms) print *, "原子", i, "的基函数数量:", size(water_mol%atoms(i)%pgs) end do ! 显式释放内存(程序结束时会自动释放,大型项目建议显式管理) deallocate(water_mol%atoms) deallocate(h1_basis%pgs, h2_basis%pgs, o_basis%pgs) end program test_molecule
3. 核心优势说明
- 数组式访问:通过
mol%atoms(i)%pgs(k)%attr实现类似Python的索引访问,完全满足便捷性需求。 - 可迭代性:结合
size()函数和do循环,直接实现嵌套迭代,解决了静态命名成员无法遍历的问题。 - 动态扩展:通过
append_pg_to_atom这类子程序,可以动态添加元素,模拟Python列表的灵活性。 - 元素数量获取:
size()函数对动态数组完全有效,直接获取各层的元素数量,替代无效的Extent()。
内容的提问来源于stack exchange,提问作者electron_correlation
相关产品推荐
相关产品推荐

