Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
29285 Discussions

Modules - Can't see variable values from outside the project containing Module

sabur
Beginner
748 Views
Hello,

This question involves the same project I'm working on that's discussed in the following thread, however the question for this post involves Modules and should be an all-Fortran question.

http://software.intel.com/en-us/forums/showthread.php?t=62562

Short update of issue in above thread:

As far as the issue, passing arrays from C to Fortran, in the above thread is concerned I have had some luck using IanH's suggestion to use a static versus dynamic library and C/Fortran Module example. This worked fine with the READDATA Fortran code as a standalone main program. Placing this code as a subroutine into the application code and calling it from Excel as a dll I ran into memory problems (I think from the internal Excel side). I discovered that by reducing the size of an array slightly in my READDATA routine, the problem went away. I've also discovered that messing around with Modules sometimes I can use the full size of the array and sometimes I can't.


Now for the question related regarding title for this thread:

The question I have seems to be closely related to the one from 2001 found in the following thread:

http://software.intel.com/en-us/forums/showthread.php?t=45814 (from 2001)

My main Fortran application which is called as a dll from Excel contains several subroutines that contain a lot of COMMON blocks. As I'm getting back into Fortran, I've learned that MODULES can be used in place of COMMON blocks. I believe that I can place (and declare) all my variables currently contained in COMMON blocks and put them in, say, one MODULE. I can do away with declaration statements and such in my subroutines and by simply putting a USE [Module name] statement in the beginning of each subroutine I have access to all those variables. If I need to change the size of an array I only have to do it in one place, in the MODULE. (This would be of great help in dealing with my memory issues alluded to above.)

Now, I have one Fortran subroutine (READDATA) that is in a different project. It is the one that calls a C routine which reads data from a file generated from a research test that's in a proprietary format. (I have tried putting READDATA into the other project but ran into problems with "undefined addresses" when I called the Fortran dll from Excel. Right now, having it in a separate project "works".)

I have created a MODULE named "stuff" and put it in my main project. I am having trouble reading values from the variables in this MODULE from READDATA (READDATA is in a different project than the one that contains the MODULE "stuff"). Below is the module and the IDE settings: (The name of the source is "MODULECommon.F90") I would also like to be able to have the C code have access to the data, but for now I'm simply trying to do this on the Fortran side so have temporarily commented out the C interoperability related lines.

[cpp]Module Stuff
!USE, INTRINSIC :: ISO_C_BINDING

integer*4::RangeBaromz(128)
REAL(8) time
Real(8)::XEU(3000),SCAN_CHAN(60000,500),SCAN_CHANAVE(10001,500)
!CHARACTER(80,C_Char), BIND(C) :: str2
CHARACTER*(10) Teststring
!CHARACTER(80,C_Char), BIND(C) :: FILE_PATH

End Module Stuff[/cpp]

Settings for project READDATA: (Visual Fortran version 11.0)

1) Under Project/Fortran/Preprocessor/Additional Include Directories I have put the directory which contains "stuff.mod" and MODULECommon.obj.

2) I also put this directory in Project/Resources/General/Additional Include Directories but I don't think this does anything.

3) Under Project/Linker/Input/Additional Dependencies I put MODULECommon.obj. (doing this, suprisingly, also decreased memory such that I had to decrease a Fortran array below the nominal size to avoid memory errors when calling the Fortran dll app from Excel) This was suggested by Jugoslav in the thread from 2001. If I don't do this I get the following error:

[cpp] Error    1     error LNK2019: unresolved external symbol             _STUFF_mp_TESTSTRING referenced in function _READDATAFILE    READDATAFILEACS.obj  


[/cpp]
Having done the above, everything compiles okay. I give "Teststring" a character value in the subroutine that calls READDATA. When debugging, the value of "Teststring" reads fine before I call READDATA, but once in READDATA (again, READATA is in a different project than the MODULE "stuff"), "Teststring" comes up blank.

Any suggestions?

Thanks.

Mike
0 Kudos
4 Replies
Steven_L_Intel1
Employee
748 Views
When you say Testring comes up blank, is this viewing in the debugger or does the program also not see the value? Is READATA in its own DLL or is it just linked in with the main code?
0 Kudos
sabur
Beginner
748 Views
When you say Testring comes up blank, is this viewing in the debugger or does the program also not see the value? Is READATA in its own DLL or is it just linked in with the main code?

Okay, my main application is in a solution named ACSFortran95 which contains 10 or so subroutines and the MODULE "MODULECommon.F90" (MODULE name "stuff"). This solution is a dll which is called from Excel.

The main entry into this dll is a subroutine named MYPCALCS.FOR and it is this subroutine which calls READDATAFILE (i.e. "READDATA" which is in its own separate solution named READDATAACS).

Below is the relevant code in MYPCALCS

Near the end of the listing I have set "Teststring" to "HiFromModule". "Teststring" is the variable that is in the MODULE named "stuff" that I am trying to "see" from READDATAFILE.
[cpp]C********************************************************************
C
C SUBROUTINE MYPCALCS
C
C This subroutine is compiled as a DLL which is called by
C the Excel Post Processor GUI. A wrapper executable program
C "PCALCS.EXE" can be used to call this DLL from the command
C line.
C
C Inputs:
C fname - path anad filename of the data and info files
C w/o the ".info" and ".dat" extensions.
C pname - path and name of the param file.
C bscan - first scan to process.
C escan - last scan to process.
C iavg - averaging rate.
C no - number of output options.
C oopts - array of output options, i.e., 101, 102, etc.
C
C Outputs:
C files created by the output options.
C
C Algorithm:
C Initialize Flags
C Store parameters in QAARG common variables
C Build the path and file names for the QAFILES common
C Call READ_INFOFILE - Populates QATIME and QAREC common
C Call READ_PARAMFILE - Populates QAUPAR common
C Call READ_DATAFILE - Populates QAEU (scan_chan) common
C Call GET_AVERAGES - Populates QAEU (xeu) common
C Call PCALC - Does the calculations
C Call OUTPUT_OPTIONS - Writes the output files
C
C********************************************************************
SUBROUTINE MYPCALCS(fname, pname, H2SubSonic, O2SubSonic,
& AddSubSonic,
& bscan, escan, iavg, no, rangebarom, SonThrt,
& H2SonM, H2SonB, O2SonM, O2SonB, H2Sonic, O2Sonic,
& AddSonic, H2SonIndx, O2SonIndx, AddSonicIndx,
& BegZ2scan, avrgint)

USE stuff
c implicit none
C The following line makes this DLL available to exteranl programs.
!DEC$ ATTRIBUTES DLLEXPORT::MYPCALCS
!DEC$ ATTRIBUTES DLLIMPORT::READDATAFILE

c For testing Modules MJB 01/17/2009
c CHARACTER*(10) Teststring

CHARACTER*(*) fname
CHARACTER*(*) pname
CHARACTER*(14) H2SubSonic, O2SubSonic, AddSubSonic
INTEGER*4 bscan, escan, iavg, no, rangebarom(128),int_arg
REAL*4 SonThrt(50), H2SonM(50), H2SonB(50), O2SonM(50), O2SonB(50)
REAL*4 sonics(3)
REAL*4 H2sonic
REAL*4 O2sonic
REAL*4 AddSonic
Logical WriteDebug

c INTEGER*4 RangeBaromz
REAL*4 H2SubThrt, O2SubThrt, AddSubThrt
INTEGER*4 H2SubSerial, O2SubSerial, AddSubSerial
REAL*4 SonThrtz, H2SonMz, H2SonBz, O2SonMz, O2SonBz,
& H2Sonicz, O2Sonicz, AddSonicz, AddSonicIndxz
INTEGER*4 H2SonIndxz, O2SonIndxz
INTEGER*4 BegZ2scan, BegZ2scanz, avrgint, avrgintz

INTEGER*4 oopts(no)
INTEGER*4 H2SonIndx, O2SonIndx, AddSonicIndx

C Mike's Commons Barometer and Venturi info
COMMON/MJBARRAYS/H2SubThrt,O2SubThrt,AddSubThrt,
& H2SubSerial, O2SubSerial, SonThrtz(50),
& H2SonMz(50), H2SonBz(50),
& O2SonMz(50), O2SonBz(50),
& H2Sonicz, O2Sonicz,
& H2SonIndxz, O2SonIndxz, AddSonicz, AddSubSerial,
& AddSonicIndxz

c COMMON/BaromArray/RangeBaromz(128)


C Common for Data
c COMMON/QAEU/XEU(3000),SCAN_CHAN(60000,500),SCAN_CHANAVE(10001,500)


C Common for zscan (time)

c COMMON/REALNUMBER/time
c REAL(8) time

C Common for Param File Variables
COMMON/QAUPAR/NIUR,IUPAR(200)
REAL RUPAR(200)
CHARACTER*4 CUPAR(200)
EQUIVALENCE(IUPAR,RUPAR,CUPAR)

C Common for Filenames
COMMON/QAFILES/labDAQ_path, resource_path, data_path,
& data_filename, info_filename, param_filename
CHARACTER*80 labDAQ_Path, resource_path, data_path,str2
CHARACTER*80 data_filename, info_filename, param_filename

C Common for Passed Parameters
COMMON/QAARG/begin_scan, end_scan, iaverage, nopts, opts,
& BegZ2scanz, avrgintz
INTEGER begin_scan, end_scan, iaverage, nopts, opts(10)

C Common for Date and Time
COMMON/QATIME/start_date, end_date, start_time, end_time
CHARACTER*10 start_date
CHARACTER*10 end_date
CHARACTER*8 start_time
CHARACTER*8 end_time

C Common for Recording Information
COMMON/QAREC/scan_rate, total_scans, reading_number,
* total_chans, ichan_list, scan_integer
INTEGER*4 scan_rate
INTEGER*4 total_scans
INTEGER*2 reading_number
INTEGER*2 total_chans
INTEGER*2 ichan_list(196)
INTEGER*4 scan_integer


C Common Flags
COMMON/QAFLAGS/FIRST_SCAN, LAST_SCAN, CURRENT_SCAN, NEXT_SCAN
LOGICAL FIRST_SCAN
LOGICAL LAST_SCAN
INTEGER CURRENT_SCAN
INTEGER NEXT_SCAN

C Common for Debug
COMMON/QADEBUG/sim,debug
LOGICAL sim
LOGICAL debug
C Common for communicating save param file
LOGICAL WPARAM
CHARACTER*80 SAVE_NAME
COMMON/QAPARZ/ SAVE_NAME,WPARAM

C application programmer's common
COMMON/QAAPB/CALL_ONCE
logical CALL_ONCE

C Local Variables
INTEGER Get_UnitNo, iounit
CHARACTER*80 Blanks
LOGICAL end_of_reading/.FALSE./
cc INCLUDE 'EQUIV_PARAM.EDT'
c str2 = fname // C_NULL_CHAR
cc FILE_PATH = fname !// C_NULL_CHAR

c For testing Modules MJB 01/17/2009
Teststring = "HiFromModule"

C**********995**********************************************************

[snipped code]

c
c
CALL READDATAFILE(str2)

[snipped code]

RETURN
END SUBROUTINE[/cpp]


Again, READDATAFILE is in it's own solution. It calls a C static library named "MAIN". The code for READATAFILE is below.

FYI: MODULE seedata was a contribution from IanH for communication between READDATAFILE and the C code "MAIN". I realize now that it could be placed in it's own separate source.

I have highlighted in bold several lines that are relevant.

C********************************************************************
C
C SUBROUTINE READDATAFILE.for
C
C This subroutine reads the data file and stores the information
C in the QAEU Common
C
C********************************************************************
MODULE seedata
USE, INTRINSIC :: ISO_C_BINDING
IMPLICIT NONE
! The data
REAL(C_DOUBLE), BIND(C) :: datastuffraw(30000,500)
REAL(C_DOUBLE), BIND(C) :: datastuffeun(30000,500)
CHARACTER(15,C_Char), BIND(C) :: grpnm
c Does the 15 need to be 1?
c CHARACTER(KIND=C_CHAR), DIMENSION(*) :: grpnm

INTERFACE
SUBROUTINE MAIN BIND(C)
! No arguments.
! Everything is global.
! Array dimensions are hard coded.
! All very bad.
c CHARACTER(KIND=C_CHAR), DIMENSION(80) :: grpnm
END SUBROUTINE
END INTERFACE

END MODULE seedata


Subroutine READDATAFILE(str2)
USE seedata
USE stuff
implicit none

! Expose subroutine ReadDataFile to users of this DLL
!
!DEC$ ATTRIBUTES DLLEXPORT::READDATAFILE


C Common for Data
c COMMON/QAEU/XEU(3000),SCAN_CHAN(60000,500),SCAN_CHANAVE(10001,500)

C Common for zscan (time)

c COMMON/REALNUMBER/time
c REAL(8) time
c REAL xeu
c REAL scan_chan,scan_chanave
INTEGER*4 begz2scanz,avrgintz

c For testing Modules MJB 01/17/2009
CHARACTER*(12) FromModule

C Common for Passed Parameters
COMMON/QAARG/begin_scan, end_scan, iaverage, nopts, opts,
& BegZ2scanz, avrgintz
integer begin_scan, end_scan, iaverage, nopts, opts(10)

C Common for Filenames
COMMON/QAFILES/labDAQ_path, resource_path, data_path,
& data_filename, info_filename, param_filename

C Volatile /QAFILES/

!DEC$ ATTRIBUTES DLLEXPORT::/QAFILES/


c CHARACTER*(*) filename
CHARACTER*80 labDAQ_Path, resource_path, data_path
CHARACTER*80 data_filename, info_filename, param_filename

C Common for Recording Information
COMMON/QAREC/scan_rate, total_scans, reading_number,
* total_chans, ichan_list, scan_integer
INTEGER*4 scan_rate
INTEGER*4 total_scans
INTEGER*2 reading_number
INTEGER*2 total_chans
INTEGER*2 ichan_list(196)
INTEGER*4 scan_integer

C Common for Debug
COMMON/QADEBUG/sim,debug
LOGICAL sim
LOGICAL debug

C Local Variables
character*20 project_name
character*4 data_keyword
integer Get_UnitNo, iounit, iodebug
integer iscan, jchan


CHARACTER(80) OUTPUT_TEXT,str_out
CHARACTER(LEN=80,KIND=C_CHAR) :: str1
CHARACTER(LEN=80,KIND=C_CHAR) :: str2
c CHARACTER(LEN=15,KIND=C_CHAR) :: grpnm
INTEGER*4 INT_ARG, OUTPUT_LEN
CHARACTER(80) INPUT_TEXT
c real*8 DATASTUFF(90000,500)
str1 = C_CHAR_"TestYo..." // C_NULL_CHAR

c For testing Modules MJB 01/17/2009
FromModule = Teststring

int_arg = 123
Call MAIN(datastuffraw, datastuffeun, int_arg, str2, grpnm)
ccc Call MAIN(int_arg, str1, grpnm)
SCAN_CHAN = datastuffeun

RETURN
END


Now, when I debug from ACSFORTRAN; just before I call READDATAFILE, the value of "Teststring" is 'HiFromModule'.

When I debug from READDATA and stop at the line "Call MAIN...." the value of "FromModule" is ' '. That's 2 single quotes with 12 spaces in between.

BTW, the important variable/array here is "SCAN_CHAN". This array contains all the data from the test being conducted. I have finally managed to get the data from the "dark side" i.e. the C code and onto the Fortran side (a minor miracle if there ever was one). I am now trying to replace the COMMON statemement that was used to enable other subroutines in the main application to "see" SCAN_CHAN with a MODULE. When READDATAFILE returns to MYPCALCS, I expect to see non-zero elements in SCAN_CHAN as I do in READDATAFILE after the call to MAIN. However, upon the return to MYPCALCS all the elements in SCAN_CHAN are zeros.

Thanks for your help.

Mike
0 Kudos
IanH
Honored Contributor III
748 Views
Maybe its a transcription error, but your code sample for module Stuff shows TestString as a CHARACTER(10). Later you say it contains twelve characters (either as your HiFromModule test string, or as blanks). This is inconsistent. If it is not a transcription error it is likely to be a related symptom of the real problem.

Uncommenting IMPLICIT NONE might help. I personally don't have the skills or patience required to write error free programs without it. I similary struggle with F77 style source.

Your project layout confuses me. I get the impression that you are building multiple DLL's, when your description imples that only one (for Excel to call) would be required. ReadDataFile does not seem like a subroutine that Excel would call directly, in which case it doesn't need to have its entry point exported. It could be part of the same static library as stuff. Maybe this is not relevant, but it is complicating the picture.

IanH

0 Kudos
sabur
Beginner
748 Views
Quoting - IanH
Maybe its a transcription error, but your code sample for module Stuff shows TestString as a CHARACTER(10). Later you say it contains twelve characters (either as your HiFromModule test string, or as blanks). This is inconsistent. If it is not a transcription error it is likely to be a related symptom of the real problem.

Uncommenting IMPLICIT NONE might help. I personally don't have the skills or patience required to write error free programs without it. I similary struggle with F77 style source.

Your project layout confuses me. I get the impression that you are building multiple DLL's, when your description imples that only one (for Excel to call) would be required. ReadDataFile does not seem like a subroutine that Excel would call directly, in which case it doesn't need to have its entry point exported. It could be part of the same static library as stuff. Maybe this is not relevant, but it is complicating the picture.

IanH



The CHARACTER(10) thing: It's sort of a transcription error. I had changed the test string from a 10 character string (I think it may actually have been "Teststring") to the 12 character "HiFromModule" string which was less confusing to me. I neglected to go back to the original post and change the 10 to a 12.

The original code, which I did not write, and which may go back quite a while did not have an "implicit none". I added it recently to see what would happen and quite a few things got flagged. I little history may be in order here...

About how the original application code has been used. There's an old test cell and a new test cell. I have used this application successfully in the "old test" cell for several years. The data collecting software (a fairly old version of LabView by National Instruments) in the old test cell creates data files in a simple binary format (Big Endian). These data files are easily opened with a Fortran OPEN statement with "Format = 'binary'" and "Convert = 'Big Endian'". No problemo. This was how the program was written when I "acquired" it. It all works just fine. (and without implicit nones, although I know very well it would be a good idea to go and use them and make sure everything's declared etc.)

This Fortran application as it has/is used in the old test cell is a collection of subroutines in a single "Fortran" dll (all in one project/solution). The excel "front end" can call several subroutines individually and the Fortran subroutines sometimes call each other. One of these subroutines, "READDATAFILE" is called by another subroutine in the dll (agian, same project) to do nothing but read the binary datafile from the LabView data collecting software from each test run. READDATAFILE reads this binary data file and puts the data into a 2-dimensional array called "scan_chan" (rows are time increments and columns are instrument channels).

Okay, moving on to the new test cell. It is very similar to the first and I plan on using the above application program for data crunching. One small problem. The new test cell is using a modern version of the LabView data collecting software and the data files are no longer simple binary files but are in a new proprietary format (TDMS/Diadem) that Fortran can not read directly. Yes, LabView has fancy software you can buy (and we have) to read these files and make very sophisticated plots, but I have a lot of specific calculations and various things I do with my Excel/Fortran dll application that I don't thing can be easily done with LabView's software, but that's another thread :).

Okay, all I have to do is somehow get the data from these new binary files into the array "scan_chan" in the subroutine "READDATAFILE". The rest of the Fortran/Excel code then acts on the data in "scan_chan" and could care less how it got there. It is transparent to the rest of the code. Turns out that National Instruments has some C code that can read these proprietary formatted data files if you don't want to use their software.

So what I did (to make this easier) was take a copy of "READDATAFILE" and temporarily turn it into a main standalone program and try to get it to call this C code and get the data from C into "scan_chan in "READDATAFILE". This I have finally managed to do with your (and others) help (I am still working on extracting string/character data but the actual numeric test data is the most important of course) and is what these threads over the past few weeks have been about.

Soooo....... you would think that all I'd have to do is make READDATAFILE into a subroutine again, stick it back into the original Visual Studio project, letting the linker know where the C .lib file is etc., fire up Excel and let 'er rip. No such luck.

Using the standalone version of READDATAFILE I was able to get the data from the C code and put it into "scan_chan". Worked very nicely, unfortunately, after incorporating it into the Excel/Fortran dll app I ran into memory problems. Probably memory limitations inside Excel. I finally figured out that if I decreased the size of the
"datastuff..." arrays in READDATAFILE slightly I got past the memory problem (this is with Excel 2003, with Excel 2007, which I have used very little so far, I did not have a memory problem with the original array size, but did run into memory issues when I increased the arrays slightly from the original size).

But, getting past the memory issue for the time being, I ran into yet another problem. When I made the first call from Excel to a Fortran subroutine in the dll a couple of the arguments on the Fortran side came up "undefined address". Never had this problem before in original "old test cell" version and the only major difference is that now I have this C static library hanging around somewhere. (again, this is with READDATAFILE in the original visual studio project with all the other subroutines)

So, to cut to the chase, it turns out that if I make READDATAFILE a dll in it's own project, separate from the original dll used in the "old test cell", I don't have the "undefined address" problem and it also seems to alleviate to some degree the memory problem (i.e. I can keep the "datastuff.." arrays their original size using Excel 2003). And right now I'm just trying to get something working, I can try and tackle the "undefined address" issue later.

So, things are actually working pretty good. I simply would like to use a MODULE file to replace my COMMON blocks, especially the ones that contain "scan_chan" and a couple of others. If I understand MODULES correctly I should be able to put "scan_chan" in one, such that all the subroutines, using the "USE ..." statement, can "see" "scan_chan" and if I want to change the size of "scan_chan" I only have to do it in one place.

Sorry for the length, it's as short as I can make it. So, to sum up a bit, I'm trying to take an Excel/dll app which works perfectly fine in one environment and make it work in another where the only difference is the format of the data files from a test necessitating the replacing of an OPEN and a READ statement in READDATAFILE by a call to a C code.

Mike

Oh, and about exporting the entry point. Yes, it's probably not necessary and is probably "left over" from some experimenting at some point. I have commented it out.
0 Kudos
Reply