4.5. Fortran 90 implementation of the Midpoint integrator

4.5.1. The Midpoint module implementation

  • After the Fortran 90 code has been generated by Babel, in student-src/components/integrators/f90, edit the Fortran module definition to define data that will be stored in each instance of this component:

    file: student-src/components/integrators/f90/integrators_Midpoint_Mod.F90
    #include"integrators_Midpoint_fAbbrev.h"
    module integrators_Midpoint_impl
    
    ! DO-NOT-DELETE splicer.begin(integrators.Midpoint.use)
    ! Insert use statements here...
    
    ! CCA framework services module
    use gov_cca_Services
    
    ! Use a "wrapper" module for the legacy FunctionModule module
    use FunctionModule                                         (1)
    
    ! Use legacy Integrator module
    use Integrator                                             (2)
    
    ! DO-NOT-DELETE splicer.end(integrators.Midpoint.use)
    
    type integrators_Midpoint_priv
      sequence
      ! DO-NOT-DELETE splicer.begin(integrators.Midpoint.private_data)
      
      ! Handle to framework Services object
      type(gov_cca_Services_t) :: frameworkServices            (3)
    
      ! Function parameters (required by legacy integrator)
      type(FunctionParams_t) :: funcParams                     (4)
      
      ! DO-NOT-DELETE splicer.end(integrators.Midpoint.private_data)
    end type integrators_Midpoint_priv
    
    type integrators_Midpoint_wrap
      sequence
      type(integrators_Midpoint_priv), pointer :: d_private_data
    end type integrators_Midpoint_wrap
    
    end module integrators_Midpoint_impl
    

    Notes on the integrators_Midpoint_Mod.F90 file

    1

    The integrators_Midpoint module uses the FunctionModule, which means that the integrator can only evaluate functions defined in this FunctionModule, or other Fortran modules that "extend" it.

    3

    This component stores a handle to the framework's Services object, equivalently to the way the Driver component was implemented in Step 2.

    2

    The legacy Integrator module is included.

    4

    The integrators.Midpoint component, like the legacy integrator (see Integrator.f90) requires that the function whose integral is to be computed provides its state via the FunctionParams_t type.

4.5.2. Defining the constructor and destructor

In the same directory (student-src/components/integrators/f90), edit the integrators_Midpoint_Impl.F90 and insert the code between splicer blocks of the integrators_Midpoint__ctor_mi, integrators_Midpoint__dtor_mi, and setServices subroutines:

file: student-src/components/integrators/f90/integrators_Midpoint_Impl.F90

...

! 
! Class constructor called when the class is created.
! 

recursive subroutine integrators_Midpoint__ctor_mi(self)
  use integrators_Midpoint
  use integrators_Midpoint_impl
  ! DO-NOT-DELETE splicer.begin(integrators.Midpoint._ctor.use)
  ! Insert use statements here...
  ! DO-NOT-DELETE splicer.end(integrators.Midpoint._ctor.use)
  implicit none
  type(integrators_Midpoint_t) :: self ! in

! DO-NOT-DELETE splicer.begin(integrators.Midpoint._ctor)
! Insert the implementation here...
  
  ! Access private data
  type(integrators_Midpoint_wrap) :: dp
  ! Allocate memory and initialize
  allocate(dp%d_private_data)
  call set_null(dp%d_private_data%frameworkServices)
  call integrators_Midpoint__set_data_m(self, dp)

! DO-NOT-DELETE splicer.end(integrators.Midpoint._ctor)
end subroutine integrators_Midpoint__ctor_mi

! 
! Class destructor called when the class is deleted.
! 

recursive subroutine integrators_Midpoint__dtor_mi(self)
  use integrators_Midpoint
  use integrators_Midpoint_impl
  ! DO-NOT-DELETE splicer.begin(integrators.Midpoint._dtor.use)
  ! Insert use statements here...
  ! DO-NOT-DELETE splicer.end(integrators.Midpoint._dtor.use)
  implicit none
  type(integrators_Midpoint_t) :: self ! in

! DO-NOT-DELETE splicer.begin(integrators.Midpoint._dtor)
! Insert the implementation here...
  
  ! Access private data and deallocate storage
  type(integrators_Midpoint_wrap) :: dp
  call integrators_Midpoint__get_data_m(self, dp)

  ! Decrement reference count for framework services handle
  if (not_null(dp%d_private_data%frameworkServices)) then
     call deleteRef(dp%d_private_data%frameworkServices)
  end if

  deallocate(dp%d_private_data)

! DO-NOT-DELETE splicer.end(integrators.Midpoint._dtor)
end subroutine integrators_Midpoint__dtor_mi

4.5.3. The setServices implementation

In this step we continue to edit the student-src/components/integrators/f90/integrators_Midpoint_Impl.F90 file, adding the implementation of the setServices subroutine, which is part of the gov.cca.Component. Note that in order to accommodate identifier length restriction in Fortran (31 characters), the name of the subroutine was automatically shortened by Babel. The unmangled name is always visible in the comment preceding the subroutine in the Fortran generated code.

...
recursive subroutine Midpoi_setServices6_m9htaw4m_mi(self, services,           &
  exception)
  use sidl_BaseInterface
  use integrators_Midpoint
  use gov_cca_Services
  use gov_cca_CCAException
  use integrators_Midpoint_impl
  ! DO-NOT-DELETE splicer.begin(integrators.Midpoint.setServices.use)
  ! Insert use statements here...
  
  use gov_cca_TypeMap
  use gov_cca_Port
  use SIDL_BaseInterface
 
  ! DO-NOT-DELETE splicer.end(integrators.Midpoint.setServices.use)
  implicit none
  type(integrators_Midpoint_t) :: self ! in
  type(gov_cca_Services_t) :: services ! in
  type(sidl_BaseInterface_t) :: exception ! out

! DO-NOT-DELETE splicer.begin(integrators.Midpoint.setServices)
! Insert the implementation here...
 
  type(gov_cca_TypeMap_t)    :: myTypeMap
  type(gov_cca_Port_t)       :: integratorPort
  type(SIDL_BaseInterface_t) :: excpt
  ! Access private data
  type(integrators_Midpoint_wrap) :: dp
  call integrators_Midpoint__get_data_m(self, dp)

  ! Set my reference to the services handle
  dp%d_private_data%frameworkServices = services

  call addRef(services)
  
  ! Create a TypeMap with my properties
  call createTypeMap(dp%d_private_data%frameworkServices, myTypeMap, excpt)
  call checkExceptionMid(excpt, 'setServices createTypeMap call')

  call cast(self, integratorPort)

  ! Register my provides port
  call addProvidesPort(dp%d_private_data%frameworkServices, integratorPort, &
                       'IntegratorPort', 'integrator.IntegratorPort', &
                       myTypeMap, excpt)
  call checkExceptionMid(excpt, 'setServices addProvidesPort: IntegratorPort')

  ! The ports I use
  call registerUsesPort(dp%d_private_data%frameworkServices, &
                          'FunctionPort', 'function.FunctionPort', &
                          myTypeMap, excpt)
  call checkExceptionMid(excpt, 'setServices registerUsesPort: FunctionPort')

  call deleteRef(myTypeMap)
 
! DO-NOT-DELETE splicer.end(integrators.Midpoint.setServices)
end subroutine Midpoi_setServices6_m9htaw4m_mi

4.5.4. The integrate implementation

Continuing your edits in the integrators_Midpoint_Impl.F90 file, fill in the implementation of the integrator.IntegratorPort interface component, inserting the call to the legacy integrator in the integrate method.

file: student-src/components/integrators/f90/integrators_Midpoint_Impl.F90
recursive subroutine Midpoint_integrateekg4n6wqha_mi(self, lowBound, upBound,  &
  count, retval)
  use integrators_Midpoint
  use integrators_Midpoint_impl
  ! DO-NOT-DELETE splicer.begin(integrators.Midpoint.integrate.use)
  ! Insert use statements here...
 
  use function_FunctionPort
  use randomgen_RandomGeneratorPort
  use gov_cca_Services
  use gov_cca_Port
  use sidl_BaseInterface
  
  use Integrator        ! Legacy integrator module
  use FunctionModule    ! Legacy function module wrapper
 
  ! DO-NOT-DELETE splicer.end(integrators.Midpoint.integrate.use)
  implicit none
  type(integrators_Midpoint_t) :: self ! in
  real (selected_real_kind(15, 307)) :: lowBound ! in
  real (selected_real_kind(15, 307)) :: upBound ! in
  integer (selected_int_kind(9)) :: count ! in
  real (selected_real_kind(15, 307)) :: retval ! out

! DO-NOT-DELETE splicer.begin(integrators.Midpoint.integrate)
! Insert the implementation here...
 
  type(gov_cca_Port_t) :: generalPort
  type(function_FunctionPort_t) :: functionPort
  type(randomgen_RandomGeneratorPort_t) :: randomPort
  type(SIDL_BaseInterface_t) :: excpt

  ! Legacy types and wrappers:
  type(FunctionParams_t) :: funParams

  ! Private data reference
  type(integrators_Midpoint_wrap) :: dp

  ! Copies of base type arguments to the integrate method
  real :: lbnd, ubnd
  integer :: cnt

  real (selected_real_kind(15, 307)) :: sum, width, x, func
  integer (selected_int_kind(9)) :: i

  ! Access private data
  call integrators_Midpoint__get_data_m(self, dp)
  retval = -1

  if (not_null(dp%d_private_data%frameworkServices)) then

     ! Obtain a handle to a FunctionPort
     call getPort(dp%d_private_data%frameworkServices, &
          'FunctionPort', generalPort, excpt)

     if (is_null(excpt)) then

        call cast(generalPort, functionPort)
        if (not_null(functionPort)) then
           
           ! Set the function port in the FunctionModule wrapper
           call setFunctionPort(funParams, functionPort) 

           ! Invoke legacy integrator algorithm to compute integral
           lbnd = lowBound
           ubnd = upBound
           cnt = count
           retval = integrate_mp(funParams, lbnd, ubnd, cnt)

        else   ! functionPort is null
           write(*,*) 'Exception: Midpoint: incompatible FunctionPort'
        endif

        ! Free ports
        call releasePort(dp%d_private_data%frameworkServices, &
             'FunctionPort', excpt)
        call checkExceptionMid(excpt, 'releasePort(''FunctionPort'')')

     else  ! excpt is not null

        call checkExceptionMid(excpt, 'getPort(''FunctionPort'')')

    endif
  else    ! frameworkServices is null
     write(*,*) 'Error: Midpoint: integrate called before setServices'
  endif
 
! DO-NOT-DELETE splicer.end(integrators.Midpoint.integrate)
end subroutine Midpoint_integrateekg4n6wqha_mi

Finally, in the integrators_Midpoint_Impl.F90 file, find the very last splicer block (labeled _miscellaneous_code_end) and add the following helper subroutine:

file: student-src/components/integrators/f90/integrators_Midpoint_Impl.F90
! 
! Small routine (not part of the SIDL interface) for 
! checking the exception and printing the message passed as
! and argument
!
subroutine checkExceptionMid(excpt, msg)
  use SIDL_BaseInterface
  use gov_cca_CCAException
  implicit none
  type(sidl_BaseInterface_t), intent(inout) :: excpt  
  character (len=*) :: msg ! in
  if (not_null(excpt)) then
      write(*, *) 'integrators.Midpoint Exception: ', msg
      call deleteRef(excpt)
  end if
end subroutine checkExceptionMid