Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass data as pointer #4

Closed
Nicholaswogan opened this issue Nov 27, 2021 · 3 comments
Closed

Pass data as pointer #4

Nicholaswogan opened this issue Nov 27, 2021 · 3 comments

Comments

@Nicholaswogan
Copy link

It would be nice if data could be passed to the objective function. This could be done with a void C pointer, type(c_ptr), or any other method. Right now data must be passed globally, which makes programs not thread-safe.

@jacobwilliams
Copy link
Member

You don't have to use global variables. You can wrap the call in a class method. So your data lives in the class. Something like this:

module my_module

  use minpack_module
  use iso_fortran_env, only: wp => real64

  implicit none

  type :: my_solver_t
    integer :: some_data ! your data
    contains
    procedure :: solve
  end type my_solver_t

  type(my_solver_t) :: my_solver_1
  type(my_solver_t) :: my_solver_2

  ...

  contains

  subroutine solve(me)

    class(my_solver_t),intent(inout) :: me
    
    call hybrd(fcn, ...)
    
  contains

    subroutine fcn(n,x,fvec,iflag)

    integer,intent(in) :: n  
    real(wp),intent(in) :: x(n)  
    real(wp),intent(out) :: fvec(n)  
    integer,intent(inout) :: iflag 

    ! can use me%some_data here !
    ...

    end subroutine fcn

  end subroutine solve

end module my_module

Eventually I might just make this part of the library. This is the modern way to do it.

@Nicholaswogan
Copy link
Author

Thanks!!

@ivan-pi
Copy link
Member

ivan-pi commented Feb 6, 2022

The pattern shown by @jacobwilliams is quite interesting. On the other hand it's a kind of Frankenstein between data container, callback function, and the actual solver algorithm. Say I want to swap between MINPACK and Ceres (or any other least squares solver). Where is my design breakpoint?

Would I introduce separate procedures, i.e.

subroutine solve_minpack()
! ...
subroutine solve_ceres()
! ...

Or would I introduce a method argument? Here's some pseudo-code

subroutine solve(me,method)
type(my_solver_t), intent(inout) :: me
character(len=*), intent(in), optional :: method
character(len=:), allocatable :: method_

method_ = "minpack"
if (present(method)) method_ = lowercase(method)

select case (method_)
case('minpack')
   call hybrd(...)
case('ceres')
   call ceres_optimize(...) ! ...
case default
  error stop 'my_solver_t%solve: unknown method, available options are "minpack" (default) or "ceres"'
end select

end subroutine

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants