포트란 언어 기반 스크립트: 디렉토리 만들고 연속적으로 job 제출하기 by 바죠

포트란 언어 기반 스크립트 (유닉스/리눅스 명령어):


N 개의 디렉토리를 만들고 각각의 디렉토리에서 독립적인 계산을 수행하고자 한다.  기본적인 데이터들과 준비된 입력 파일들을 각각의 디렉토리에 복사하고 연속적으로 job을 제출한다. 포트란 언어로 스크립트 만들기를 시도했다. python이나 쉘 스크리트로 하는 것이 일반적이다.  사실 이런일들을 하려고 파이썬이나 쉘 스크립트를 공부한다.  하지만, 포트란으로도 가능하다는 것을 보여주기 위해서 아래와 같이 만들어 보았다.

여러 개의 계산 노드가 확보된 상황이라면 병렬로 계산이 될 것이다. 그렇지 않으면 하나 하나 계산이 진행될 것이다. 역시 병렬계산의 특수한 경우가 씨리얼 계산이다. 쉘스크립트, 파이썬을 활용한다면 더 간단하게 할 수 있을 것이라고 이야기 할 수 있을 것이다.  하지만, 포트란으로도 가능하다는 것을 보여주는 것이다. 그 실용성은 충분히 있다.


몇 가지 유용한 string 전용 함수들을 잘 익혀 둘 필요가 있다.

adjustl()

trim()

len()

len_trim()

index()


과 같은 문자열(스트링) 전용 함수들이 유용하다.


포트란 기반 파싱(parsing)도 지난번 포스팅에서 다루긴 했었다.
http://incredible.egloos.com/4836430
strings.txt

포트란 기반 스크립트 작성시 유용할 수 있는 명령어:
http://incredible.egloos.com/3474225



       implicit none
        integer isize
       integer i,nd
       character*200 string1,string
       character*200 cmd
       character*200000 string9

       nd=16*8
       nd=96
!
       isize=3
!      goto 999
       do i=1,nd
       call xnumeral (i,string,isize)
       string='disp-'//trim(string)
       cmd='mkdir '//string
       cmd=trim(cmd)
       call system(cmd)
       enddo
       do i=1,nd
       call xnumeral (i,string,isize)
       string1='disp-'//trim(string)
       string='POSCAR-'//trim(string)//' '//trim(string1)//'/POSCAR'
       cmd='cp '//string
       call system(cmd)
       string='POTCAR'//' '//trim(string1)//'/'
       cmd='cp '//string
       call system(cmd)
       string='KPOINTS'//' '//trim(string1)//'/'
       cmd='cp '//string
       call system(cmd)
       string='INCAR_phonopy'//' '//trim(string1)//'/INCAR'
       cmd='cp '//string
       call system(cmd)
       string='TEST_force.pbs'//' '//trim(string1)//'/'
       cmd='cp '//string
       call system(cmd)
       enddo
!
       do i=1,nd
       call xnumeral (i,string,isize)
       string='disp-'//trim(string)
       cmd='cd '//string
       cmd=trim(cmd)//' ; qsub TEST_force.pbs'
       cmd=trim(cmd)
       call system(cmd)
       enddo
!
 999   continue
!      phonopy -f disp-*/vasprun.xml
!
       stop
       end

유용한 프로그램이 있다. 숫자를 텍스트로 변환하는 것이다. 자릿수를 고정한 상태에서 처리한다.

----------------------------------------------------------------------------------------------

c
c
c ###################################################
c ## COPYRIGHT (C) 1992 by Jay William Ponder ##
c ## All Rights Reserved ##
c ###################################################
c
c #############################################################
c ## ##
c ## subroutine numeral -- convert number to text string ##
c ## ##
c #############################################################
c
c
c "numeral" converts an input integer number into the
c corresponding right- or left-justified text numeral
c
c number integer value of the number to be transformed
c string text string to be filled with corresponding numeral
c size on input, the minimal acceptable numeral length, if
c zero then output will be right justified, if
c nonzero then numeral is left-justified and padded
c with leading zeros as necessary; upon output, the
c number of non-blank characters in the numeral
c
c
      subroutine xnumeral (number,string,size)
      implicit none
      integer i,number,size,multi,pos
      integer length,minsize,len
      integer million,hunthou,tenthou
      integer thousand,hundred,tens,ones
      character*1 digit(0:9)
      character*(*) string
      logical right,negative
      data digit / '0','1','2','3','4','5','6','7','8','9' /
c
c
c     set justification and size bounds for numeral string
c
      if (size .eq. 0) then
         right = .true.
         size = 1
      else
         right = .false.
      end if
      minsize = size
      length = len(string)
c
c     test the sign of the original number
c
      if (number .ge. 0) then
         negative = .false.
      else
         negative = .true.
         number = -number
      end if
c
c     use modulo arithmetic to find place-holding digits
c
      million = number / 1000000
      multi = 1000000 * million
      hunthou = (number-multi) / 100000
      multi = multi + 100000*hunthou
      tenthou = (number-multi) / 10000
      multi = multi + 10000*tenthou
      thousand = (number-multi) / 1000
      multi = multi + 1000*thousand
      hundred = (number-multi) / 100
      multi = multi + 100*hundred
      tens = (number-multi) / 10
      multi = multi + 10*tens
      ones = number - multi
c
c     find the correct length to be used for the numeral
c
      if (million .ne. 0) then
         size = 7
      else if (hunthou .ne. 0) then
         size = 6
      else if (tenthou .ne. 0) then
         size = 5
      else if (thousand .ne. 0) then
         size = 4
      else if (hundred .ne. 0) then
         size = 3
      else if (tens .ne. 0) then
         size = 2
      else
         size = 1
      end if
      size = min(size,length)
      size = max(size,minsize)
c
c     convert individual digits to a string of numerals
c
      if (size .eq. 7) then
         string(1:1) = digit(million)
         string(2:2) = digit(hunthou)
         string(3:3) = digit(tenthou)
         string(4:4) = digit(thousand)
         string(5:5) = digit(hundred)
         string(6:6) = digit(tens)
         string(7:7) = digit(ones)
      else if (size .eq. 6) then
         string(1:1) = digit(hunthou)
         string(2:2) = digit(tenthou)
         string(3:3) = digit(thousand)
         string(4:4) = digit(hundred)
         string(5:5) = digit(tens)
         string(6:6) = digit(ones)
      else if (size .eq. 5) then
         string(1:1) = digit(tenthou)
         string(2:2) = digit(thousand)
         string(3:3) = digit(hundred)
         string(4:4) = digit(tens)
         string(5:5) = digit(ones)
      else if (size .eq. 4) then
         string(1:1) = digit(thousand)
         string(2:2) = digit(hundred)
         string(3:3) = digit(tens)
         string(4:4) = digit(ones)
      else if (size .eq. 3) then
         string(1:1) = digit(hundred)
         string(2:2) = digit(tens)
         string(3:3) = digit(ones)
      else if (size .eq. 2) then
         string(1:1) = digit(tens)
         string(2:2) = digit(ones)
      else
         string(1:1) = digit(ones)
      end if
c
c     right-justify if desired, and pad with blanks
c
      if (right) then
         do i = size, 1, -1
            pos = length - size + i
            string(pos:pos) = string(i:i)
         end do
         do i = 1, length-size
            string(i:i) = ' '
         end do
      else
         do i = size+1, length
            string(i:i) = ' '
         end do
      end if
      return
      end


위의 작업과 완벽하게 대치되는 상황:
포트란 프로그램 실행 중에 system으로 나와서 여러가지 작업을 수행하고 원래 프로그램으로 복귀하는 경우이다.
http://incredible.egloos.com/3474225

사실, 씨리얼 프로그램이 그 실행을 하는 도중에 시스템에 나와서 많은 배치 job들을 실행시킬 수 있다. 씨리얼 프로그램(스크립트)이 여러 개의 디렉토리를 만들고  각각의 디렉토리에서 사실상 독립적인 계산 들을 동시에 수행할 수 있다. 다시 말해서 "느슨한 병렬 계산"을 할 수 있다. 

쉘스크립트를 활용하여 씨리얼하게 한 디렉토리에서 연속적으로 계산 할 경우:

number=1
while [ $number -le 25 ]; do
    tmp="POSCAR.$number"
    cp $tmp POSCAR
mpirun_intel /usr/local/vasp4us_INTEL/vasp.5.2.12_11NOV2011_GRAPE.O3.MPIBLOCK1000.mpi.x  > stdout.log
    tmq="out.$number"
    cp OUTCAR  $tmq
    number=$((number + 1))
done


http://phonopy.sourceforge.net/

---------------------------------------------------------------------------------

#!/bin/sh
#PBS -l nodes=1:quad:ppn=8
#PBS -N csa_soldBP14

NPROCS=`wc -l < $PBS_NODEFILE`

hostname
date

cd $PBS_O_WORKDIR

# do not change file names, e.g., stdout.log, STATUS

# normal
cp INCAR_rlx    INCAR
sleep 0.5
mpirun -genv I_MPI_DEBUG 5 -np $NPROCS /opt/VASP/bin/vasp.5.2.12_GRAPE_GRAPHENE_NORMAL.mpi.x > stdout.log
# accurate   550 eV
number=1
while [ $number -lt 4 ]
do
cp INCAR_rlxall INCAR
cp CONTCAR      POSCAR
sleep 0.5
mpirun -genv I_MPI_DEBUG 5 -np $NPROCS /opt/VASP/bin/vasp.5.2.12_GRAPE_GRAPHENE_NORMAL.mpi.x > stdout.log
cp OUTCAR out.out_$number
sleep 0.5
number=`expr $number + 1`
done
# accurate   550 eV
if false; then
cp INCAR_bs     INCAR
cp CONTCAR      POSCAR
sleep 0.5
mpirun -genv I_MPI_DEBUG 5 -np $NPROCS /opt/VASP/bin/vasp.5.2.12_GRAPE_GRAPHENE_NORMAL.mpi.x > stdout.log
fi

sleep 0.5
STAMP=$(date +%Y%m%d_%H%M%S)_$RANDOM
echo $STAMP
#cp CONTCAR   ../deposit/CONTCAR_$STAMP
#cp OUTCAR   ../deposit/OUTCAR_$STAMP
#cp EIGENVAL ../deposit/EIGENVAL_$STAMP
#cp DOSCAR   ../deposit/DOSCAR_$STAMP

sleep 0.5
touch STOP
echo "DONE" >> STATUS

---------------------------------------------------------------------------------

#!/bin/sh
#PBS -l nodes=1:quad:ppn=1
#PBS -N csa_kingBP14
                                                                               
NPROCS=`wc -l < $PBS_NODEFILE`

hostname
date

cd $PBS_O_WORKDIR


#rm fort.?
#rm -rf 0???
#rm -rf /home/ihlee/csa_lj/BP14/deposit/*
#mkdir  /home/ihlee/csa_lj/BP14/deposit

# check files INCAR_bs, INCAR_rlx, POTCAR, csa.in, and CSA_SOLDIER.pbs
# never ending job : kill the PBS job, change STATUS
if [ ! -d deposit ]
then
    mkdir deposit
fi
/home/ihlee/csa_vasp/csa_vasp.x < csa.in &> csa.out
STAMP=$(date +%Y%m%d_%H%M%S)_$RANDOM
cp csa.out   csa.out_$STAMP
cp fort.1     fort.1_$STAMP

---------------------------------------------------------------------------------

!234567890
       implicit none
       integer islc
       character*280 otname
       character*280 cname1
       character*80 string0
       logical lfault7

       otname='/home/ihlee/csa_lj/gSiC7/0001/OUTCAR'
       islc=len(otname)
       write(6,*) islc
       islc=len_trim(otname)
       write(6,*) islc
       islc=len(trim(otname))
       write(6,*) islc

       islc=islc-6 ; cname1=otname(1:islc)
!      write(6,*) trim(cname1)
       cname1=trim(cname1)//'CONTCAR'
!      write(6,*) trim(cname1)
       lfault7=.false.
       open(71,file=trim(cname1),form='formatted')
       do
       read(71,'(a80)',err=711,end=799) string0
       if(len_trim(string0) == 0) goto 700
       if(len_trim(string0) > 0) write(6,*) trim(string0)
       enddo
  711  continue
       lfault7=.true.
  799  continue
  700  continue
       close(71)

       stop
       end

--------------------------------------------------------------------------------------------------------------------
컴퓨터 프로그램 개발 단계에서는 컴퓨터로 부터 기계적으로 더 많은 정보를 자동적으로 얻어낼 필요가 있다.
컴파일러 제공 정보, 실행 순간 제공 정보, 보다 더 많은 계산 관련 정보를 얻어내는 것이 중요하다. 
계산 속도는 차후의 문제이다. 우선 정확해야만 한다.  
이를 위해서 ifort  컴파일러의 경우 아래의 컴파일 옵션을 사용하는 것이 매우 중요하다. 
실행할 때, 많은 문제점들을 자동적으로 지적해 준다. 느린 계산이지만 자동적으로 프로그램의 문제점을 제시한다. 
물론, 문제점이 없을 수 있지만, 그래도 한 번 시도하는 것은 남는 장사이다.
 
 -CB -check all -warn interface -assume realloc_lhs

--------------------------------------------------------------------------------------------------------------------


       cmd='cd ./'//trim(file_names(1))//' ; '//'qsub ./ADMD_SOLDIER.pbs'
       cmd=trim(cmd)
       call system(cmd)

--------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------


핑백

덧글

댓글 입력 영역

최근 포토로그



MathJax