1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CoArray Fortran で Mandelbrot (再々) 

Last updated at Posted at 2018-02-28

CoArray Fortran で Mandelbrot

以前もやりましたが、しつこくやります。
https://qiita.com/cure_honey/items/3af353390fe913ae86a9

本質的には変わりはありませんが、Fortran 2008 の submodule を使ったりしています。またcoarray の使い方を少し変えています。Mandelbrot 図形計算も、すこし変えてあります。

parameterized type は使い方が難しく、OO の type-bound procedure にし難く、coarray とのつながりも分かりにくいです。parameterized type は、型種 KIND を実行時パラメータに出来て動的に変えられる点で他に無い機能を持ちますが、配列の大きさを変えるのは、素直に allocate でやった方がいいかも知れません。まだ判断つきかねます。

実行結果

intel fortran ver. 18.0.1 で実行しています。submodule は、まだバグ?が残っている感じです。optional 変数を認識しないとか、type-bound procedure を procedure :: wr => wr_bmp のようにポインタで結ぼうとすると、Linker がうまく見つけられなくて Linker エラーが出ます。

image 1 writing..
image 2 writing..
image 3 writing..
image 4 writing..
image 5 writing..
image 6 writing..
image 7 writing..
image 8 writing..
続行するには何かキーを押してください . . .

mandel.png

ソース・プログラム

fortran2008 の新知識をありったけぶち込んでみました。明示的に coarray 命令を使っているところにはコメントをつけておきました。抜けてたらごめんなさいw 

追記:文法上の警告を減らすようにニ三か所修正しました。内容的には変化ありません。

    module m_bmp
      implicit none
      private
      public :: t_bmp, rd_bmp, to_rgb
      type :: t_rgb
        sequence
        character :: b = char(0), g = char(0), r = char(0)
      end type t_rgb 

      type :: t_bmp(nx, ny)
        integer, len :: nx = 0, ny = 0  
        type (t_rgb) :: rgb(nx, ny)
      contains 
        generic :: wr => wr_bmp
        procedure :: wr_bmp
        procedure :: wr_header
      end type  
!
      interface assignment(=)
        module procedure :: assign_bmp
      end interface assignment(=) 

      interface t_bmp
        module procedure :: construct_bmp
      end interface t_bmp
!
      interface  
        module function construct_bmp(nx, ny) result(res)
          integer, intent(in) :: nx, ny
          type (t_bmp(:, :)), allocatable :: res
        end function construct_bmp    

        module subroutine assign_bmp(dest, src) 
          type (t_bmp(:, :)), intent(out), allocatable :: dest
          type (t_bmp(*, *)), intent(in ) :: src
        end subroutine assign_bmp

        module subroutine wr_bmp(bmp, fn)
          class (t_bmp(*, *)), intent(in) :: bmp
          character (len = *), intent(in) :: fn
        end subroutine wr_bmp

        module subroutine wr_header(bmp, fn)
          class (t_bmp(*, *)), intent(in) :: bmp
          character (len = *), intent(in) :: fn
        end subroutine wr_header

        module function rd_bmp(fn) result(bmp)
          character (len = *), intent(in) :: fn
          type (t_bmp(:, :)), allocatable :: bmp
        end function rd_bmp
      end interface  
    contains
    ! convert to t_RGB    
      pure elemental type(t_rgb) function to_rgb(ir, ig, ib)
        integer, intent(in) :: ir, ig, ib
        to_rgb = t_rgb(achar(ib), achar(ig), achar(ir))
      end function to_rgb  
    end module m_bmp

    submodule (m_bmp) m_bmp_body
      use, intrinsic :: iso_fortran_env
      implicit none
      type :: t_bmp_file_header
        sequence  
        integer(int16) :: bfType = transfer('BM', 0_int16) ! BitMap
        integer(int32) :: bfSize          ! file size in bytes
        integer(int16) :: bfReserved1 = 0 ! always 0
        integer(int16) :: bfReserved2 = 0 ! always 0
        integer(int32) :: bfOffBits
      end type t_bmp_file_header
      !
      type :: t_bmp_info_header
        sequence
        integer(int32) :: biSize          = Z'28' ! size of bmp_info_header ; 40bytes 
        integer(int32) :: biWidth
        integer(int32) :: biHeight
        integer(int16) :: biPlanes        = 1 ! always 1
        integer(int16) :: biBitCount
        integer(int32) :: biCompression   = 0 !0:nocompression,1:8bitRLE,2:4bitRLE,3:bitfield
        integer(int32) :: biSizeImage
        integer(int32) :: biXPelsPerMeter = 3780 ! 96dpi
        integer(int32) :: biYPelsPerMeter = 3780 ! 96dpi 
        integer(int32) :: biClrUsed       = 0
        integer(int32) :: biClrImportant  = 0 
      end type t_bmp_info_header
    contains   
      module procedure construct_bmp
        allocate(t_bmp(nx, ny)::res)
      end procedure construct_bmp    

      module procedure assign_bmp
        allocate(dest, source = src)
      end procedure assign_bmp    

      module procedure wr_header
        type (t_bmp_file_header) :: bmp_file_header
        type (t_bmp_info_header) :: bmp_info_header
        integer :: i, j, iw
        associate(nx => bmp%nx, ny => bmp%ny * num_images())                          ! coarray
          bmp_file_header%bfSize      = 14 + 40 + 0 + (3 * nx + mod(nx, 4)) * ny 
          bmp_file_header%bfOffBits   = 14 + 40
          bmp_info_header%biWidth     = nx
          bmp_info_header%biHeight    = ny 
          bmp_info_header%biBitCount  = 24 
          bmp_info_header%biSizeImage = (3 * nx + mod(nx, 4)) * ny 
          open(newunit = iw, file = fn//'.bmp', access = 'stream', status = 'replace')
          write(iw) bmp_file_header
          write(iw) bmp_info_header
          close(iw)
        end associate
      end procedure wr_header

      module procedure wr_bmp
        integer :: i, j, iw
        associate(nx => bmp%nx, ny => bmp%ny)
          open(newunit = iw, file = fn//'.bmp', access = 'stream', status = 'unknown', position = 'append')
          write(iw) (bmp%rgb(:, i), (achar(0), j = 1, mod(nx, 4)), i = 1, ny)
          close(iw)
        end associate  
      end procedure wr_bmp

      module procedure rd_bmp
        type (t_bmp_file_header) :: bmp_file_header
        type (t_bmp_info_header) :: bmp_info_header
        integer :: i, j, ir
        character :: dummy
        associate(nx => bmp_info_header%biWidth, ny => bmp_info_header%biHeight)
          open(newunit = ir, file = fn//'.bmp', access = 'stream', status = 'old')
          read(ir) bmp_file_header
          read(ir) bmp_info_header
          bmp = t_bmp(nx, ny)
          read(ir) (bmp%rgb(:, i), (dummy, j = 1, mod(nx, 4)), i = 1, ny)
          close(ir)
        end associate
      end procedure rd_bmp
    end submodule m_bmp_body

    program mandel
      implicit none
      integer, parameter :: nx = 1279, ny = 1280, maxiter = 255
      real   , parameter :: x0 = -2.0, x1 = 1.0, y0 = -1.5, y1 = 1.5
      complex, allocatable :: c(:, :)[:], z(:, :)[:]                ! coarray
      integer :: i, j, me, ni, my, iter
      integer, allocatable :: niter(:, :)[:]                        ! coarray
      ni = num_images()
      me = this_image()
      if (mod(ny, ni) /= 0) stop 'ny must be a multiple of num_image()'
      my = ny / ni
      allocate(c(nx, my)[*], z(nx, my)[*]) ! implicitly sync all    ! coarray
!
! make 2D-mesh :  c(:, :)
!      
      block
        real  :: x(nx), y(ny)
        x = [( (x1 - x0) / (nx - 1) * (i - 1) + x0, i = 1, nx )]
        y = [( (y1 - y0) / (ny - 1) * (i - 1) + y0, i = 1, ny )]
        forall (i = 1:nx, j = 1:my) c(i, j) = cmplx(x(i), y((me - 1) * my + j)) 
      end block
 !   
 ! main iteration : niter(:, :)        
 !           
      allocate(niter(nx, my)[*]) ! implicitly sync all              ! coarray    
      niter = 0
      do iter = 0, maxiter
        where (abs(z) <= 2.0) 
          z = z * z + c
          niter = niter + 1
        end where  
      end do
 !
 ! make bmp file: Mandel.bmp   
 !    
      block 
        use m_bmp
        type (t_bmp(:, :)), allocatable :: bmp[:]                   ! coarray
        allocate(bmp[*], source = t_bmp(nx, my))
        bmp%rgb = to_rgb(256 - niter, 256  - niter, 256 - niter)
        if (me == 1) call bmp%wr_header('mandel') ! write header
        if (me > 1 ) sync images(me - 1)                            ! coarray
          print '(3g0)', 'image ', me, ' writing..' 
          call bmp%wr('mandel')                   ! write body
        if (me < ni) sync images(me + 1)                            ! coarray  
      end block
    end program mandel
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?