首页 > 解决方案 > Fortran 中的非表格数据结构

问题描述

我想为非表格数据构建一个数据结构。我不确定在(现代)Fortran 中这样做的正确方法是什么。

我有一组房屋数据,其中包括它们的位置(纬度、经度)和价格。我有另一个工厂数据,包括它们的位置(纬度,经度)和它们产生的污染量。对于每个房子,我需要创建一个在房子半径 5 公里内的工厂列表。不仅仅是这些工厂的数量,还有这些工厂的整个(纬度、经度、污染)向量。每个房子附近都有不同数量的工厂,从零到大约八十个不等。

MODULE someDefinitions
IMPLICIT NONE
INTEGER, PARAMETER :: N_houses=82390, N_factories=4215

TYPE house
  REAL :: lat,lon,price
  ! a few more fields which are not important here
END TYPE
TYPE factory
  REAL :: lat,lon,pollution
  ! a few more fields which are not important here
END TYPE

Contains

PURE FUNCTION haversine(deglat1,deglon1,deglat2,deglon2) RESULT (dist)
  ! Some code for computing haversine distance in meters
END FUNCTION haversine

END MODULE someDefinitions


PROGRAM createStructure
USE someDefinitions
IMPLICIT NONE

TYPE(factory), DIMENSION(N_factories) :: factories
TYPE(house), DIMENSION(N_houses) :: houses
INTEGER :: i,j
! more variables definitions as needed

! code to read houses data from the disk
! code to read factories data from the disk

DO i=1,N_houses
  DO j=1,N_factories
     !here I compute the distance between houses(i) and factories(j)
     ! If this distance<=5000 I want to add the index j to the list of indices
     ! associated with house i. How? What is the right data structure to do
     ! that? some houses have zero factories within 5000 meters from them.
     ! Some houses have about 80 factories around them. It's unbalanced.
  END DO !j
END DO !i

END PROGRAM createStructure

然后创建的结构将用于进一步的计算。N_houses x N_factories 的矩阵太大而无法保存在内存中。注意:我知道 Fortran 2008 是否有帮助。

标签: fortranfortran90

解决方案


使用太多嵌套的派生类型会变得乏味。这是一个对除所需列表之外的所有数据使用 2D 数组的示例。这类似于天真的实现的 K-Nearest Neighbors (KNN) 算法。当然,可能有更好的算法,但以下可能是一个好的开始。

program NoStrucyures
  implicit none
  type listi
    real, allocatable :: item(:,:)
  end type 

  integer, parameter :: N_houses=82390, N_factories=4215
  real :: houses(N_houses,3)
  real :: factories(N_factories,3)
  real :: distance(N_factories)
  type(listi) :: list(N_houses)
  integer :: i, j, k, within5k 

  ! Generating dummy data
  call random_number(houses)
  call random_number(factories)
  houses = houses * 500000
  factories = factories * 500000

  do i = 1, N_houses

      distance = sqrt((houses(i,1)-factories(:,1))**2 + (houses(i,2)-factories(:,2))**2)
      within5k = count( distance <= 5000 ) 

      if (within5k > 0) then 
        allocate(list(i)%item(within5k,3))
        k = 0
        do j = 1, N_factories
          if (distance(j) <= 5000) then 
            k = k + 1
            list(i)%item(k,:) = factories(j,:)
          end if
        end do 
      else 
        list(i)%item = reshape([-1, -1, -1],[1,3])
      end if 

  end do

  do i=1,10
    print *, list(i)%item
  end do 

end program NoStrucyures


推荐阅读