CFD Online Discussion Forums

CFD Online Discussion Forums (https://www.cfd-online.com/Forums/)
-   CFX (https://www.cfd-online.com/Forums/cfx/)
-   -   User Fortran with CFX 14.5.7 on winnt_amd64 (https://www.cfd-online.com/Forums/cfx/127434-user-fortran-cfx-14-5-7-winnt_amd64.html)

HLo December 11, 2013 05:56

User Fortran with CFX 14.5.7 on winnt_amd64
 
1 Attachment(s)
Hello,
when looking for a means for doing time integration of a expression, I read a little into user fortran. As the fortran environment is complex and expensive I did some research (to be honest: more trial-and-error) with free Mingw64.
It is a little tricky as the systems are not compatible concerning function names. At least I succeded in implementing some subroutines with simple arithmetic, not using any of the CFX internal calls. It is enough for storing a previous value, doing time integration or calculting a derivative of an expression.
The essential thing is to provide upper case aliases for the lowercase function names of Mingw, as CFX expects them in uppercase despite they appear lowercae in CFX-Pre. And prohibit adding underscores to function names.
Works in my environment ANSYS CFX 14.5.7 both single and double precision, no idea whether it works distributed, partitioned etc.
You need a installation of TDM64-GCC 4.8.1-3, include gfortran.
In a DOS-Box (best with <TDM-GCC-Inst-Dir>\bin in the PATH variable) 'cd' to the directory where you unpack the zip to. Customize the paths in compile.bat to your paths and run it.
Please give iti a try.

Time Integration itself can be done more consitently in the solver itself:
http://www.cfd-online.com/Forums/cfx...tml#post465756

njdyck December 19, 2013 10:31

HLo,

Thank you so much for posting this. I have been looking around a lot recently for a way to use the MinGW compiler instead of the Intel one.

I have found a way to get the CFX Utility Routines working for use with MMS based on your solution.

The problem boils down to the fact the GNU c++ preprocessor is case in-sensitive and converts the output symbols in lower case, but the object file library (in my case solver-hpmpi.lib) has the (non-mangled) symbol names in uppercase.

When I compiled naively I got errors like:

undefined reference to 'user_assemble_info'

This led me to the above conclusion. Since we can't recompile the libraries (don't have the source) we probably need to rename or create aliases for the symbols at compile-time.

The solution I found was to add the command line option you are already using to the linker for each symbol (subroutine that needs to be converted) e.g. :

Code:

-Wl,--defsym,user_assemble_info=USER_ASSEMBLE_INFO
[repeat this linker option for other symbols]

In addition, I created an additional .def file (named solver-hpmpi.def) containing:

Code:

LIBRARY "SOLVER-HPMPI.LIB"
EXPORTS
user_assemble_info = USER_ASSEMBLE_INFO
[other symbols to convert]

So don't forget to append this new .def file into the compile/link command.

Using this technique I was able to compile the dll for the AdVarSource.F example located in %CFXROOT%/examples/UserFortran/ (using TGM-MinGW64)

Disclaimer: I don't really get why this works I thought I would just need the .def or the linker but it only works if both are included.

Disclaimer: I haven't tested the .dll file yet. Will edit this post when I have confirmed that it works.

Again, thanks HLo, I wouldn't have been able to get this far without your help. :)

Future work:
Maybe somebody could come up with a modified cfx5mkext.ccl file (or batch file) that automatically converts the symbols for all the CFX utility routines that are being used. That way everyone on windows could easily compile user fortan without depending on the expensive intel compiler.

HLo December 19, 2013 10:46

Symbol Table
 
Hello njcyck,

I tried with the defsym switch myself, but no success then.
With your proposal I'll give it a new try now.
In an other experiment I hexeditet the object file from mingw and uppercased the function name (here SET_A_0), linked it, but CFX solver crashed. Please let me know about your experiments and vice versa.

BTW: did the example run in solver?

Thanks
HLo

njdyck December 19, 2013 11:24

HLo,

I forgot to mention a couple of things:
I am including the .def file that is modelled after yours (I called it AdVarSource.def):

Code:

LIBRARY "ADVARSOURCE.DLL"
EXPORTS
USER_SOURCE2 = user_source2

and I used the linker option:

Code:

-Wl,--defsym,set_a_0=set_a_0
This is in addition to the other --defsym commands I used to convert the subroutine names.

If I exclude either the --defsym set_a_0=set_a_0 option or the AdVarSource.def file (or both) it fails to compile/link.
I am still confused about something:
the --defsym set_a_0=set_a_0 command seems to be renaming a symbol to itself? I'm glad that it works, but it really doesn't make sense.

I also removed the -Wl,--defsym,set_a_0=set_a_0 option from your batch file and ran it: it still makes the Utility.dll file without any issues. You don't need it unless there's a subroutine called SET_A_0.

Just to be clear, I am using cfx5mkext.exe; here is the important chunk from the cfx5mkext.ccl file I am using (obviously I haven't bothered with the double precision chunk just yet):

Code:

OS: winnt amd64
  cc = gcc
  fc = gfortran
  ld = ld
  cxx = cl
  ext build cflags = -MD
  ext build fflags =  -fno-underscoring -fno-range-check
  ext link ldflags = -mdll AdVarSource.def solver-hpmpi.def -Wl,--defsym,set_a_0=set_a_0 -Wl,--defsym,user_assemble_info=USER_ASSEMBLE_INFO -Wl,--defsym,get_phase_from_var=GET_PHASE_FROM_VAR -Wl,--defsym,convert_name_s2u=CONVERT_NAME_S2U -Wl,--defsym,lenact=LENACT -Wl,--defsym,user_getvar=USER_GETVAR -Wl,--defsym,mesage=MESAGE
  ext link lib5files = solver-hpmpi.lib
  cppflags f = -cpp
  cc outopt obj = -Fo
  ext lib suffix = dll
  ext lib pattern = %s.dll
  ATTRS: double
    cppflags = -DDOUBLE_PRECISION
    ext build fflags = -Qvec- -iface:cvf -integer_size:32 -real_size:64 -MD
    ext link lib5files = solver-hpmpi.lib
  END
END


HLo December 20, 2013 02:55

defsym
 
Hello,
yes the set_a_0 stuff is not needed, if it is not used.

First: Does the example run in CFX? And what is your system when you use solver-hpmpi.lib?

I did some further research, as my code crashes with segmentation fault, when using one of the CFX routines like SET_A_0, MESAGE etc.
One thing that gave me a hint was that one has to change the definition of argument CRESLT form CHARACTER*(*) to fixed length. The reason for it -I assume- is the different handling of character arguments. The compiler argument -iface:qvf of Intel Fortran influences the order how the hidden length values are passed. In gfortran there is no such switch, I read somewhere, that the hidden strings lengths are appended to the argument list. Whereas the -iface:qvf gives them immedeately following the string arg.
As a consequence the different arg order or hidden additional args mess up the processor stack, which does not matter as long as these are not used in your program.
You may verify if you include an additional arg NLNG after CRESLT and declare as INTEGER,VALUE :: NLNG. if you watch it it gives 4.
The key to solve the entire problem is the correct number and order of the passed arguments, their bytelength I think is always 4 (pointer or integer)

For double precision in your ccl fflags should be the same plus -fdefault-real-8

HLo

Raijin Thunderkeg December 20, 2013 04:35

Hello, do you have any experience on User Fortran Compiling on Win X64 OS? Ansys 14.0 is used on my PC. I installed Mircosoft Visual 2012 and Intel Visual Fortran Composer XE2013. But when I try to compile the user fortran in the tutorial file, a message appears like "The compiler command ifort can't be found. Please ensure that the compiler is on your path and try again." Can you help me? Thx.

HLo December 20, 2013 05:18

ifort not found
 
Hello Raijin,
First: the directory, where the ifort executable resides, must be in your system's path:
Open a dos box and enter 'set path' (without quotes), the printout should contain "C:\Program Files (x86)\Intel\Composer XE 2013 SP1\bin\intel64" or similar, otherwise Composer is not installed correctly.
I myself worked with an eval version for 32-bit, which compiled after some tweaks, but did not work, as CFX is 64-bit.
The tweaks go into the mess with appended underscores, which ifort creates, but cannot be linked, maybe something messed up in the examples or I didn't get far enough
Sorry that's all I can offer, I focus on Mingw
HLo

njdyck December 20, 2013 15:25

HLo,

I have been doing some testing and it has not been successful. :(

By system do you mean my machine specs?
I'm on windows 7 64-bit with an Intel i7 cpu. Also I'm using ANSYS 13.0

Whenever I try and run something that uses the CFX utility routines I get the error:

+--------------------------------------------------------------------+
| ERROR #001100279 has occurred in subroutine ErrAction. |
| Message: |
| Signal caught: Segmentation violation |
| |
| |
| |
| |
| |
+--------------------------------------------------------------------+

+--------------------------------------------------------------------+
| ERROR #001100279 has occurred in subroutine ErrAction. |
| Message: |
| Stopped in routine FPX: SIG_HANDLER |
| |
| |
| |
| |
| |
+--------------------------------------------------------------------+

I assume this is the same segmentation fault that you have run into.

Your theory about the string lengths is intriguing. I also changed the CRESULT argument length to fixed to satisfy the compiler.

I am trying to understand the consequences, so please confirm my thinking or correct me if I'm wrong:

Whenever the intel compiler encounters a variable-length character string in an argument list for a subroutine, it writes the machine instructions so that the length of the string is passed as an additional (hidden) variable which immediately follows the string itself. If an intel compiler also compiles the calling code for the routine it will write instructions to calculate the length of the string that is being passed (at run time), and pass that length argument immediately following the string itself.

Whenever the gfortran compiler encounters a variable length character string in an argument list, it does something similar except it appends the hidden string length list to the end of the argument list. When the calling code is compiled it also writes the instructions to append the string lengths (calculated at runtime) to the end of the list. Everything works well if the subroutine and the calling code are compiled with gfortran.

So we have a problem because the subroutines we are calling expect that string lengths immediately follow strings, and there are no gfortran compiler options to tell gfortran to pass the hidden string lengths in a different way.

Ok so if that is true then you are saying we just need to (whenever calling a CFX utility routine) replace all of the variable length string arguments with fixed width arguments, and insert those string lengths (integers) as makeshift hidden arguments after every argument that is expected to be a variable string.

Is this correct? I am just trying to get a clear picture of what's happening, so I haven't tried anything yet. Let me know what you think.

HLo December 21, 2013 11:13

hidden string args
 
Hello,
"my" error ist the same, but ONLY when I call CFX subroutines like SET_A_0, ERRMSG, MESAGE etc. so if you can avoid them, like in my example it should work. I didn't succeed in calling these CFX subs without error.
To overcome the problem of hidden string lengths at end of arg list try to wrap character variables into a new type and explicitely add the string lengths in your functions:
SUBROUTINE BLABLA(NLOC,NRET,NARG,RET,ARGS,CRESLT,NLNG,
& CZ,NLNG2,DZ,IZ,LZ,RZ)
and define:
TYPE CWRAP4
CHARACTER(LEN=4) str
END TYPE
INTEGER,VALUE :: NLNG, NLNG2
the latter for the CZ stack
...
TYPE(CWRAP4) :: CRESLT
and later
CRESLT%str = 'GOOD'
So in theory the CALL ERRMSG(string) in gfortan should be replaced with CALL ERRMSG(wrapped_str, %VAL(length_of_wrapped_str)) (the hidden length is always "by value" not like fortran default "by ref")

To the linking with solver-....lib:
I think it is better to replace the lowercase symbols of gfortran to uppercase ones with 3rd party tools e.g objconv, then the "def" stuff is obsolete:
1) compile file.F to file.o:
gfortran -mthreads -I "C:\Program Files\ANSYS Inc\v145\CFX\include" -shared -fno-underscoring TStat_Control.F -c
2) then uppercase your symbols (output in TStat_Control.obj):
objconv -nr:errmsg:ERRMSG -nr:blabla:BLABLA TStat_Control.o
3) then link
gfortran -mthreads -I "C:\Program Files\ANSYS Inc\v145\CFX\include" -shared -L"C:\Program Files\ANSYS Inc\v145\CFX\lib\winnt-amd64" -o winnt-amd64\example.dll -Bstatic -static-libgfortran -static-libgcc TStat_Control.obj -lsolver-XXmpi
(XX for your environment)
I'd recommend the "-static-libgfortran -static-libgcc" options because otherwise these libraries are called at runtime and they point to the libs in the TDM installation directory, so on another machine where they are missing .....

HLo December 30, 2013 15:10

Solved
 
Hello,
finally got the solution:
1) compile source file with options:
gfortran -fno-underscoring -c -I "C:\....CFX\include" file.F
in source do CHARACTER to TYPE mangling, to enable string length arg directly after the string pointer, and always CFX's char function with string pointer and length pair
2) do "objconv.exe" to uppercase all references to CFX subroutines e.g:
objconv -nr:set_a_0:SET_A_0 -nr:mesage:MESAGE file.o file.obj (will create file.obj)
3) create a def file with contents:
LIBRARAY "MyDLL.dll"
EXPORTS
MYSUB = mysub @1
MYOTHERSUB = myothersub @2
4) link using -static-libgfortran and -static-libgcc against a rebuilt library of solver-pcmpi.lib (my case) in mingw format:
reimp.exe -d "C:\Pro....\CFX\lib\winnt-amd64\solver-pcmpi.lib"
dlltool.exe -d solver-pcmpi.def -k -l libsolver-pcmpi.a

Example for double prec.:
gfortran -fno-underscoring -fno-range-check -cpp -fdefault-real-8 -c -I "C:\Program Files\ANSYS Inc\v145\CFX\include" "TStat_Control.F"
objconv -ew2015 -nr:wrttxt:WRTTXT -nr:out_section_header:OUT_SECTION_HEADER -nr:set_a_0:SET_A_0 "TStat_Control.o" "TStat_Control.obj"
gfortran -O2 -mthreads -static-libgfortran -static-libgcc -shared -L. "TStat_Control.obj" "TStat_Control.def" -ldoublesolver-pcmpi-imp -o "winnt-amd64\double\TStat_Control.dll"
Import library "libdoublesolver-pcmpi-imp.a" built with:
reimp -d "C:\Program Files\ANSYS Inc\v145\CFX\lib\winnt-amd64\double\solver-pcmpi.lib"
dlltool -d "solver-pcmpi.def" -k -l libdoublesolver-pcmpi-imp.a
Definiton file "TStat_Control.def" contains:
LIBRARY "TStat_Control.dll"
EXPORTS
TESTSUB = testsub @1

Does someone give it a try?
HLo

njdyck January 1, 2014 11:52

HLo,

Thanks so much for posting your solution. I will try it in the next couple of days and let you know how it goes.

Happy New Year!

njdyck January 6, 2014 11:40

HLo,

It works!! Here are the steps I followed:

1. I downloaded objconv from http://www.agner.org/optimize/. I used the .exe file given in the folder.

2. I downloaded the reimp source from here, and built it using TDM-GCC with the following commands:

Code:

gcc -c -I "C:\...\src" reimp.c ar.c util.c
gcc reimp.o ar.o util.o -o reimp.exe

3. I created the following batch file and ran it:

Code:

REM re-build the library
reimp -d "C:\Program Files\ANSYS Inc\v130\CFX\lib\winnt-amd64\solver-hpmpi.lib"
dlltool -d "solver-hpmpi.def" -k -l libsolver-hpmpi-imp.a

REM build the dll
gfortran -fno-underscoring -fno-range-check -cpp -c -I "C:\Program Files\ANSYS Inc\v130\CFX\include" "MomentumSource1.F"
objconv -ew2015 -nr:mesage:MESAGE -nr:user_source_sub:USER_SOURCE_SUB "MomentumSource1.o" "MomentumSource1.obj"
gfortran -O2 -mthreads -static-libgfortran -static-libgcc -shared -L. "MomentumSource1.obj" "MomentumSource1.def" -lsolver-hpmpi-imp -o "winnt-amd64\MomentumSource1.dll"

MomentumSource1.def:
Code:

LIBRARY "MomentumSource1.dll"
EXPORTS
USER_SOURCE = user_source @1

MomentumSource1.F:
Code:

#include "cfx5ext.h"
dllexport(user_source)
      SUBROUTINE USER_SOURCE (
    & NLOC,NRET,NARG,RET,ARGS,CRESLT,NLNG,CZ,NLNG2,DZ,IZ,LZ,RZ)
C
C .....
C
C ------------------------------
C        Argument list
C ------------------------------
C
      TYPE CWRAP4
      CHARACTER(LEN=4) str
      END TYPE
     
      INTEGER,VALUE :: NLNG, NLNG2
      INTEGER NLOC, NRET, NARG
      TYPE(CWRAP4) :: CRESLT
      REAL    RET(1:NLOC,1:NRET), ARGS(1:NLOC,1:NARG)
C
      INTEGER IZ(*)
      CHARACTER CZ(*)*(1)
      DOUBLE PRECISION DZ(*)
      LOGICAL LZ(*)
      REAL RZ(*)
C
C .....
C
C ------------------------------
C    Executable statements
C ------------------------------
C
C---------------------------------------------------------
C    SOURCE = RET(1:NLOC,1)
C    X      = ARGS(1:NLOC,1)
C    Y      = ARGS(1:NLOC,2)
C---------------------------------------------------------
C
C---- Low level user routine
     
      TYPE(CWRAP4) :: COMMAND
      TYPE(CWRAP4) :: MES
     
      COMMAND%str = 'WRITE'
      MES%str = 'TEST'
     
      CALL MESAGE(COMMAND,%VAL(LEN(COMMAND%str)),MES,%VAL(LEN(MES%str)))
     
C        Create some data
C      CALL MAKDAT(CDANAM, CDTYPE, CERACT, ISIZE, JADRES, CRESLT)
     
C        Set the value of that data and read it back
C      CALL POKEI(CDANAM, JADRES, INPUT_VALUE, CERACT, CRESULT, IZ)
C      CALL PEEKI(CDANAM, JADRES, OUTPUT_VALUE, CERACT, CRESULT, IZ)
     
      CALL USER_SOURCE_SUB (NLOC,RET(1,1),ARGS(1,1),ARGS(1,2),ARGS(1,3))
     
      CRESLT%str = 'GOOD'
     
C10      CONTINUE

      END

      SUBROUTINE USER_SOURCE_SUB (NLOC,SOURCE,X,Y,Z)
C
C .....
C
C ------------------------------
C        Local Variables
C ------------------------------
      INTEGER NLOC, ILOC
      REAL    SOURCE(NLOC), X(NLOC), Y(NLOC), Z(NLOC)
C---------------------------------------------------------
C    -  0.5<x<1.5 and 1.25<y<1.75 --> SOURCE =  1000.0
C    -  3.5<x<4.5 and 1.25<y<1.75 --> SOURCE = -1000.0
C---------------------------------------------------------
C ---------------------------
C    Executable Statements
C ---------------------------
      DO ILOC=1,NLOC
        SOURCE(ILOC) = 0.0
        IF (X(ILOC).GE.0.5  .AND. X(ILOC).LE.1.5 .AND.
    &    Y(ILOC).GE.1.25 .AND. Y(ILOC).LE.1.75 .AND.
    &    X(ILOC).GE.1.25 .AND. Z(ILOC).LE.1.75) THEN
            SOURCE(ILOC) =  1000.0
        ELSE IF (X(ILOC).GE.3.5  .AND. X(ILOC).LE.4.5 .AND.
    &    Y(ILOC).GE.1.25 .AND. Y(ILOC).LE.1.75 .AND.
    &    Z(ILOC).GE.1.25 .AND. Z(ILOC).LE.1.75) THEN
            SOURCE(ILOC) = -1000.0
        END IF
      END DO
C
      END

At this point the .dll file was created as expected (109 KB)

I ran the test program in serial. It prints "TEST" (without quotations) a bunch of times at every timestep.

HLo January 6, 2014 12:43

successful test
 
Hello njdyck,
congrats to your successful test.
I wasn't sure whether it worked in another environment. In my case I had to use solver-pcmpi.lib instead of solver-hpmpi.lib. I also was afraid that the successful run depended on a certain Microsoft VC++ runtime.
To be sure it works reliably we should run all the tutorials' fortran examples later.
Remark: For double precision use flag '-fdefault-real-8' when creating the object file and put dll in winnt-amd64\double directory
Of course in other experiments the wrapped strings maybe longer than 4
I'll post other test results when applicable.

HLo

njdyck January 6, 2014 13:31

Ok so it's nice to be able to use the MinGW compiler instead of Intel's for compiling fortran code, however it would be much nicer if we didn't have to mangle the character strings and write messy subroutine calls like:

Code:

CALL MESAGE(COMMAND,%VAL(LEN(COMMAND%str)),MES,%VAL(LEN(MES%str)))
It might be possible to wrap all of the cfx utility routines into a new library whose source code looks something like:

Code:

TYPE CWRAPS
CHARACTER str*(*)
END TYPE

C  SOME SUBROUTINES

SUBROUTINE MESAGE(COMMAND,MESSAGE)

CHARACTER COMMAND*(*)
CHARACTER MESSAGE*(*)

TYPE(CWRAPS) :: COMMAND_CFX
TYPE(CWRAPS) :: MESSAGE_CFX

COMMAND_CFX%str = COMMAND
MESSAGE_CFX%str = MESSAGE

C  MESAGE_CFX is the renamed symbol for the orignal MESAGE utility routine
CALL MESAGE_CFX(COMMAND_CFX,%VAL(LEN(COMMAND_CFX%str)),MES_CFX,%VAL(LEN(MES_CFX%str)))

END

C  SOME OTHER SUBROUTINES

Using objconv or objcopy we could easily redifine all of the symbols in solver-XXmpi.lib to have "_CFX" appended to avoid name clashes. Also, we could compile it so that the symbol (wrapping subroutine) names are mangled in the gfortran fashion (uppercase); then the user subroutines don't need to redefine symbol names that correspond to calls to cfx utility routines.

This will of course be less efficient than mangling the user source code, but it will enable the same (unmangled) code to be compiled using intel and mingw compilers. Intel compilers will use the original lib and gfortran compilers use the wrapped lib.

I also don't know how much inlining/optimization the gfortran compiler will do so it might just increase the final .dll size without to much of a performance hit.

What do you think? Would this be useful? or is there an easier way to strip out the CHARACTER -> TYPE mangling from the user source code?

HLo January 7, 2014 09:56

#define macros
 
Hello njdyck,

should work. an alternative may be using macros (#define) for that
Code:

#define WRAP(f,g) f%str = g
#define WRAPCALL(f) f,%VAL(LEN(f%str))

and later
Code:

      WRAP(STR1, 'Hello World!')
      CALL ERRMSG(WRAPCALL(STR1))

Remark: The wrapping isn't mandatory for CRESLT, simplest use:
Code:

      CHARACTER*4 CRESLT
...
      CRESLT='GOOD'

HLo

BTW: After some further reading, thinking and experiments the reason why cfx crashes when CRESLT is defined as CHARACTER*(*) is clear:
As gfortran expects all variable string lengths added at the end of the argument list, but CFX never delivers them, a variable length definition of CRESLT therefore will pop off 4 bytes too much from stack.

HLo January 10, 2014 14:02

Current status
 
Hello,
currently I got so far, that all code from examples and tutorials hasn't to be heavily changed, all modified arg lists and string pointer mangling is outsourced to 2 include files which are conditionally preprocessed, when using gfortran. They don't disturb if using ifort. There are only 1 global and 2 mods in each subroutine, everthing else, accompanying #define macros (aliases) for the CFX subroutines and functions are declared in header files:
1) #include "gfortran.h" at the beginning of the file has global #defines and macros for each CFX function and subroutine
2) #include "usercelargs.h" in each subroutine has the modified CEL arg definiton and a type specification for each used CFX function
3) each sub needs a gnuexport(MYSUBNAME) directive
I'll post the files and example when code and compilation script are "ripe"
@ njdyck
I went away from wrapping strings in another type, as this cannot be implemented with #define macros. I use the LOC(S) (wrapped in another function CPTR__(S) though) in combination with %VAL so a CFX argument string S is replaced with %VAL(CPTR__(S)),%VAL(LEN(S)). The predefined LOC(S) function in a 1-liner CFX call appends a hidden additional length for each S to the end of the arg list therefore puts them on the stack and the runtime behaviour is unpredictable (probably segm. fault). I assume that is a bug in the compiler. Proof is given in the assembly code. The first puts 4 args to the stacks, the latter 3, as desired (to proof: compilation with -S to assembly file)
Code:

    CALL WRTTXT(%VAL(LOC(S)), %VAL(LEN(S), 1)  --> buggy
Code:

    PTR = LOC(S)
    CALL WRTTXT(%VAL(PTR), %VAL(LEN(S), 1)  --> good

or
Code:

    CALL WRTTXT(%VAL(CPTR__(S)), %VAL(LEN(S)), 1) --> good
with
Code:

    INTEGER*8 FUNCTION CPTR__(S)
        CHARACTER*(*) S
        CPTR__ = LOC(S)
    END FUNCTION

Luckily, if calling a function which returns a string, both compilers put 2 hidden args in front of the arg list (string address and string length) in the same order, so no tricks there.

Remark to processor stack: on Win 64-bit systems the calling convention is FASTCALL, so the first 4 args are put to 8-byte registers, only the remaining args to conventional stack space. (can be seen in assembly code)

HLo

njdyck January 10, 2014 17:23

HLo,

I started working on my own fortran-based library and I'm not having any problems using #define macros in the code. For example the following code can be compiled into a library:

Code:

      MODULE CHAR

      TYPE CWRAP4
      CHARACTER(LEN=4) str
      END TYPE CWRAP4
     
      TYPE CWRAP16
      CHARACTER(LEN=16) str
      END TYPE CWRAP16
     
      TYPE CWRAP32
      CHARACTER(LEN=32) str
      END TYPE CWRAP32
     
      INTEGER MXDNAM = 64
     
      TYPE CWRAPMAX
      CHARACTER(LEN=MXDNAM) str
      END TYPE CWRAPMAX
     
#define WRAP(f,g) f%str = g
#define WRAPCALL(f) f,%VAL(LEN(f%str))
     
      END MODULE CHAR

C ...

SUBROUTINE MESAGE(COMMAND,MESSAGE)
     
      USE CHAR
     
      CHARACTER COMMAND*16
      CHARACTER MESSAGE*32
     
      TYPE(CWRAP16) :: COMMAND_CFX
      TYPE(CWRAP32) :: MESSAGE_CFX
     
      WRAP(COMMAND_CFX,COMMAND)
      WRAP(MESSAGE_CFX,MESSAGE)

      CALL MESAGE_CFX(WRAPCALL(COMMAND_CFX),
    &                        WRAPCALL(MESSAGE_CFX))
   
      END

C ...

I appended _cfx to the necessary symbols in the mpi-XXX.a lib to avoid name clashes. I can then compile a dll from the code in my last post and it runs no problem.

This does, however, restrict the string length to fixed values. Lately I have not got any variable length string code to compile, so I have abandoned them altogether.

Anyway, I look forward to seeing your solution (sounds a little cleaner). Let me know of any way I can help.

ves January 16, 2014 13:48

Hello!
I am use ANSYS CFX 14.5.7.1 and Intel Composer Compiler SE 2011, Windows 7x64.

I am replace string:

CHARACTER CRESLT*(*)

on code:

TYPE CWRAP10
CHARACTER(LEN=10) str
END TYPE

TYPE(CWRAP10) :: CRESLT
..............................................

CRESLT%str = 'GOOD'


in cfx example #19, file Tstat_Control.F


I have errorr:


+--------------------------------------------------------------------+
| PROBLEM ENCOUNTERED WHEN EXECUTING CFX EXPRESSION LANGUAGE |
| |
| The CFX expression language was evaluating: |
| Static Temperature |
| |
| The problem was: |
| Internal Error - CEL ICODE array mismatch |
| |
| FURTHER INFORMATION |
| |
| The problem was encountered in executing the expression for: |
| ACOn |
| The complete expression is: |
| Thermostat Function(TSensor,TSet,TTol,atstep) |
| The error occurs on sub-expression: |
| TSensor |
| |
| BACKGROUND INFORMATION |
| |
| The error was detected at one location. The same problem may be |
| present at other locations - that has not been investigated. |
| The following values are for the first location which has the |
| problem. |
| |
| |
| END OF DIAGNOSTIC OUTPUT FOR CFX EXPRESSION LANGUAGE |
+--------------------------------------------------------------------+
Unexpected IP data copied: ABSCOEF_FL1


================================================== ====================
| Timestepping Information |
----------------------------------------------------------------------
| Timestep | RMS Courant Number | Max Courant Number |
+----------------------+----------------------+----------------------+
| 3.0000E+00 | 0.00 | 0.00 |
----------------------------------------------------------------------

================================================== ====================
TIME STEP = 1 SIMULATION TIME = 3.0000E+00 CPU SECONDS = 5.202E+00
----------------------------------------------------------------------
COEFFICIENT LOOP ITERATION = 1 CPU SECONDS = 5.202E+00
----------------------------------------------------------------------
| Equation | Rate | RMS Res | Max Res | Linear Solution |
+----------------------+------+---------+---------+------------------+
| U-Mom | 0.00 | 2.2E-02 | 8.9E-01 | 1.7E-04 OK|
| V-Mom | 0.00 | 0.0E+00 | 0.0E+00 | 0.0E+00 OK|
| W-Mom | 0.00 | 1.5E-01 | 7.6E-01 | 5.9E-05 OK|
| P-Mass | 0.00 | 1.5E-04 | 6.5E-03 | 39.4 7.4E-02 OK|
+----------------------+------+---------+---------+------------------+
----------------------------------
Error in subroutine GET_SPECVAR :
A recursion problem was encountered when evaluating the expression for
"Temperature" at the following location: "Inlet". Please carefully check that
the result of your expression does not depend on itself.
GETVAR originally called by subroutine CAL_TEMP_BCS

+--------------------------------------------------------------------+
| ERROR #001100279 has occurred in subroutine ErrAction. |
| Message: |
| Stopped in routine GV_ERROR |
| |
| |
| |
| |
| |
+--------------------------------------------------------------------+

+--------------------------------------------------------------------+
| An error has occurred in cfx5solve: |
| |
| The ANSYS CFX solver exited with return code 1. No results file |
| has been created. |
+--------------------------------------------------------------------+


What s wrong?

I need recompiling platform-mpi?


settings for compiler?

njdyck January 16, 2014 15:33

Ves,

The focus of this thread is to discuss techniques to compile CFX friendly user fortran code with the open source MinGW (gfortran) compiler for Windows. You said you are using the intel compiler, so you don't need to use any of the tricks here. Just compile the code as you normally would with variable length string arguments, and everything should line up.

One piece of advice I can give is make sure you are using the Intel Composer Command Prompt (look for it under the start menu). If you try and use the windows command prompt it can't find 'link' or something like that.

ves January 17, 2014 12:28

yes, I have windows command promt. CFX command promt compiler not found


All times are GMT -4. The time now is 21:50.