ReactorClass.f90 Source File


Contents

Source Code


Source Code

! #############################
module ReactorClass
    use MathClass
    implicit none
  
    integer(int32),parameter :: PF_MAX_REACTION_NUM = 20
    integer(int32),parameter :: PF_MAX_INPUT_NUM = 5
    integer(int32),parameter :: PF_MAX_OUTPUT_NUM = 5
  
    type :: Reactor_
      ! substances
      type(Real64Ptr_), allocatable :: substances(:)
      type(String_),    allocatable :: substance_names(:)
      integer :: n_substances=0
      
      ! reactions
      integer :: n_reaction=0
      integer(int32):: input_list(PF_MAX_REACTION_NUM,PF_MAX_INPUT_NUM) = 0
      integer(int32):: output_list(PF_MAX_REACTION_NUM,PF_MAX_OUTPUT_NUM) = 0
      real(real64)  :: reaction_order(PF_MAX_REACTION_NUM,PF_MAX_INPUT_NUM+PF_MAX_OUTPUT_NUM) = 0
      real(real64)  :: mol_rate(PF_MAX_REACTION_NUM,PF_MAX_INPUT_NUM+PF_MAX_OUTPUT_NUM) = 0
      real(real64)  :: constants(PF_MAX_REACTION_NUM) = 0
  
    contains
      procedure :: Init => InitReactor
      procedure :: put => putReactor
      procedure :: define => defineReactor
      procedure :: SearchSubstanceID=>SearchSubstanceIDReactor
      procedure :: run => runReactor
    end type
  contains
  
  ! ---------------------------
  subroutine InitReactor(this, max_num_substances)
    class(Reactor_), intent(inout) :: this
    integer(int32),optional, intent(in) :: max_num_substances
    integer(int32) :: n
  
    if(present(max_num_substances) )then
      n = max_num_substances
    else
      n = 100
    endif
    this%n_substances = 0
  
    if(allocated(this%substances) )then
      deallocate(this%substances)
    end if
    if(allocated(this%substance_names) )then
      deallocate(this%substance_names)
    end if
  
    allocate(this%substances(n))
    allocate(this%substance_names(n))
    
  end subroutine InitReactor
  ! ---------------------------
  
  
  ! ---------------------------
  subroutine putReactor(this, substance_name, substance)
    class(Reactor_), intent(inout) :: this
    character(*), intent(in) :: substance_name
    real(real64),target,intent(in) :: substance
    integer(int32) :: i,num
    num = this%n_substances + 1
  
    if(num>size(this%substances ) )then
      print *, "ERROR :: putReactor num>size(this%substances ) "
    else
      this%substances(num)%ptr => substance
      this%substance_names(num) = substance_name
    endif  
    this%n_substances =this%n_substances + 1
  
  end subroutine putReactor
  ! ---------------------------
  
  pure function SearchSubstanceIDReactor(this,name) result(ret)
    class(Reactor_), intent(in) :: this
    character(*),intent(in) :: name
    integer(int32) :: i, ret
  
    ret = 0
    do i=1,this%n_substances
      if(trim(this%substance_names(i)%all)==trim(name) )then
        ret = i
        return
      endif
    enddo
  
  end function
  
  ! ---------------------------
  subroutine defineReactor(this, input_list,output_list,constant,mol_rate,reaction_order)
    class(Reactor_), intent(inout) :: this
    type(String_),intent(in) :: input_list(:)
    type(String_),intent(in) :: output_list(:)
    real(real64),intent(in) :: constant ! reacton constant k
    real(real64),optional,intent(in) :: reaction_order(:),mol_rate(:)
    real(real64),allocatable :: mrate(:),rrate(:)
    integer(int32) :: i,j,n
    
    this%n_reaction = this%n_reaction + 1
  
  
    if(present(mol_rate)  )then
      mrate = mol_rate
    else
      n = size(input_list) + size(output_list)
      allocate(mrate(n) )
      mrate(:) = 1.0d0
    endif
  
    if(present(reaction_order)  )then
      rrate = reaction_order
    else
      n = size(input_list) + size(output_list)
      allocate(rrate(n) )
      rrate(:) = 1.0d0
    endif
  
    if(size(input_list) > PF_MAX_INPUT_NUM .or. size(output_list) > PF_MAX_OUTPUT_NUM )then
      print *, "ERROR :: defineReactor size(mrate) > PF_MAX_INPUT_NUM+PF_MAX_OUTPUT_NUM"
      stop
    endif
    ! register reaction
    ! INPUT
    do i=1,size(input_list)
      ! search substance id
      this%input_list(this%n_reaction,i) = this%SearchSubstanceID( trim(input_list(i)%all))
    enddo
  
  
    do i=1,size(output_list)
      ! search substance id
      this%output_list(this%n_reaction,i) = this%SearchSubstanceID( trim(output_list(i)%all ))
    enddo
  
    this%reaction_order(this%n_reaction,1:size(mrate) ) = mrate(1:size(mrate) )
    this%mol_rate(this%n_reaction,1:size(mrate) ) = mrate(1:size(mrate) )
  
    this%constants(this%n_reaction) = constant
  
  end subroutine
  ! ---------------------------
  
  subroutine runReactor(this, dt)
    class(Reactor_),intent(inout) :: this
    real(real64),intent(in) :: dt
    integer(int32) :: i,j,num_input,num_output
    real(real64) :: A_B_ratio,xi,xi_n,coef,A0,B0,nA,nB
    real(real64) :: k1,k2, k3, k4
  
    ! run simulation
    if(this%n_reaction==0)then
      print *, "ERROR :: runReactor this%n_reaction==0"
      stop
    elseif(this%n_reaction==1)then
      ! single reaction equation
      num_input = 0
      do i=1,size(this%input_list,2)
        if(this%input_list(1,i)/=0)then
          num_input = num_input + 1
        endif
      enddo
      num_output = 0
      do i=1,size(this%output_list,2)
        if(this%output_list(1,i)/=0)then
          num_output = num_output + 1
        endif
      enddo
      if(num_input==1 .and. num_output==1)then
        ! x*A -> y*B reaction equation
        print *, "[ok] Reactor Started >> "
        A_B_ratio = this%reaction_order(1,2) / this%reaction_order(1,1)
        this%substances(this%input_list(1,1))%ptr = this%substances(this%input_list(1,1))%ptr *exp(this%constants(1)*dt)
        this%substances(this%output_list(1,1))%ptr = this%substances(this%output_list(1,1))%ptr *exp(A_B_ratio*this%constants(1)*dt)
      elseif(num_input==2 .and. num_output==1)then
        print *, "[ok] Reactor Started >> "
        ! x*A + y*B -> z*C reaction equation
        ! A + y/x*B -> z/x*C reaction equation
        ! by Runge-Kutta mehod
        ! Reacted A = A0 - xi
        ! d xi/dt = k*(A0-xi)**(nA) * (B0 - xi)**(nB)
        ! 反応比率も必要!!
        ! 反応速度式の次数は反応比率によらないが,
        ! 反応量は反応比率によるため.
        coef = this%constants(1)
        
        A0 = this%substances(this%input_list(1,1))%ptr
        B0 = this%substances(this%input_list(1,2))%ptr
        nA = this%reaction_order(1,1)
        nB = this%reaction_order(1,2)
        xi_n = 0.0d0
        k1 = coef*((A0-xi_n)**(nA)) *( (B0 - xi_n)**(nB))
        k2 = coef*((A0- (xi_n + dt*0.50d0*k1 ) )**(nA)) &
            * ( (B0 -  (xi_n + dt*0.50d0*k1 ) )**(nB))
        k3 = coef*((A0- (xi_n + dt*0.50d0*k2 ) )**(nA)) &
            * ( (B0 -  (xi_n + dt*0.50d0*k2 ) )**(nB))
        k4 = coef*((A0- (xi_n + dt*k3 ) )**(nA)) &
            * ( (B0 -  (xi_n + dt*k3 ) )**(nB))
        xi = xi_n + 1.0d0/6.0d0*dt*(k1+k2+k3+k4)
  
        this%substances(this%input_list(1,1))%ptr = A0 - xi
        this%substances(this%input_list(1,2))%ptr = &
          B0 - dble(this%mol_rate(1,2)/this%mol_rate(1,1))* xi
        
        this%substances(this%output_list(1,1))%ptr = &
          this%substances(this%output_list(1,1))%ptr &
          + dble(this%mol_rate(1,3)/this%mol_rate(1,1))* xi
      else
        print *, "ERROR :: runReactor num_input/=1 .or. num_output/=1, now being implemented."
        stop  
      endif
  
  
    else
      print *, "ERROR :: runReactor this%n_reaction>=2, now being implemented."
      stop
    endif
  end subroutine
  
  
  end module ReactorClass
  ! #############################