2015-09-03 4 views
1

Я не хочу использовать общие блоки в своей программе. Моя основная программа вызывает подпрограмму, которая вызывает функцию. Функция нуждается в переменных из подпрограммы.Каковы способы передачи набора переменных значений через подпрограмму функции без общего блока?

Каковы способы передачи набора данных из подпрограммы в функцию?

program 
... 

call CONDAT(i,j) 

end program 

SUBROUTINE CONDAT(i,j) 

common /contact/ iab11,iab22,xx2,yy2,zz2 
common /ellip/ b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2 
call function f(x) 
RETURN 
END 

function f(x) 
common /contact/ iab11,iab22,xx2,yy2,zz2 
common /ellip/ b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2 
end 
+2

процедуры принимают аргументы. Передавайте данные в качестве аргументов и используйте их при вызове других. – casey

+0

Не могли бы вы предоставить определенный код, чтобы показать, что вы на самом деле не понимаете? Как сказал Кейси, в основном нет разницы в передаче аргументов подпрограммам или процедурам, поэтому для меня это немного немного непонятно, к чему стремится ваш вопрос. – haraldkl

+0

Спасибо Кейси и Харальдл. Я редактировал свой вопрос с примера. Мой вопрос заключается в том, как передать переменные в общем блоке «контакт и эллип» из подпрограммы «CONDAT» в функцию f (x) без использования общего блока. – sam

ответ

3

Ниже приведен пример того, как можно достичь этого ...

код был адаптирован из метода BFGS, чтобы показать, как вы можете передать функции и вызывать другие функции в модуле ...

Здесь я использую:

  • частные функции, вложенные в других подпрограммах
  • переменные переходят из подпрограммы в вложенная функция
  • передать функцию в качестве аргумента для функции, которая может быть определена вне блока модуля

Надеемся, что это будет охватывать все для вас ...

Module Mod_Example 

Private :: private_func 

    SUBROUTINE test_routine(res,start,fin,vector,func,dfunc) 
     IMPLICIT NONE 
     REAL, DIMENSION(:), INTENT(IN) :: res, start, fin 
     REAL, DIMENSION(:), INTENT(INOUT) :: vector 

     INTERFACE 
     FUNCTION func(vector)          
      IMPLICIT NONE          
      REAL, DIMENSION(:), INTENT(IN) :: vector     
      REAL :: func          
     END FUNCTION func          

     FUNCTION dfunc(vector)          
      IMPLICIT NONE          
      REAL, DIMENSION(:), INTENT(IN) :: vector    
      REAL, DIMENSION(size(vector)) :: dfunc     
     END FUNCTION dfunc          
     END INTERFACE 

     ! do stuff with p 

     private_func(res,start,fin,vector,func,dfunc) 

     ! do stuff 
    END SUBROUTINE test_routine 

    SUBROUTINE private_func(res,start,fin,vector,func,dfunc) 
     IMPLICIT NONE 
     REAL, DIMENSION(:), INTENT(IN) :: res, start, fin 
     REAL, DIMENSION(:), INTENT(INOUT) :: vector 
     INTERFACE 
     FUNCTION func(vector)    
      REAL, DIMENSION(:), INTENT(IN) :: vector 
      REAL :: func 
     END FUNCTION func 
     FUNCTION dfunc(vector) 
      REAL, DIMENSION(:), INTENT(IN) :: vector 
      REAL, DIMENSION(size(vector)) :: dfunc 
     END FUNCTION dfunc  
     END INTERFACE 

     ! do stuff    
    END SUBROUTINE private_func 

END Mod_Example 
  • func и dfunc будет объявлен в программном коде, который использует MODULE Mod_Example с интерфейсным блоком в верхней части.
  • переменные: res, start и т. Д. Могут быть объявлены со значениями в основном программном блоке и переданы в SUBROUTINE test_routine в качестве аргументов.
  • SUBROUTINE test_routine будет вызывать private_func с переменными, которые были переданы ему.

Ваша основная программа будет выглядеть примерно так:

Program Main_Program 
    USE Mod_Example 
    INTERFACE 
     FUNCTION func(vector)    
     REAL, DIMENSION(:), INTENT(IN) :: vector 
     REAL :: func 
     END FUNCTION func 
     FUNCTION dfunc(vector) 
     REAL, DIMENSION(:), INTENT(IN) :: vector 
     REAL, DIMENSION(size(vector)) :: dfunc 
     END FUNCTION dfunc  
    END INTERFACE 

    ! do stuff  

    ! calls test_routine form module 
    ! uses dfunc and func defined below 
    call test_routine(res,start,fin,vector,func,dfunc) 

    ! do stuff 
END PROGRAM Main_Program 

! define dfunc and nfunc for passing into the modular subroutine 
FUNCTION func(vector) 
    IMPLICIT NONE 
    REAL, DIMENSION(:), INTENT(IN) :: vector 
    REAL :: func 

    nfunc = vector 
END FUNCTION func 

FUNCTION dfunc(vector) 
    IMPLICIT NONE 
    REAL, DIMENSION(:), INTENT(IN) :: vector 
    REAL, DIMENSION(size(vector)) :: dfunc 

    dfunc = vector 
END FUNCTION dfunc 
+0

Спасибо Alexander. Я обязательно попробую с модулем и сообщит, если он работает или нет. Таким образом, нет способа без общего блока или модуля передавать информацию? – sam

+0

@SadiaF модуль не требуется. Также я не уверен, что вам действительно нужна функция в качестве аргумента. Из вашего кода это выглядит как обычный вызов. – haraldkl

+0

Хорошо, что вы правы, это обычный вызов, но я добавил функцию, чтобы продемонстрировать, как это можно сделать. Также я считаю, что модули делают большие проекты намного легче обрабатывать –

3

Так, в принципе вы могли бы решить эту проблему с чем-то вдоль этих линий:

SUBROUTINE CONDACT(i,j, iab11,iab22,xx2,yy2,zz2,b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2,res) 
    !declaration to all those parameters and res 
    res = f(x) 
END SUBROUTINE CONDACT 

function f(x,iab11,iab22,xx2,yy2,zz2,b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2) 
!declaration to all those parameters 
end function f 

program 
    ... 

    call CONDAT(i,j,iab11,iab22,xx2,yy2,zz2,b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2,res) 

end program 

То есть, просто передавая параметры через. Настоятельно рекомендуется использовать модули, см. Ответ Александра МакФарлейна, хотя это не требуется. Александр МакФарлейн показывает, как передать f в качестве аргумента в подпрограмму, чтобы вы могли использовать разные функции в подпрограмме, но ваш код, похоже, не требует этого.

Теперь это ужасный длинный список параметров, и вы, вероятно, не хотите носить с собой все это время. Обычный подход к решению этого вопроса состоит в том, чтобы поместить эти параметры в derived datatype, а затем просто передать это. Как это:

!> A module implementing ellip related stuff. 
module ellip_module 

    implicit none 

    type ellip_type 
    !whatever datatypes these need to be... 
    integer :: b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2 
    end type 
end module ellip_module 


!> A module implementing condact related stuff. 
module condact_module 
    use ellip_module ! Make use of the ellip module to have the type available 

    implicit none 

    type condact_type 
    !whatever datatypes these need to be... 
    integer :: iab11,iab22,xx2,yy2,zz2 
    end type 

    contains 

    subroutine condact(i,j, con, ellip, res) 
    integer :: i,j 
    type(condact_type) :: con 
    type(ellip_type) :: ellip 
    real :: res 

    real :: x 
    res = f(x, con, ellip) 
    end subroutine condact 

    function f(x, con, ellip) result(res) 
    real :: x 
    real :: res 
    type(condact_type) :: con 
    type(ellip_type) :: ellip 

    res = !whatever this should do 
    end function f 
end module condact_module 


!> A program using the condact functionality. 
program test_condact 
    use ellip_module 
    use condact_module 

    implicit none 

    type(condact_type) :: mycon 
    type(ellip_type) :: myellip 
    integer :: i,j 
    real :: res 

    call condact(i,j, mycon, myellip, res) 
end program test_condact 

Это просто грубый набросок, но у меня сложилось впечатление, что это то, что вы ищете.

+0

большое спасибо. Я многое узнал из вашего ответа. – sam

+0

@SadiaF Нет проблем, я надеюсь, что вы разобрались со своими обычаями. Насколько я понял, наилучшим вариантом для OpenMP-распараллеливания было бы определить локальные переменные типа эллип и тип контакта в вашей программе ford и передать их. Поскольку ваш цикл OpenMP находится снаружи, они будут полностью закрыты без дальнейших церемоний. – haraldkl

+0

Локализация переменной не работает. Поскольку подпрограммы перезаписывают и обмениваются переменными. Мой старый код написан FORTRAN77. модуль не работает на 77! Мне интересно, что делать дальше! – sam

6

То, что вы заботитесь о здесь ассоциации: вы хотите, чтобы иметь возможность связать объекты в функции f с теми, в подпрограмме condat. Хранение ассоциации является одним из способов сделать это, что делает общий блок.

Существуют и другие формы ассоциации, которые могут быть полезны. Они

  • использование ассоциация
  • хоста ассоциация
  • аргумента ассоциация

Аргумент ассоциация описаны в haraldkl's answer.

Использование ассоциация приходит через модули как

module global_variables 
    implicit none  ! I'm guessing on declarations, but that's not important 
    public ! Which is the default 
    real b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2,xx2,yy2,zz2 
    integer iab11,iab22 
end module 

subroutine condat(i,j) 
    use global_variables ! Those public things are use associated 
    ... 
end subroutine 

function f(x) 
    use global_variables ! And the same entities are accessible here 
    ... 
end function 

Принимающая ассоциация иметь доступ к лицам, доступных для хоста. Хозяин здесь мог бы с пользой быть модулем или программа

module everything 
    integer iab11,... 
    real ... 
contains 
    subroutine condat(i,j) 
    ! iab11 available from the host module 
    end subroutine 

    function f(x) 
    ! iab11 available from the host module 
    end function 
end module 

или даже сама подпрограмма

subroutine condat(i,j) 
    integer iab11,... 
    real ... 
contains 
    function f(x) 
    ! Host condat's iab11 is accessible here 
    end function 
end subroutine 
+0

Большое спасибо! Я буду использовать «ассоциацию использования» и дам вам знать, работает ли она или нет. – sam