- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
I would like to ask you for advice.
How to pass a, b from subp to fcn in following code?
------------------------
program passing_vars
implicit none
real a, b
external subp
call subp(a, b)
end program passing_vars
subroutine subp(a, b)
real a, b
external fcn
...
end subroutine subp
subroutine fcn
...
end subroutine fcn
------------------------
COMMON and MODULE end with #6401 error code.
The only ugly way I found was to assign the a, b to a_, b_ and then thay can be passed to fcn using common block.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I dont want to use such surrogates because in some of the problems I have already computed and solved with Fortan/IMSL, I have quite big arrays. I know how to pass big arrays VB <-> Fortran but unfortunately it seems Fortran cannot pass them to its own external subroutine then.
But it is not a feature unique to Fortran, but to virtually all programming languages. The problem is that the interface between the IMSL routine (IVPAG) and your fcn is given, and you cannot change it. If you need additional parameters to pass to the fcn, you must submit your own mechanism, because there's no path for them to go through IVPAG.
Please give yourself a freedom to design the language as you wish -- which syntax would you use to achieve what you want without using an external module or common block (with the only limit being that you mustn't change the prototype of IVPAG)?
(In C/C++ you could use an additional void* argument used to pass any sort of data through, but the library routine (IVPAG) would have to be extended allow that. Fortran could also do that with a little hacking around. But I digress).
On to your real-life problem: Arjen's example is still valid, but you don't have to physically copy the data into module variables. If your working arrays are large, you can declare POINTER arrays in fcn_module, and point (=>) to your original data rather than copy them into the fcn_module.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Why not simply use
call fcn(a,b)
in subp?
and declare
subroutine fcn(a,b)
real a,b
...
end subroutine fcn
Jakub
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Sorry if I didn't understand your problem correctly but, is there anything wrong with just using arguments here?
You mentioned MODULE, so I suggest you to just stick to that and forget about COMMON blocks (unless there's a compelling reason to use COMMON blocks). CONTAINed procedures in the PROGRAM unit are also an option. Finally, the INTENT attribute may help you identify what's wrong with your code. Say:
program passing_vars
implicit none
real a, b
call subp(a, b)
contains
subroutine subp(a, b)
real, intent(INOUT) :: a, b
!...
end subroutine subp
subroutine fcn(a,b)
real, intent(IN) :: a
real, intent(INOUT) :: b
!...
end subroutine fcn
end program passing_vars
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Thanks for answers but I mustn't use 'contains' and and mustn't pass vars as function parameters. The reason is simple: both subp and fcn must be external and more complicated - fcn interface is already defined (this is IMSL part).
So the only way I was thinking will pass my variables from subp to fcn will be module (I tested it first because I know it is superior to commonblock) or common block. Both don't work as the compiler complains that subp has already the definition as parameters:
error #6401: The attributes of this name conflict with those made accessible by a USE statement.
or if I don't do 'REAL a, b'
error #6404: This name does not have a type, and must have an explicit type.
The only way to compile such program is not to use 'implicit none', program compiles then but a, b are assumed integer I think (that I don't want).
I put this simple test, you might copy/paste:
module ab
real a, b
end module ab
program passing_vars
implicit none
real a, b
external subp
call subp(a, b)
end program passing_vars
subroutine subp(a, b)
use ab
implicit none
real a, b
external fcn
!---here I do some code that calls IMSL procedure which takes fcn as parameter so I can't pass vars as arguments
!see I don't call fcn directly - CALL IVPAG (IDO, FCN, FCNJ, t1, t2, x, TOL=TOL)
end subroutine subp
subroutine fcn(n, t, x, dxdt)
use ab
implicit none
integer n
real*8 t, x(n), dxdt(n)
!--- here I need my variables
end subroutine fcn
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
And I outrun next 'why' questions :)
Why I define subp as external?
I need my subp to be external because it is finally supposed to be exported as dll
why I need dll?
Because I want to code the front of my program in Visual Basic which is much, much easier to code than Fortran Windowing application and gives the same functionality to me. So I mix easiness of form coding in VB NET with computational power of Fortran.
regards,
Maciej
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
FCN represents the mathematical function y' = f(t,y), and therefore the only things that should vary within your function are t, y (as input/intent(in)) and the result y' (as output/intent(out)). Anything else in FCN should be constant or local to the FCN subroutine; if it isn't, then your code might be subject to unexpected side-effects.
You really don't know what's going on within the IVPAG subroutine, you don't know when or how many times the FCN subroutine is going to be invoked so the code within FCN shouldn't depend on global variables;in a worst case scenario, IVPAG might invoke FCN with a modified/normalized version of T and Y. Those are things you don't have control about, so try to keep FCN as simple as possible ---think of FCN as if it were PURE.
I suggest you re-check the usage notes on IVPAG.
Also, EXTERNAL is a blurry concept within IMSL (since I remember to have provided module procedures to IMSL routines, in the past). And for dll purposes, what you need is the DLLEXPORT attribute in a compiler directive, rather than the EXTERNAL statement.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks John!
I know that I shouldn't change anything in FCN during integrating. And I even don't intend so. I only need to pass variables. You can easily imagine that the Y and YPRIME are not the only that I must use in my problem - there can be density, viscosity etc etc that I have to know inside FCN and that will not change during one step of integration.
I also know how to work with DLLEXPORT - I already made a few applications that mix VBNET and Visual Fortran. So the reason I do this using EXTERNAL is only for testing purposes because the dll also will be treated as external to VB code. So my main program calls external subp just as in next step will VB do. It's only for testing because it's easier to work with one language first and when that works - then make a mix.
best regards,
Maciej
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
And maybe there is no elegant solution? And I must do what I don't like:
module ab
real a_, b_
end module ab
and somewhere in subp before CALL IVPAG:
a_ = a
b_ = b
and in FCN use a_, b_
That works. I checked. But I think it's so ugly and ineffective especially for many variables...
regards,
Maciej
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm not sure if you understand that FCN, in IVPAG's case, is just a callback procedure. You are not supposed to invoke it directly (unless it's an intermediate step) ---you don't even have to name it FCN and the argument names don't have to be N, T, Y and YPRIME; only the types and shapes/ranks must match, and the N, T and Y arguments are "dummy" representations of the NEQ, T and Y you pass to IVPAG---. You just call IVPAG for different time steps and perform intermediate computations between those time steps (again, take a look at the example(s) provided with the IMSL documentation). If you really need to use more variables than the ones required in FCN, then either you either failed to state the problem correctly or IVPAG is not the right routine for your problem.
And being EXTERNAL in Fortran doesn't have anything to do with being External? in VB. Visual Basic only needs an import library, and that's what DLLEXPORT is for.
It's funny that you asked for help, but keep finding ways to justify a wrong approach to a problem.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
John, I know all that, I have no problems computing with FCN and exporting to VB.
I just wanted to pass values to FCN in elegant way without introducing additional variables.
Just imagine very, very simple initial value problem:
dC/dt=-k*C
(YPRIME(1) = -k * Y(1))
So it turns out that I really need that k value to be passed. In my several years of working with IMSL I do it using MODULE, but this environment is little bit different now. So I asked for advice.
I also know I can use different names for variables and also for FCN. I do so when I solve several problems in one program. In fact I use IVPAG from those times when it was called DGEAR - quite long ago, isn't it.
I also know that EXTERNAL doesn't have anything with DLLEXPORT. I don't want to scatter the discussion to this subject.
And finally - do you know the elegant solution to pass those vars?
regards,
Maciej
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am also using this "ugly" solution using module when calling imsl routines. I think it is only way.
Jakub
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
What I've been trying to explain is that you should never try to modify module variables from within FCN (or FCNJ); also, if you need module variable y to be accessible from within FCN, then try to rename the argument "y" to something else (as I told you, the name doesn't matter). Also, you shouldn't rely on FCN computing values only at the exact "t" and "tend" values you provided; IVPAG might chose to call FCN for t=t+dt, when dt is some intermediate increment arbitrarily chosen, so you should try to make FCN as general as possible, and minimize the possibility of errors during the computations (i.e., it should behave as PURE).
Maybe the following will help:
module mod1
real, protected :: viscosity, density
real :: t, y
!...
end module mod1
module mod2
!...
contains
subroutine subp()
use mod1
!...
condition = .TRUE.
do while (condition)
!do some computations here, maybe to update viscosity and density
call IVPAG (IDO, fcn, fcnj, t, tend, y)
!do some other computations here
if (...) then
!check if condition is still strue and IVPAG needs to be called again
endif
enddo
!...
end subroutine subp
subroutine fcn(nx, tx, yx, yprimex)
use mod1
integer, intent(IN) :: nx
real, intent(IN) :: tx, yx
real, intent(OUT) :: yprimex
!whitin this subroutine, you'll have "read-only" access to viscosity and
! density, i.e., their values cannot depend on (t,y) or (tx,yx)
!you also have access to t and y, but you shouldn't use their values at all, since
! they're being modified by IVPAG
!tx and yx might have the same values as t and y, but you cannot be sure
!...
end subroutine fcn
!...
end module mod2
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jakub, Fortunately I dont mean that using MODULE is ugly.
By the ugly solution I mean the need of using surrogate variables. Below example solves my problem with this ugly way.
------------------------------------
module ab
real a_, b_
end module ab
program passing_vars
implicit none
real a, b
external subp
call subp(a, b)
end program passing_vars
subroutine subp(a, b)
use ab
implicit none
real a, b
external my_fcn
a_ = a !here I have to use the surrogate that will be accessible in FCN
b_ = b !here also I have to use the surrogate that will be accessible in FCN
!CALL IVPAG (IDO, MY_FCN, FCNJ, tau1, tau2, x, TOL=TOL)
end subroutine subp
subroutine my_fcn(n, tau, x, dxdt)
use ab
implicit none
integer n
real*8 tau, x(n), dxdt(n)
!here I use the surrogates: a_, b_ - this is the ugly way. I thought I can pass a, b
end subroutine fcn
------------------------------------
This compiles succesfly and works. For small amount of data it can be OK.
But if I will have a number of big arrays it can be very ineffective - I will have to declare double number of memory space to make this copy. This is ugly - not the module itself.
As I seem not to see from your answers - there probably is no solution to that passing variables problem.
Is it just Fortran limitation by design?
regards,
Maciej
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
John,
As your example might work as standalone code it will not in the dll where I have to get the passed variables as function arguments subp(a, b). That makes the conflict with defined module or common block. So when I declare in the module surrogate variables then it works.
I nowhere mentioned I will rely on anything during integrating. I made many tests, tracing "what FCN does and where it is" printing intermediate values of t, yprimes and so on during integration. In fact the IVPAG will not return the control to me until it finishes so I am not able to change anything in FCN from outside during integration.
That example you provided reminds me my other work with IVPAG when I set the PARAM() to return control to me after every succesful iteration to compute fresh values of thermodynamic state functions. Now I am even not so rigorous - I can update them every succesful time step. And in fact at the first I can set them constant during whole simulation. Just pass the vars... :)
regards,
Maciej
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
To my surprise I think I just touched the formal limits of Fortran.
This can be disappointing a little bit - but I know that not everything can be done within every language...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Maciej,
are you saying that within the Visual Basic environment you can not pass values via a module?
Not even if you have:
subroutine setparameter( k_for_fcn )
use fcn_module
real :: k_for_fcn
k = k_for_fcn
end subroutine
and a function fcn that looks like this:
real function fcn( x )
use fcn_module
real :: x
fcn = -k * x
end function
Or something similar?
Note that the subroutine set_parameter must appearoutside a module,
as I do not think you can access a subroutine inside a module from VB.
The function fcn can either appear inside or outside a module, depending
on the actual reference (from VB or from Fortran).
Regards,
Arjen
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Arjen,
Your example works. But you had to introduce additional variable k_for_fcn. I thought I can pass directly variables to fcn.
I showed it a few posts earlier here:
http://software.intel.com/en-us/forums/showpost.php?p=108747
a_ and b_ are those additional surrogates I wanted not to use. But it seems I must.
I dont want to use such surrogates because in some of the problems I have already computed and solved with Fortan/IMSL, I have quite big arrays. I know how to pass big arrays VB <-> Fortran but unfortunately it seems Fortran cannot pass them to its own external subroutine then.
I just wanted to make a nice frontend to my old, good working models for students that they would be able to work with them more easily.
reagrds,
Maciej
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I dont want to use such surrogates because in some of the problems I have already computed and solved with Fortan/IMSL, I have quite big arrays. I know how to pass big arrays VB <-> Fortran but unfortunately it seems Fortran cannot pass them to its own external subroutine then.
But it is not a feature unique to Fortran, but to virtually all programming languages. The problem is that the interface between the IMSL routine (IVPAG) and your fcn is given, and you cannot change it. If you need additional parameters to pass to the fcn, you must submit your own mechanism, because there's no path for them to go through IVPAG.
Please give yourself a freedom to design the language as you wish -- which syntax would you use to achieve what you want without using an external module or common block (with the only limit being that you mustn't change the prototype of IVPAG)?
(In C/C++ you could use an additional void* argument used to pass any sort of data through, but the library routine (IVPAG) would have to be extended allow that. Fortran could also do that with a little hacking around. But I digress).
On to your real-life problem: Arjen's example is still valid, but you don't have to physically copy the data into module variables. If your working arrays are large, you can declare POINTER arrays in fcn_module, and point (=>) to your original data rather than copy them into the fcn_module.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Exactly, the interface of the callback function/subroutine must provide for this degree of freedom
you require, otherwise you will have to use means like COMMON blocks or module variables.
You could actually keep all your variables (arrays and scalar parameters) in the module and
use that module in the callback function fcn.
(A way out would be to have a language facility that creates "curried" functions, something you
find in, say, LISP or other functional languages, a dynamic/scripting language like Tcl can do that
too, but that is not a feature that Fortran offers. Mind you, some simple forms _are_ possible, but
that is a completely different topic ;) and borders on the esoteric)
Regards,
Arjen
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes, POINTERs are acceptable here!
I wonder why I didn't think of it earlier, my fault.
Thanks!
Maciej

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page