!> Define a species type data structure
!!
module MW_species
   use MW_kinds, only: wp
   use MW_species_parameters, only: &
         SPECIES_NAME_LENGTH, &
         CHARGE_TYPE_NEUTRAL, CHARGE_TYPE_POINT, CHARGE_TYPE_GAUSSIAN
   implicit none
   private

   ! public types
   public :: MW_species_t

   ! public subroutines
   public :: void_type
   public :: print_type
   public :: set_molecule
   public :: set_electrode
   public :: identify
   public :: read_parameters
   public :: set_offsets

   ! Species datatype
   type MW_species_t
      character(len=SPECIES_NAME_LENGTH) :: name = ""     !< name
      integer                          :: index = 0       !< index of the species type
      integer                          :: count = 0       !< number of species of this type
      integer                          :: offset = 0      !< Offset in species data arrays

      ! Mobility parameters
      logical                          :: is_mobile = .true. !< does species move or not?

      ! Mobility parameters
      logical                          :: is_fourth_site = .false. 

      ! Mass parameters
      real(wp)                         :: mass = 0.0_wp       !< mass
      real(wp)                         :: mass_rec = 0.0_wp   !< inverse of mass

      ! Electrostatic parameters
      integer  :: charge_type = 0              !< species charge type
      real(wp) :: charge = 0.0_wp              !< electric charge
      real(wp) :: polarizability = 0.0_wp      !< polarizability
      real(wp) :: eta = 0.0_wp                 !< gaussian charge width
      logical  :: has_constant_charge = .true. !< do all species have the same constant charge during the simulation?
                                               !! .false. for species in electrodes with constant potential
      logical  :: is_polarizable = .false.     !< is the species polarizable?
      ! Dumping parameters
      logical  :: dump_efg = .false.           !< is the efg data dumped for this species?
      logical  :: dump_lammps = .true.         !< is the lammps data dumped for this species?
      logical  :: dump_xyz = .true.            !< is the xyz data dumped for this species?
      logical  :: dump_trajectories = .true.   !< is the trajectories data dumped for this species?
      logical  :: dump_pdb = .true.            !< is the pdb data dumped for this species?
      ! Deformation parameters
      real(wp) :: selfdaimD = 0.0_wp
      real(wp) :: selfdaimbeta = 0.0_wp
      real(wp) :: selfdaimzeta = 0.0_wp
      logical  :: is_deformable = .false.     !< is the species deformable?
      ! Species attributes
      logical :: in_molecule = .false.  !< does this species belong to a molecule
      character(len=SPECIES_NAME_LENGTH) :: molecule_name = "" !< name of the molecule it belongs to
      integer :: molecule_index = 0           !< index of the molecule it belongs to

      logical :: in_electrode = .false. !< does this species belong to an electrode
      character(len=SPECIES_NAME_LENGTH) :: electrode_name = "" !< name of the electrode it belongs to
      integer :: electrode_index = 0          !< index of the electrode it belongs to
   end type MW_species_t

contains

   !================================================================================
   ! Void the data structure
   subroutine void_type(this)
      implicit none
      type(MW_species_t), intent(inout) :: this

      this%name   = ""
      this%count  = 0
      this%offset = 0
      this%is_mobile = .false.
      this%mass = 0.0_wp
      this%mass_rec = 0.0_wp
      this%charge_type = 0
      this%charge = 0.0_wp
      this%polarizability = 0.0_wp
      this%selfdaimD = 0.0_wp
      this%selfdaimbeta = 0.0_wp
      this%selfdaimzeta = 0.0_wp
      this%eta = 0.0_wp
      this%has_constant_charge = .false.
      this%is_polarizable = .false.
      this%is_deformable = .false.
      this%in_molecule = .false.
      this%dump_efg = .false.
      this%dump_lammps = .true.
      this%dump_xyz = .true.
      this%dump_trajectories = .true.
      this%dump_pdb = .true.
      this%molecule_name = ""
      this%molecule_index = 0
      this%in_electrode = .false.
      this%electrode_name = ""
      this%electrode_index = 0

   end subroutine void_type

   !================================================================================
   ! Print the data structure to ounit
   subroutine print_type(this, ounit)
      implicit none
      type(MW_species_t), intent(in) :: this          ! structure to be printed
      integer,        intent(in) :: ounit         ! output unit

      write(ounit,'("|species| name: ",a16)') this%name
      write(ounit,'("|species| count: ",i8," offset: ", i8)') this%count, this%offset
      write(ounit,'("|species| mass: ",es12.5)') this%mass
      if (this%is_mobile) then
         write(ounit,'("|species| mobile: ",a3)') "yes"
      else
         write(ounit,'("|species| mobile: ",a3)') " no"
      end if

      select case(this%charge_type)
      case(CHARGE_TYPE_NEUTRAL)
         write(ounit,'("|species| charge type: ",a8)') " neutral"
      case(CHARGE_TYPE_POINT)
         write(ounit,'("|species| charge type: ",a8," charge: ",es12.5)') "   point", this%charge
      case(CHARGE_TYPE_GAUSSIAN)
         write(ounit,'("|species| charge type: ",a8," charge: ",es12.5," eta: ",es12.5)') &
               "gaussian", this%charge, this%eta
      case default
         write(ounit,'("|species| charge type: ???")')
      end select

      if (this%is_polarizable) then
      write(ounit,'("|species| polarizability: ",es12.5)') this%polarizability
      else
         write(ounit,'("|species| species is not polarizable.")')
      end if
      if (this%is_deformable) then
      write(ounit,'("|species| parameters for deformability D: ",es12.5," beta: ",es12.5,"zeta: ",es12.5)') &
           this%selfdaimD,this%selfdaimbeta,this%selfdaimzeta
      else
         write(ounit,'("|species| species is not deformable.")')
      end if


      if (this%in_molecule) then
         write(ounit,'("|species| species belongs to molecule ",a8," (",i3,")")') &
               this%molecule_name, this%molecule_index
      else
         write(ounit,'("|species| species does not belong to any molecule.")')
      end if

      if (this%in_electrode) then
         write(ounit,'("|species| species belongs to electrode ",a8," (",i3,")")') &
               this%electrode_name, this%electrode_index
      else
         write(ounit,'("|species| species does not belong to any electrode.")')
      end if

   end subroutine print_type

   !================================================================================
   ! Search for an species in a list and return the index in the list
   !
   ! The first matching index is returned.
   ! 0 is returned if no match found
   subroutine identify(species_name, species, species_index)
      implicit none
      character(*),                 intent(in)  :: species_name  ! name of species to search
      type(MW_species_t), dimension(:), intent(in)  :: species      ! list of species
      integer,                      intent(out) :: species_index ! index of species in the list

      integer :: i

      species_index = 0
      do i = 1, size(species,1)
         if (species_name == species(i)%name) then
            species_index = i
            exit
         end if
      end do
   end subroutine identify

   !================================================================================
   !> Set the name of the species
   !>
   subroutine set_name(this, name)
      implicit none
      type(MW_species_t), intent(inout) :: this   ! species
      character(len=*),   intent(in)    :: name
      this%name = name
   end subroutine set_name

   !================================================================================
   !> Set the count of the species
   !>
   subroutine set_count(this, count)
      implicit none
      type(MW_species_t), intent(inout) :: this   ! species
      integer, intent(in) :: count !< number of particles of this species type
      this%count = count
   end subroutine set_count

   !================================================================================
   !> Set the mass parameters
   !>
   subroutine set_mass(this, mass)
      implicit none
      type(MW_species_t), intent(inout) :: this   ! species
      real(wp),           intent(in)    :: mass   ! mass values
      this%mass = mass
      if (mass > 0.0_wp) then
         this%mass_rec = 1.0_wp / mass
      else
         this%mass_rec = 0.0_wp
      end if
   end subroutine set_mass

   !================================================================================
   ! Set the mobility attribute of the species
   !
   subroutine set_mobility(this, mobile)
      implicit none
      type(MW_species_t), intent(inout) :: this     ! species
      logical,        intent(in)    :: mobile   ! can this species move?
      this%is_mobile = mobile
   end subroutine set_mobility

   !================================================================================
   ! Set if the atom is a fourth_site atom
   !
   subroutine set_fourth_site(this, fourth_site)
      implicit none
      type(MW_species_t), intent(inout) :: this     ! species
      logical,        intent(in)    :: fourth_site
      this%is_fourth_site = fourth_site
   end subroutine set_fourth_site

   !================================================================================
   ! Set the efg flag for the species
   !
   subroutine set_dump_efg(this, dump_efg)
      implicit none
      type(MW_species_t), intent(inout) :: this   ! species
      logical,        intent(in)    :: dump_efg   ! do we need efg for this species?
      this%dump_efg = dump_efg
   end subroutine set_dump_efg

   !================================================================================
   ! Set the lammps flag for the species
   !
   subroutine set_dump_lammps(this, dump_lammps)
      implicit none
      type(MW_species_t), intent(inout) :: this      ! species
      logical,        intent(in)    :: dump_lammps   ! do we need lammps data for this species?
      this%dump_lammps = dump_lammps
   end subroutine set_dump_lammps

   !================================================================================
   ! Set the xyz flag for the species
   !
   subroutine set_dump_xyz(this, dump_xyz)
      implicit none
      type(MW_species_t), intent(inout) :: this   ! species
      logical,        intent(in)    :: dump_xyz   ! do we need xyz data for this species?
      this%dump_xyz = dump_xyz
   end subroutine set_dump_xyz

   !================================================================================
   ! Set the trajectories flag for the species
   !
   subroutine set_dump_trajectories(this, dump_trajectories)
      implicit none
      type(MW_species_t), intent(inout) :: this   ! species
      logical,        intent(in)    :: dump_trajectories   ! do we need trajectories data for this species?
      this%dump_trajectories = dump_trajectories
   end subroutine set_dump_trajectories

   !================================================================================
   ! Set the pdb flag for the species
   !
   subroutine set_dump_pdb(this, dump_pdb)
      implicit none
      type(MW_species_t), intent(inout) :: this   ! species
      logical,        intent(in)    :: dump_pdb   ! do we need pdb data for this species?
      this%dump_pdb = dump_pdb
   end subroutine set_dump_pdb

   !================================================================================
   ! Set neutral charge type
   !
   subroutine set_charge_neutral(this)
      implicit none
      type(MW_species_t), intent(inout) :: this     ! species
      this%charge_type = CHARGE_TYPE_NEUTRAL
      this%charge = 0.0_wp
      this%eta = 0.0_wp
   end subroutine set_charge_neutral

   !================================================================================
   ! Set point-charge type
   !
   subroutine set_charge_point(this, charge)
      implicit none
      type(MW_species_t), intent(inout) :: this  !< species
      real(wp), intent(in) :: charge             !< charge of the species type
      this%charge_type = CHARGE_TYPE_POINT
      this%charge = charge
      this%eta = 0.0_wp
   end subroutine set_charge_point

   !================================================================================
   ! Set gaussian-charge type
   !
   subroutine set_charge_gaussian(this, charge, eta)
      implicit none
      type(MW_species_t), intent(inout) :: this  !< species
      real(wp), intent(in) :: charge             !< charge of the species type
      real(wp), intent(in) :: eta                !< gaussian width parameter
      this%charge_type = CHARGE_TYPE_GAUSSIAN
      this%charge = charge
      this%eta = eta
   end subroutine set_charge_gaussian

   !================================================================================
   !> Set the polarizability parameters
   !>
   subroutine set_polarizability(this, polarizability)
      implicit none
      type(MW_species_t), intent(inout) :: this             ! species
      real(wp),           intent(in)    :: polarizability   ! polarizability values
      this%polarizability = polarizability
   end subroutine set_polarizability

   !================================================================================
   !> Set the polarizability parameters
   !>
   subroutine set_deformability(this, selfdaimD, selfdaimbeta, selfdaimzeta)
      implicit none
      type(MW_species_t), intent(inout) :: this             ! species
      real(wp),           intent(in)    :: selfdaimD
      real(wp),           intent(in)    :: selfdaimbeta
      real(wp),           intent(in)    :: selfdaimzeta
      this%selfdaimD =selfdaimD
      this%selfdaimbeta =selfdaimbeta
      this%selfdaimzeta =selfdaimzeta
   end subroutine set_deformability

   !================================================================================
   ! Set whether the ion is polarizable
   !
   subroutine set_polarizable(this, polarizable)
      implicit none
      type(MW_species_t), intent(inout) :: this    !< species
      logical,        intent(in)    :: polarizable ! is the species polarizable
      this%is_polarizable = polarizable
   end subroutine set_polarizable

   !================================================================================
   ! Set whether the ion is deformable
   !
   subroutine set_deformable(this, deformable)
      implicit none
      type(MW_species_t), intent(inout) :: this    !< species
      logical,        intent(in)    :: deformable ! is the species deformable
      this%is_deformable = deformable
   end subroutine set_deformable

   !================================================================================
   ! Set molecule, this species belongs to
   !
   subroutine set_molecule(this, molecule_name, molecule_index)
      implicit none
      type(MW_species_t), intent(inout) :: this  !< species
      character(*), intent(in) :: molecule_name !< name of the molecule it belongs to
      integer, intent(in) :: molecule_index     !< index of the molecule it belongs to
      this%in_molecule = .true.
      this%molecule_name  = molecule_name
      this%molecule_index = molecule_index
   end subroutine set_molecule

   !================================================================================
   ! Set electrode, this species belongs to
   !
   subroutine set_electrode(this, electrode_name, electrode_index)
      implicit none
      type(MW_species_t), intent(inout) :: this  !< species
      character(*), intent(in) :: electrode_name !< name of the electrode it belongs to
      integer, intent(in) :: electrode_index     !< index of the electrode it belongs to
      this%in_electrode = .true.
      this%electrode_name = electrode_name
      this%electrode_index = electrode_index
      this%has_constant_charge = .false.
   end subroutine set_electrode

   ! ================================================================================
   !> Set offsets for a list of species
   subroutine set_offsets(species)
      implicit none
      type(MW_species_t), intent(inout) :: species(:)

      integer :: i, n, offset
      n = size(species,1)
      offset = 0
      do i = 1, n
         species(i)%offset = offset
         offset = offset + species(i)%count
      end do
   end subroutine set_offsets

   !================================================================================
   !> Read species parameters from runtime.inpt
   !!
   !! Block format:
   !! -------------
   !! species_type *block*
   !!   name *string*
   !!   count *int*
   !!   mass  *real*
   !!   + charge neutral
   !!   + charge point q (*real*)
   !!   + charge gaussian eta (*real*) [q] (*real*)
   !!   polarizability *real*
   !!   deformability D (*real*) beta (*real*) zeta (*real*)
   !!   mobile *bool*
   !!   fourth_site_atom 
   !!   dump_efg *bool*
   !!   dump_lammps *bool*
   !!   dump_xyz *bool*
   !!   dump_trajectories *bool*
   !!   dum_pdb *bool*
   !!
   !! Parameters
   !! ----------
   !! funit : integer
   !!    handle to the runtime input file
   !!
   !! line_num : integer
   !!    current line number in the runtime input file
   subroutine read_parameters(this, funit, line_num)
      use MW_configuration_line, only: MW_configuration_line_t, &
            MW_configuration_line_seek_next_data => seek_next_data, &
            MW_configuration_line_get_word => get_word, &
            max_word_length
      use MW_constants, only: amu2me
      use MW_errors, only: MW_errors_runtime_error => runtime_error
      implicit none
      ! Parameters
      ! ----------
      type(MW_species_t), intent(inout) :: this
      integer, intent(in) :: funit
      integer, intent(inout) :: line_num

      ! Local
      ! -----
      type(MW_configuration_line_t) :: config_line
      character(max_word_length) :: keyword
      character(SPECIES_NAME_LENGTH) :: name
      integer :: count
      real(wp) :: mass
      logical :: mobile
      logical :: dump_efg
      logical :: dump_lammps
      logical :: dump_xyz
      logical :: dump_trajectories
      logical :: dump_pdb
      logical :: polarizable
      logical :: deformable
      logical :: fourth_site
      character(8) :: charge_keyword
      integer :: charge_type
      real(wp) :: charge, eta
      real(wp) :: polarizability
      real(wp) :: selfdaimD, selfdaimbeta, selfdaimzeta
      integer :: name_defined, count_defined, charge_defined, mass_defined, mobile_defined
      integer :: polarizability_defined, deformability_defined, fourth_site_defined
      integer :: dump_efg_defined, dump_lammps_defined, dump_xyz_defined, dump_trajectories_defined, dump_pdb_defined
      character(256) :: errmsg

      ! Void data structure
      call void_type(this)

      ! Set default values
      name = "****"
      count = 0
      charge_type = CHARGE_TYPE_NEUTRAL
      charge = 0.0_wp
      polarizability = 0.0_wp
      selfdaimD = 0.0_wp
      selfdaimbeta = 0.0_wp
      selfdaimzeta = 0.0_wp
      polarizable = .false.
      deformable = .false.
      eta = 0.0_wp
      mass = 0.0_wp
      mobile = .true.
      fourth_site = .false.
      dump_efg = .false.
      dump_lammps = .true.
      dump_xyz = .true.
      dump_trajectories = .true.
      dump_pdb = .true.

      ! Flag each section as undefined (line number will be stored)
      name_defined = 0
      count_defined = 0
      charge_defined = 0
      mass_defined = 0
      mobile_defined = 0
      polarizability_defined = 0
      deformability_defined = 0
      fourth_site_defined = 0
      dump_efg_defined = 0
      dump_lammps_defined = 0
      dump_xyz_defined = 0
      dump_trajectories_defined = 0
      dump_pdb_defined = 0

      call MW_configuration_line_seek_next_data(config_line, funit, line_num)
      keywordLoop: do while(config_line%num_words > 0)

         ! Look for keyword and read corresponding value
         call MW_configuration_line_get_word(config_line, 1, keyword)

         select case(keyword)

         case("name")
            if (name_defined > 0) then
               write(errmsg,'("At line ",i4,", redefinition of |name|. First definition at line ",i4,".")') &
                     line_num, name_defined
               call MW_errors_runtime_error("read_parameters", "species.f90", errmsg)
            end if
            name_defined = line_num

            ! Read name parameters
            if (config_line%num_words /= 2) then
               write(errmsg,'("Invalid format for name parameters at line ",i4)') line_num
               call MW_errors_runtime_error("read_parameters","species.f90", &
                     errmsg)
            end if
            call MW_configuration_line_get_word(config_line, 2, name)

         case("count")
            if (count_defined > 0) then
               write(errmsg,'("At line ",i4,", redefinition of |count|. First definition at line ",i4,".")') &
                     line_num, count_defined
               call MW_errors_runtime_error("read_parameters", "species.f90", errmsg)
            end if
            count_defined = line_num

            ! Read count parameters
            if (config_line%num_words /= 2) then
               write(errmsg,'("Invalid format for count parameters at line ",i4)') line_num
               call MW_errors_runtime_error("read_parameters","species.f90", &
                     errmsg)
            end if
            call MW_configuration_line_get_word(config_line, 2, count)

         case("charge")
            if (charge_defined > 0) then
               write(errmsg,'("At line ",i4,", redefinition of |charge|. First definition at line ",i4,".")') &
                     line_num, charge_defined
               call MW_errors_runtime_error("read_parameters", "species.f90", errmsg)
            end if
            charge_defined = line_num

            ! Read charge type keyword parameters
            if (config_line%num_words < 2) then
               write(errmsg,'("Invalid format for charge parameters at line ",i4)') line_num
               call MW_errors_runtime_error("read_parameters","species.f90", &
                     errmsg)
            end if
            call MW_configuration_line_get_word(config_line, 2, charge_keyword)

            select case(charge_keyword)
            case ("neutral")
               if (config_line%num_words /= 2) then
                  write(errmsg,'("Invalid format for charge parameters at line ",i4)') line_num
                  call MW_errors_runtime_error("read_parameters","species.f90", &
                        errmsg)
               end if
               charge_type = CHARGE_TYPE_NEUTRAL
               charge = 0.0_wp
               eta = 0.0_wp

            case("point")
               if (config_line%num_words /= 3) then
                  write(errmsg,'("Invalid format for charge parameters at line ",i4)') line_num
                  call MW_errors_runtime_error("read_parameters","species.f90", &
                        errmsg)
               end if
               charge_type = CHARGE_TYPE_POINT
               call MW_configuration_line_get_word(config_line, 3, charge)
               eta = 0.0_wp

            case("gaussian")
               if ((config_line%num_words < 3) .or. (config_line%num_words > 4)) then
               end if
               charge_type = CHARGE_TYPE_GAUSSIAN
               if (config_line%num_words == 3) then
                  call MW_configuration_line_get_word(config_line, 3, eta)
                  charge = 0.0_wp
               else if (config_line%num_words == 4) then
                  call MW_configuration_line_get_word(config_line, 3, eta)
                  call MW_configuration_line_get_word(config_line, 4, charge)
               else
                  write(errmsg,'("Invalid format for charge parameters at line ",i4)') line_num
                  call MW_errors_runtime_error("read_parameters","species.f90", &
                        errmsg)
               end if

            case default
               write(errmsg,'("Invalid format for charge type keyword, ",a8,", at line ",i4)') &
                     charge_keyword, line_num
               call MW_errors_runtime_error("read_parameters","species.f90", &
                     errmsg)
            end select

         case("mass")
            if (mass_defined > 0) then
               write(errmsg,'("At line ",i4,", redefinition of |mass|. First definition at line ",i4,".")') &
                     line_num, mass_defined
               call MW_errors_runtime_error("read_parameters", "species.f90", errmsg)
            end if
            mass_defined = line_num

            ! Read length parameters
            if (config_line%num_words /= 2) then
               write(errmsg,'("Invalid format for mass parameters at line ",i4)') line_num
               call MW_errors_runtime_error("read_parameters","species.f90", &
                     errmsg)
            end if
            call MW_configuration_line_get_word(config_line, 2, mass)

         case("polarizability")
            if (polarizability_defined > 0) then
               write(errmsg,'("At line ",i4,", redefinition of |polarizability|. First definition at line ",i4,".")') &
                     line_num, polarizability_defined
               call MW_errors_runtime_error("read_parameters", "species.f90", errmsg)
            end if
            polarizability_defined = line_num

            ! Read length parameters
            if (config_line%num_words /= 2) then
               write(errmsg,'("Invalid format for polarizability parameters at line ",i4)') line_num
               call MW_errors_runtime_error("read_parameters","species.f90", &
                     errmsg)
            end if
            call MW_configuration_line_get_word(config_line, 2, polarizability)
            if (polarizability > 0.0_wp) then
               polarizable = .true.
            end if

         case("deformability")
            if (deformability_defined > 0) then
               write(errmsg,'("At line ",i4,", redefinition of |deformability|. First definition at line ",i4,".")') &
                     line_num, deformability_defined
               call MW_errors_runtime_error("read_parameters", "species.f90", errmsg)
            end if
            deformability_defined = line_num

            ! Read length parameters
            if (config_line%num_words /= 4) then
               write(errmsg,'("Invalid format for deformability parameters at line ",i4)') line_num
               call MW_errors_runtime_error("read_parameters","species.f90", &
                     errmsg)
            end if
            call MW_configuration_line_get_word(config_line, 2, selfdaimD)
            if (selfdaimD > 0.0_wp) then
               deformable = .true.
            end if
            call MW_configuration_line_get_word(config_line, 3, selfdaimbeta)
            call MW_configuration_line_get_word(config_line, 4, selfdaimzeta)

         case("mobile")
            if (mobile_defined > 0) then
               write(errmsg,'("At line ",i4,", redefinition of |mobile|. First definition at line ",i4,".")') &
                     line_num, mobile_defined
               call MW_errors_runtime_error("read_parameters", "species.f90", errmsg)
            end if
            mobile_defined = line_num

            ! Read length parameters
            if (config_line%num_words /= 2) then
               write(errmsg,'("Invalid format for mobile parameters at line ",i4)') line_num
               call MW_errors_runtime_error("read_parameters","species.f90", &
                     errmsg)
            end if
            call MW_configuration_line_get_word(config_line, 2, mobile)

         case("fourth_site_atom")
            if (fourth_site_defined > 0) then
               write(errmsg,'("At line ",i4,", redefinition of |fourth_site_atom|. First definition at line ",i4,".")') &
                     line_num, fourth_site_defined
               call MW_errors_runtime_error("read_parameters", "species.f90", errmsg)
            end if
            fourth_site_defined = line_num

            ! Read length parameters
            if (config_line%num_words /= 1) then
               write(errmsg,'("Invalid format for fourth_site_atom parameters at line ",i4)') line_num
               call MW_errors_runtime_error("read_parameters","species.f90", &
                     errmsg)
            end if
            fourth_site = .true.

         case("dump_efg")
            if (dump_efg_defined > 0) then
               write(errmsg,'("At line ",i4,", redefinition of |dump_efg|. First definition at line ",i4,".")') &
                     line_num, dump_efg_defined
               call MW_errors_runtime_error("read_parameters", "species.f90", errmsg)
            end if
            dump_efg_defined = line_num

            ! Read length parameters
            if (config_line%num_words /= 2) then
               write(errmsg,'("Invalid format for mobile parameters at line ",i4)') line_num
               call MW_errors_runtime_error("read_parameters","species.f90", &
                     errmsg)
            end if
            call MW_configuration_line_get_word(config_line, 2, dump_efg)

         case("dump_lammps")
            if (dump_lammps_defined > 0) then
               write(errmsg,'("At line ",i4,", redefinition of |dump_lammps|. First definition at line ",i4,".")') &
                     line_num, dump_lammps_defined
               call MW_errors_runtime_error("read_parameters", "species.f90", errmsg)
            end if
            dump_lammps_defined = line_num

            ! Read length parameters
            if (config_line%num_words /= 2) then
               write(errmsg,'("Invalid format for mobile parameters at line ",i4)') line_num
               call MW_errors_runtime_error("read_parameters","species.f90", &
                     errmsg)
            end if
            call MW_configuration_line_get_word(config_line, 2, dump_lammps)

         case("dump_xyz")
            if (dump_xyz_defined > 0) then
               write(errmsg,'("At line ",i4,", redefinition of |dump_xyz|. First definition at line ",i4,".")') &
                     line_num, dump_xyz_defined
               call MW_errors_runtime_error("read_parameters", "species.f90", errmsg)
            end if
            dump_xyz_defined = line_num

            ! Read length parameters
            if (config_line%num_words /= 2) then
               write(errmsg,'("Invalid format for mobile parameters at line ",i4)') line_num
               call MW_errors_runtime_error("read_parameters","species.f90", &
                     errmsg)
            end if
            call MW_configuration_line_get_word(config_line, 2, dump_xyz)

         case("dump_trajectories")
            if (dump_trajectories_defined > 0) then
               write(errmsg,'("At line ",i4,", redefinition of |dump_trajectories|. First definition at line ",i4,".")') &
                     line_num, dump_trajectories_defined
               call MW_errors_runtime_error("read_parameters", "species.f90", errmsg)
            end if
            dump_trajectories_defined = line_num

            ! Read length parameters
            if (config_line%num_words /= 2) then
               write(errmsg,'("Invalid format for mobile parameters at line ",i4)') line_num
               call MW_errors_runtime_error("read_parameters","species.f90", &
                     errmsg)
            end if
            call MW_configuration_line_get_word(config_line, 2, dump_trajectories)

         case("dump_pdb")
            if (dump_pdb_defined > 0) then
               write(errmsg,'("At line ",i4,", redefinition of |dump_pdb|. First definition at line ",i4,".")') &
                     line_num, dump_pdb_defined
               call MW_errors_runtime_error("read_parameters", "species.f90", errmsg)
            end if
            dump_pdb_defined = line_num

            ! Read length parameters
            if (config_line%num_words /= 2) then
               write(errmsg,'("Invalid format for mobile parameters at line ",i4)') line_num
               call MW_errors_runtime_error("read_parameters","species.f90", &
                     errmsg)
            end if
            call MW_configuration_line_get_word(config_line, 2, dump_pdb)

         case default
            ! Keyword not expected in box section assume end of box section
            ! Backspace to previous line and give hand back to parent box
            backspace(funit)
            line_num = line_num - 1
            exit keywordLoop

         end select
         call MW_configuration_line_seek_next_data(config_line, funit, line_num)
      end do keywordLoop

      call set_name(this, name)
      call set_count(this, count)
      mass = mass*amu2me ! mass conversion from amu to m_e
      call set_mass(this,mass)
      select case(charge_type)
      case(CHARGE_TYPE_NEUTRAL)
         call set_charge_neutral(this)
      case(CHARGE_TYPE_POINT)
         call set_charge_point(this, charge)
      case(CHARGE_TYPE_GAUSSIAN)
         call set_charge_gaussian(this, charge, eta)
      case default
         call set_charge_neutral(this)
      end select
      call set_polarizable(this,polarizable)
      call set_polarizability(this,polarizability)
      call set_deformable(this,deformable)
      call set_deformability(this,selfdaimD,selfdaimbeta,selfdaimzeta)
      call set_fourth_site(this, fourth_site)
      call set_mobility(this, mobile)
      call set_dump_efg(this, dump_efg)
      call set_dump_lammps(this, dump_lammps)
      call set_dump_xyz(this, dump_xyz)
      call set_dump_trajectories(this, dump_trajectories)
      call set_dump_pdb(this, dump_pdb)
   end subroutine read_parameters

end module MW_species
