! ----------------------------------------------------------------------------------- !
! The Research LINE source (R-LINE) model is in continuous development by various     !
! groups and is based on information from these groups: Federal Government employees, !
! contractors working within a United States Government contract, and non-Federal     !
! sources including research institutions.  These groups give the Government          !
! permission to use, prepare derivative works of, and distribute copies of their work !
! in the R-LINE model to the public and to permit others to do so.  The United States !
! Environmental Protection Agency therefore grants similar permission to use the      !
! R-LINE model, but users are requested to provide copies of derivative works or      !
! products designed to operate in the R-LINE model to the United States Government    !
! without restrictions as to use by others.  Software that is used with the R-LINE    !
! model but distributed under the GNU General Public License or the GNU Lesser        !
! General Public License is subject to their copyright restrictions.                  !
! ----------------------------------------------------------------------------------- !

      program RLINE_Main
! -----------------------------------------------------------------------------------
!     Written by Akula Venkatram (AV), Michelle G. Snyder (MGS) and David K. Heist (DKH)
!     RLINE v1.2, November 2013
!
!     This program computes the concentration in microgm/m^3 associated with a 
!     an arbitrary number of line sources. Each line source is specified with an 
!     emission rate per unit length of Qemis gm/s/m,(x,y,z) and co-ordinates of the 
!     end points. Each line sources has a different sigmaz0. The line sources are 
!     listed in a text file specified in text file called Line_Source_Inputs.txt

!     The number of receptors is arbitrary. They are specified using coordinates 
!     are Xrecep, Yrecep, Zrecep. The receptors are listed in a text file specified 
!     in a text file called Line_Source_Inputs.txt

!     The meteorology is specified an .sfc file geneerated by AERMET, the met-preprocessor 
!     for AERMOD.  Its name is specified in a text file called Line_Source_Inputs.txt
!
!     2025/06 - Added parallelization with mpi for sources according to indq. 
!
! -----------------------------------------------------------------------------------

      Use mpi_params
      Use Line_Source_Data
      Implicit None

! Local variables:
      Real(kind=double)  :: Error    !  Error in the numerical integration
      Real(kind=double)  :: Concd    !  Dummy concentration at receptor
      Real(kind=double)  :: Zb       !  Release height for barriers
      Integer            :: index, isource, AllocateStatus,imet, igroup,i
      Integer            :: SizeSurf
      Real(kind=double)  :: start, finish
      Integer, Allocatable  :: indq_mtx(:,:)
      
! -----------------------------------------------------------------------------------


! -----------------------------------------------------------------------------------
! -                                                                                 -
! -                                   INIT MPI                                      -
! -                                                                                 -
! -----------------------------------------------------------------------------------

    call mpi_init(ierr)
    call mpi_comm_size(MPI_COMM_WORLD, nb_procs, ierr)
    call mpi_comm_rank(MPI_COMM_WORLD, my_rank, ierr)  


! -----------------------------------------------------------------------------------
! -                                                                                 -
! -                            READING INITIAL FILES                                -
! -                                                                                 -
! -----------------------------------------------------------------------------------


      if (my_rank==0) then
        Call cpu_time(finish)
        if (nb_procs /= 1) write(*,*) "R-LINE parallelized on sources (indq)"
        if (nb_procs /= 1) write(*,*) "Number of processors: ", nb_procs
      end if
 
      Call Create_Exp_Table

      if (my_rank==0) write(*,*) "Reading Inputs..."
      Call Read_Line_Source_Inputs
      
      if (my_rank==0) write(*,*) "Reading Receptors..."
      Call Read_Receptors
      
      if (my_rank==0) write(*,*) "Reading Sources file..."
      Call Read_Sources
      
      if (my_rank==0) write(*,*) "Reading SFC-file..."
      Call Read_Met_Inputs(SizeSurf)
      
      
      Allocate(Concentration(Number_Receptors,SizeSurf,Number_Groups),Stat=AllocateStatus)
      Allocate(mpiSum_Concentration_src(Number_Receptors,SizeSurf,Number_Groups),Stat=AllocateStatus)

      Concd=0.0         ! Initialize Concentrations
      Concentration=0.0
      mpiSum_Concentration_src=0.0
 
    
      
      call init_mpi_params(Number_Sources, mpi_source_start, mpi_source_end)

      ! Crec que és millor que ho calculi el processador 0 i passar la info
      ! a la resta de processadors.
      ! Apareix un error relacionat amb el mpi_bcast:
      ! Abort(402203905) on node 1 (rank 1 in comm 0): Fatal error in internal_Bcast: Invalid buffer pointer, error stack:
      ! internal_Bcast(107): MPI_Bcast(buffer=(nil), count=1, MPI_INTEGER, 0, MPI_COMM_WORLD) failed
      ! internal_Bcast(80).: Null buffer pointer


!      Potser això podria estar inclòs dins de la subrutina de lectura de l'arxiu de fonts.

!      if (my_rank==0) then
      
        Allocate(indq_mtx(Number_Sources,3),Stat=AllocateStatus)
        indq_mtx(:,:)=0
        do igroup=1,Number_Groups
           do isource = 1, Number_Sources
              indq = Group_Array(isource,igroup)
              if (indq/=0) then
                indq_mtx(indq,1) = igroup 
                indq_mtx(indq,2) = isource
                indq_mtx(indq,3) = indq ! set global variable for line index
              end if
           end do
        end do
      
!      end if
      
!      if (nb_procs /= 1) then
!        write(*,*) indq_mtx(:,:)
!        write(*,*) size(indq_mtx(:,:))
!        call mpi_bcast(indq_mtx(:,:), size(indq_mtx(:,:)), MPI_int, &
!                       0, MPI_COMM_WORLD, ierr)
!      end if
      
!      if (my_rank==1) then
!        write(*,*)
!        write(*,*) "Size indq_mtx:", shape(indq_mtx)
!        do i=1,Number_Sources
!          write(*,*) indq_mtx(i,:)
!        end do
!        write(*,*)
!        write(*,*) indq_mtx
!      end if
      
! -----------------------------------------------------------------------------------
! -                                                                                 -
! -                             COMPUTING DISPERSION                                -
! -                                                                                 -
! -   1. Meteorology loop: computes met variables, sigmav, thetaw, rotates co-      -
! -      ordinates.                                                                 -
! -      2. Group loop [for each metstep]:                                          -
! -         3. Sources PARALLELIZED loop [for each metstep and source group]:       -
! -            Retrives source coordinates and sigmay0                              -
! -            4. Receptors loop [for each metstep, source, group and source        -
! -               (parallel)]:                                                      - 
! -                   - Obtains receptor rotated coordinates,                       - 
! -                   - Calls Analytical/Numerical line solution,                   -
! -                   - Sums concentration to concentrations at the same            -
! -                     receptor, group and meteorology step (multiplied by the     -
! -                     total emission of the source.                               -
! -                                                                                 -
! -----------------------------------------------------------------------------------



 met: do imet=1, SizeSurf
        
        if (my_rank==0) write(*,*) "Working on line ", imet, "of", SizeSurf, "in SFC-file..."    
        
        if ((SurfaceMet(imet)%ustar.LE.0.0).OR.(SurfaceMet(imet)%Hs.EQ.-999.0)) then
          Concentration(1:Number_Receptors,imet,:)=-99.0        
        else
          Call Fill_Met(imet)      ! Assign met variables
          Call Compute_Met         ! Compute sigmav and Ueff and thetaw 
          Call Translate_Rotate    !  Translate and rotate line source to align with wind direction  
 
 indxq:   do indq=mpi_source_start, mpi_source_end
              igroup = indq_mtx(indq,1)  
              isource = indq_mtx(indq,2)      
 
          
              !write(*,*) my_rank, mpi_source_start, mpi_source_end, igroup, isource, indq 
              
! --------------Get translated an rotated source information
              sigmaz0=Source(indq)%init_sigmaz     
              Xsbegin=Xsb_rot(indq);
              Xsend = Xse_rot(indq);
              Ysbegin=Ysb_rot(indq);
              Ysend = Yse_rot(indq);

              if((op_SC.EQ.'Y') .AND. (Source(indq)%hwall .GT. 0.0))then
                Call Barrier_Displacement(Zb)
                Zsbegin = Zb
                Zsend   = Zb
              else
                Zsbegin=Source(indq)%Zsb
                Zsend  =Source(indq)%Zse
              end if

! ----------------Set roadwidth (initial sigmay)
              sigmay0 = 0.0 ! initialize intital sigmay

              if (op_width =='Y')then
                sigmay0 = abs(0.5*(width*Source(indq)%Nlanes)*sin(thetaw+sm_num));
              end if

 ! ---------------Receptor loop
 rcp:         do index=1,Number_Receptors  
              
                Xr_rot=Xrcp_rot(index)
                Yr_rot=Yrcp_rot(index)
                Zrecep=Receptor(index)%Zr

                if (op_Analytical =='Y')then
                  Call Analytical_Line_Source(Concd)
                  Error = 0.0
                else
                  Call Numerical_Line_Source(imet,index,Concd,Error)
                end if
              
                Concentration(index,imet,igroup)=Concentration(index,imet,igroup)+Concd*1.0e06*Source(indq)%Qemis

              end do rcp      ! receptor loop
    
           
          end do indxq          ! group loop
          
! --------------Sum up contribution of all processors to each receptor                                 
          if (nb_procs /= 1) then
            call mpi_reduce(Concentration(:,imet,:), mpiSum_Concentration_src(:,imet,:) &
                            , size(Concentration(:,imet,:)) &
                            , mpi_double_precision, mpi_sum, 0,mpi_comm_world, ierr)
          else
            mpiSum_Concentration_src(:,imet,:) = Concentration(:,imet,:) 
          end if   
            
        end if                ! valid meteorology
      end do met              ! met loop


      Concentration = mpiSum_Concentration_src

! -----------------------------------------------------------------------------------
! -                                                                                 -
! -                                WRITING FILES                                    -
! -                                                                                 -
! -----------------------------------------------------------------------------------
      
      if (my_rank==0) then
      
        if (op_monthly =='M')then
          write(*,*) "DONE computing"
          write(*,*) "Now writing hourly output file by MONTH... "
          Call Write_Hourly_by_Month(SizeSurf)
        else if (op_monthly =='A')then
          write(*,*) "DONE computing"
          write(*,*) "Now writing hourly output file... "
          Call Write_Hourly_All(SizeSurf)
        else
          write(*,*) "DONE computing... NOT writing hourly output file! "
        end if
   
        if (op_ave =='Y')then
          write(*,*) "Now writing 24-hour average output file... "
          Call Write_Daily_Ave(SizeSurf)
        else 
          write(*,*) "DONE ... NOT writing daily average output file! "
        end if

        Call cpu_time(finish)
        print '("runtime = ", f10.3," seconds.")', finish-start  

      end if      
      
      call Deallocate_arrays
      call MPI_FINALIZE(ierr)
      
      End 
